diff --git a/.browserslistrc b/.browserslistrc index b3e198a..1b16c45 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1 +1 @@ -Chrome 128 +Chrome 142 diff --git a/.electron-builder.config.js b/.electron-builder.config.js index 2fb677a..f735939 100644 --- a/.electron-builder.config.js +++ b/.electron-builder.config.js @@ -1,3 +1,6 @@ +// .env 파일 로드 +require('dotenv').config(); + if (process.env.VITE_APP_VERSION === undefined) { const now = new Date(); process.env.VITE_APP_VERSION = `${now.getUTCFullYear() - 2000}.${ @@ -13,16 +16,23 @@ const config = { appId: 'co.kr.bugi.electron', productName: 'bugi', directories: { - output: 'dist', + output: 'electron-dist', buildResources: 'buildResources', }, files: [ 'dist/main/**', 'dist/preload/**', 'dist/renderer/**', - 'node_modules/**/*', 'package.json', ], + /* 알림에 추가한 이미지 빌드 시 */ + extraResources: [ + { + from: 'src/main/assets/Symbol Logo.png', + to: 'Symbol Logo.png', + }, + ], + asar: true, // 빌드 전에 필요한 파일들이 존재하는지 확인 beforeBuild: async (context) => { const fs = require('fs'); @@ -60,8 +70,10 @@ const config = { ], icon: 'buildResources/icon.icns', artifactName: '${productName}-${version}-${arch}.${ext}', - hardenedRuntime: false, // 코드 서명 없이 개발 시 false - gatekeeperAssess: false, + // 코드 서명 설정 + identity: process.env.APPLE_IDENTITY || undefined, // 환경변수로 인증서 지정 가능 + hardenedRuntime: true, // 코드 서명 시 true 권장 + gatekeeperAssess: true, // Gatekeeper 검증 활성화 entitlements: 'buildResources/entitlements.mac.plist', entitlementsInherit: 'buildResources/entitlements.mac.plist', extendInfo: { @@ -70,6 +82,17 @@ const config = { NSMicrophoneUsageDescription: '거부기린은 사용자의 자세를 실시간으로 분석하기 위해 마이크에 접근합니다.', }, + // 공증(Notarization) 설정 + // 환경변수가 설정되어 있으면 자동으로 공증 활성화 + // 필요한 환경변수: + // - APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID + // 또는 + // - APPLE_API_KEY, APPLE_API_KEY_ID, APPLE_API_ISSUER + notarize: !!( + process.env.APPLE_ID && + process.env.APPLE_APP_SPECIFIC_PASSWORD && + process.env.APPLE_TEAM_ID + ), }, win: { target: [ @@ -83,8 +106,7 @@ const config = { }, ], icon: 'buildResources/icon.png', - artifactName: '${productName}-${version}-${arch}.${ext}', - publisherName: 'Bugi', + artifactName: '거부기린.${ext}', }, nsis: { oneClick: false, @@ -92,6 +114,67 @@ const config = { createDesktopShortcut: true, createStartMenuShortcut: true, }, + afterPack: async (context) => { + const fs = require('fs'); + + const { electronPlatformName, appOutDir } = context; + + if (electronPlatformName !== 'darwin') { + return; + } + + const { + productFilename, + info: { + _metadata: { electronLanguagesInfoPlistStrings }, + }, + } = context.packager.appInfo; + + const resPath = `${appOutDir}/${productFilename}.app/Contents/Resources/`; + + console.log( + '\n> package.json의 "electronLanguagesInfoPlistStrings" 설정을 기반으로 언어 패키지 생성 시작\n', + '\n> electronLanguagesInfoPlistStrings:\n', + electronLanguagesInfoPlistStrings, + '\n\n', + '> ResourcesPath:', + resPath, + ); + + // APP 언어 패키지 파일 생성 + return await Promise.all( + Object.keys(electronLanguagesInfoPlistStrings).map((langKey) => { + const infoPlistStrPath = `${langKey}.lproj/InfoPlist.strings`; + let infos = ''; + + const langItem = electronLanguagesInfoPlistStrings[langKey]; + + Object.keys(langItem).forEach((infoKey) => { + infos += `"${infoKey}" = "${langItem[infoKey]}";\n`; + }); + + return new Promise((resolve) => { + // 디렉토리가 없으면 생성 + const dirPath = `${resPath}${langKey}.lproj`; + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }); + } + + fs.writeFile(`${resPath}${infoPlistStrPath}`, infos, (err) => { + if (err) { + console.error( + `> "${resPath}${infoPlistStrPath}" 생성 실패:`, + err, + ); + throw err; + } + console.log(`> "${resPath}${infoPlistStrPath}" 생성 완료.`); + resolve(); + }); + }); + }), + ); + }, }; module.exports = config; diff --git a/.electron-vendors.cache.json b/.electron-vendors.cache.json index d0d99a4..35fdd6e 100644 --- a/.electron-vendors.cache.json +++ b/.electron-vendors.cache.json @@ -1,4 +1,4 @@ { - "chrome": "128", - "node": "20" + "chrome": "142", + "node": "22" } diff --git a/.github/workflows/deploy-storybook.yml b/.github/workflows/deploy-storybook.yml deleted file mode 100644 index 9e4b475..0000000 --- a/.github/workflows/deploy-storybook.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Deploy Storybook to GitHub Pages - -# 이 워크플로우는 build-all-pr.yml로 대체되었습니다 -# main 브랜치에서만 실행하도록 제한 -on: - push: - branches: ['main'] - # pull_request는 build-all-pr.yml에서 처리 - -# GitHub Pages 배포를 위한 권한 설정 -permissions: - contents: read - pages: write - id-token: write - -# 동시 배포 방지를 위한 설정 -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - cache-dependency-path: | - package-lock.json - - - name: Install workspace dependencies - run: | - # 전체 workspace 의존성 설치 (husky 스크립트 무시) - npm ci --ignore-scripts - - - name: Verify workspace setup - run: | - echo "✅ Workspace dependencies installed successfully" - echo "📦 Workspace packages:" - ls -la packages/ - - - name: Build Storybook - run: | - cd packages/ui - npm run build-storybook - echo "✅ Storybook built successfully" - - - name: Setup Pages - uses: actions/configure-pages@v4 - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: './packages/ui/storybook-static' - - deploy: - runs-on: ubuntu-latest - needs: build - # 환경 보호 규칙 우회를 위한 조건부 배포 - if: github.ref == 'refs/heads/main' - environment: - name: github-pages - url: https://storybook.bugi.co.kr - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 - - - name: Deploy info - run: | - echo "✅ Storybook deployed successfully!" - echo "🌐 Custom Domain: https://storybook.bugi.co.kr" - echo "📁 Source directory: packages/ui/storybook-static" - echo "📝 Commit: ${{ github.sha }}" - echo "" - echo "🔧 DNS 설정 필요:" - echo " CNAME 레코드: storybook.bugi.co.kr → [username].github.io" diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index 9781de5..1e6fc27 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -7,6 +7,9 @@ on: jobs: build-and-deploy: runs-on: ubuntu-latest + defaults: + run: + shell: bash #모든 step이 bash로 실행, OS에 관계없이 통과 steps: - name: Checkout code @@ -14,57 +17,80 @@ jobs: with: fetch-depth: 0 # 전체 git 히스토리 가져오기 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - cache: 'npm' - cache-dependency-path: | - package-lock.json - - - name: Enable corepack - run: corepack enable + cache: 'pnpm' - - name: Verify package-lock.json exists + - name: Verify pnpm-lock.yaml exists run: | - if [ ! -f package-lock.json ]; then - echo "❌ package-lock.json not found!" + if [ ! -f pnpm-lock.yaml ]; then + echo "❌ pnpm-lock.yaml not found!" echo "📁 Current directory contents:" ls -la exit 1 fi - echo "✅ package-lock.json found" - echo "📋 Lockfile version:" - node -p "require('./package-lock.json').lockfileVersion" - echo "📦 npm version:" - npm --version + echo "✅ pnpm-lock.yaml found" + echo "📦 pnpm version:" + pnpm --version + echo "🔍 Checking lockfile sync status..." + pnpm install --dry-run --frozen-lockfile --ignore-scripts || echo "⚠️ Lockfile may need update, will update during install" - - name: Install workspace dependencies + - name: Install dependencies run: | - # 전체 workspace 의존성 설치 (husky 스크립트 무시) - npm ci --ignore-scripts + # 의존성 설치 (husky 스크립트 무시) + # lockfile이 오래된 경우 업데이트 후 설치 + pnpm install --frozen-lockfile --ignore-scripts || { + echo "⚠️ Lockfile outdated, updating..." + pnpm install --ignore-scripts + } - - name: Verify workspace setup + - name: Verify project setup run: | - echo "✅ Workspace dependencies installed successfully" - echo "📦 Workspace packages:" - ls -la packages/ - echo "🔗 Checking workspace links:" - cd apps/web - echo "Checking if ui package is accessible:" - node -e "try { require('ui'); console.log('✅ ui package accessible'); } catch(e) { console.log('❌ ui package not accessible:', e.message); }" - echo "Checking if api package is accessible:" - node -e "try { require('api'); console.log('✅ api package accessible'); } catch(e) { console.log('❌ api package not accessible:', e.message); }" + echo "✅ Dependencies installed successfully" + echo "📁 Project structure:" + ls -la + echo "📦 Checking if renderer source exists:" + if [ -d "src/renderer" ]; then + echo "✅ src/renderer directory found" + else + echo "❌ src/renderer directory not found" + exit 1 + fi - - name: Build web app + - name: Build web app (renderer) + env: + # GitHub Secrets에서 환경변수 가져오기 + # VITE_ 접두사가 붙은 환경변수만 클라이언트 번들에 포함됨 + VITE_BASE_URL: ${{ secrets.VITE_BASE_URL }} + # 필요한 다른 환경변수들도 여기에 추가 + # VITE_API_KEY: ${{ secrets.VITE_API_KEY }} run: | - cd apps/web - npm run build + pnpm run build:renderer + echo "✅ Build completed" + echo "📁 Checking build output location:" + ls -la dist/ || echo "dist/ not found" + ls -la src/renderer/dist/ || echo "src/renderer/dist/ not found" + find . -name "index.html" -type f | head -5 - name: Create output directory run: | mkdir -p output - cp -r apps/web/dist/* output/ + # 빌드 출력 위치 확인 및 복사 + if [ -d "dist/renderer" ]; then + echo "📁 Found dist/renderer/" + cp -r dist/renderer/* output/ + elif [ -d "src/renderer/dist" ]; then + echo "📁 Found src/renderer/dist/" + cp -r src/renderer/dist/* output/ + else + echo "❌ Build output not found in expected locations" + exit 1 + fi # Vercel 설정 파일 생성 cat > output/vercel.json << 'EOF' @@ -79,41 +105,27 @@ jobs: { "source": "/(.*)", "headers": [ - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Frame-Options", - "value": "DENY" - }, - { - "key": "X-XSS-Protection", - "value": "1; mode=block" - } + { "key": "X-Content-Type-Options", "value": "nosniff" }, + { "key": "X-Frame-Options", "value": "DENY" }, + { "key": "X-XSS-Protection", "value": "1; mode=block" } ] }, { "source": "/assets/(.*)", "headers": [ - { - "key": "Cache-Control", - "value": "public, max-age=31536000, immutable" - } + { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } ] } ], "redirects": [ { - "source": "/", - "destination": "/index.html" + "source": "/index.html", + "destination": "/", + "permanent": true } ], "rewrites": [ - { - "source": "/(.*)", - "destination": "/index.html" - } + { "source": "/(.*)", "destination": "/index.html" } ] } EOF diff --git a/.github/workflows/electron-build-pr.yml b/.github/workflows/electron-build-pr.yml index c1b8b25..fb93927 100644 --- a/.github/workflows/electron-build-pr.yml +++ b/.github/workflows/electron-build-pr.yml @@ -4,9 +4,10 @@ on: pull_request: branches: [main] paths: - - 'apps/electron/**' - - 'packages/**' - - 'apps/web/**' + - 'src/**' + - 'package.json' + - 'package-lock.json' + - '.electron-builder.config.js' - '.github/workflows/electron-build-pr.yml' permissions: @@ -16,6 +17,12 @@ permissions: jobs: build-electron: runs-on: ${{ matrix.os }} + env: + # macOS notarization / codesign secrets (Windows builds 무관) + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_IDENTITY: ${{ secrets.APPLE_IDENTITY }} strategy: fail-fast: false matrix: @@ -31,32 +38,34 @@ jobs: with: fetch-depth: 0 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup Node uses: actions/setup-node@v4 with: node-version: 20 - cache: 'npm' - cache-dependency-path: package-lock.json - - - name: Cache turbo - uses: actions/cache@v4 - with: - path: .turbo - key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }} - restore-keys: | - turbo-${{ github.job }}-${{ github.ref_name }}- + cache: 'pnpm' - name: Install dependencies - run: npm ci --ignore-scripts + run: pnpm install --frozen-lockfile --ignore-scripts - - name: Build web app for Electron renderer + - name: Verify project setup + shell: bash #기본 shell 설정 run: | - cd apps/web - npm run build - echo "✅ Web app built for Electron renderer" + echo "✅ Dependencies installed successfully" + echo "📁 Project structure:" + ls -la + echo "📦 Checking if renderer source exists:" + if [ -d "src/renderer" ]; then + echo "✅ src/renderer directory found" + else + echo "❌ src/renderer directory not found" + exit 1 + fi - name: Package Electron App - run: npm run build:${{ matrix.os_short }} --workspace=electron-wrapper + run: pnpm run build:${{ matrix.os_short }} - name: Upload artifacts uses: actions/upload-artifact@v4 @@ -64,28 +73,89 @@ jobs: name: electron-${{ matrix.os }}-${{ github.event.number }} if-no-files-found: warn path: | - apps/electron/dist/*.dmg - apps/electron/dist/*.zip - apps/electron/dist/*.exe - apps/electron/dist/mac/** + # macOS 빌드 결과물 + electron-dist/*.dmg + electron-dist/*.zip + electron-dist/*.blockmap + electron-dist/mac/** + electron-dist/mac-arm64/** + # Windows 빌드 결과물 + # NSIS 설치 프로그램 (artifactName: 거부기린.${ext}) + electron-dist/거부기린.* + # Portable 빌드 결과물 (폴더 형태) + electron-dist/win-ia32-unpacked/** + electron-dist/win-unpacked/** + comment: + needs: build-electron + runs-on: ubuntu-latest + if: always() + permissions: + contents: read + pull-requests: write + steps: - name: Comment on PR - if: always() uses: actions/github-script@v7 with: script: | - const os = '${{ matrix.os }}'; - const run = `https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}`; - const body = ` - ## 🔧 Electron Build (${os}) - - **Status**: ${{ job.status }} - - **Artifacts**: [View Build Artifacts](${run}) - --- - *This is an automated comment.* - `; - await github.rest.issues.createComment({ + // 현재 workflow run의 모든 job 가져오기 + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.runId, + }); + + // 빌드 job들 찾기 (matrix로 생성된 job들) + const buildJobs = jobs.data.jobs.filter(job => + job.name.startsWith('build-electron') + ); + + // 댓글 본문 생성 + let body = `## 🔧 Electron Build Results\n\n`; + + buildJobs.forEach(job => { + const osName = job.name.includes('macos') ? 'macOS' : + job.name.includes('windows') ? 'Windows' : + job.name; + const statusIcon = job.conclusion === 'success' ? '✅' : + job.conclusion === 'failure' ? '❌' : '⚠️'; + const statusText = job.conclusion === 'success' ? 'Success' : + job.conclusion === 'failure' ? 'Failed' : + job.conclusion === 'cancelled' ? 'Cancelled' : 'In Progress'; + + body += `### ${statusIcon} ${osName}\n`; + body += `- **Status**: ${statusText}\n`; + body += `- **Job**: [${job.name}](${job.html_url})\n\n`; + }); + + body += `---\n*This is an automated comment.*`; + + // 기존 댓글 찾기 + const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body - }); \ No newline at end of file + }); + + const existingComment = comments.data.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('## 🔧 Electron Build Results') + ); + + if (existingComment) { + // 기존 댓글 업데이트 + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id, + body + }); + } else { + // 새 댓글 작성 + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body + }); + } diff --git a/.gitignore b/.gitignore index 2565d88..511b40a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,38 +1,74 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies -node_modules +node_modules/ .pnp .pnp.js -dist/ - -# testing -coverage -# next.js -.next/ +# build outputs +dist/ +build/ out/ -build +electron-dist/ -# misc -.DS_Store -*.pem +# Electron +*.dmg +*.zip +*.exe +*.blockmap +*.AppImage +*.snap +*.deb +*.rpm +*.pkg +*.dmg.blockmap +*.zip.blockmap +*.exe.blockmap +latest-*.yml +latest-*.json +builder-debug.yml +builder-effective-config.yaml + +# testing +coverage/ +.nyc_output/ -# debug +# debug logs npm-debug.log* yarn-debug.log* yarn-error.log* -.pnpm-debug.log* +pnpm-debug.log* +lerna-debug.log* # local env files +.env .env.local .env.development.local .env.test.local .env.production.local -**/.env -**/.env.* +.env*.local + +# pnpm +.pnpm-store/ + +# OS +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +*.swp +*.swo +*~ + +# misc +*.pem +*.log -# turbo -.turbo -*storybook.log -storybook-static +.vscode/ \ No newline at end of file diff --git a/PARALLEL_BUILD_GUIDE.md b/PARALLEL_BUILD_GUIDE.md deleted file mode 100644 index 0741657..0000000 --- a/PARALLEL_BUILD_GUIDE.md +++ /dev/null @@ -1,195 +0,0 @@ -# ⚡ 병렬 빌드 가이드 - -Storybook과 Electron을 병렬로 실행하는 통합 빌드 시스템입니다. - -## 🚀 새로운 병렬 빌드 시스템 - -### ✅ 생성된 파일: - -- `.github/workflows/build-all-pr.yml` - 통합 병렬 빌드 워크플로우 - -### ✅ 비활성화된 워크플로우: - -- `electron-build-pr.yml` - 병합됨 -- `deploy-storybook.yml` - main 브랜치에서만 실행 - -## 📋 병렬 실행 구조 - -### 🔄 워크플로우 단계: - -``` -1. setup (공통 의존성 설치) - ↓ -2. build-storybook + build-electron (병렬 실행) - ↓ -3. comment-results (결과 통합 및 PR 댓글) -``` - -### ⚡ 병렬 실행 장점: - -1. **시간 단축**: Storybook과 Electron이 동시에 빌드 -2. **리소스 효율성**: 공통 의존성을 한 번만 설치 -3. **캐시 공유**: 아티팩트를 통한 의존성 공유 -4. **통합 결과**: 하나의 PR 댓글로 모든 빌드 결과 확인 - -## 🎯 실행 조건 - -### 트리거 조건: - -```yaml -on: - pull_request_target: - branches: ['main'] - paths: - - 'src/**' # Electron 앱 관련 - - '.github/workflows/build-all-pr.yml' # 워크플로우 자체 -``` - -## 📦 생성되는 아티팩트 - -| 아티팩트 이름 | 내용 | 보관 기간 | -| ----------------------------- | ------------------- | --------- | -| `workspace-cache-[PR번호]` | 공통 의존성 캐시 | 1일 | -| `storybook-[PR번호]` | Storybook 정적 파일 | 30일 | -| `electron-macos-[PR번호]` | macOS .dmg 파일 | 30일 | -| `electron-windows-[PR번호]` | Windows .exe 파일 | 30일 | -| `electron-macos-app-[PR번호]` | macOS 앱 디렉토리 | 30일 | - -## 🔧 빌드 과정 - -### 1. Setup 단계 (공통) - -- 코드 체크아웃 -- Node.js 설정 -- workspace 의존성 설치 -- 캐시 아티팩트 생성 - -### 2. 병렬 빌드 단계 - -#### Storybook 빌드: - -- 캐시 다운로드 -- Storybook 빌드 실행 -- 정적 파일 아티팩트 업로드 - -#### Electron 빌드: - -- 캐시 다운로드 -- 웹 앱 빌드 (renderer) -- Electron 앱 빌드 (main + preload) -- macOS/Windows 컴파일 -- 플랫폼별 아티팩트 업로드 - -### 3. 결과 통합 단계 - -- 모든 빌드 결과 수집 -- 통합 PR 댓글 작성 -- 빌드 요약 출력 - -## 📝 PR 댓글 내용 - -통합 댓글에는 다음이 포함됩니다: - -### 📚 Storybook 정보: - -- 빌드 상태 및 파일 크기 -- 다운로드 링크 -- 테스트 체크리스트 - -### 🔧 Electron 정보: - -- macOS/Windows 빌드 상태 -- 플랫폼별 파일 크기 -- 다운로드 링크 -- 테스트 체크리스트 - -### ⚡ 성능 정보: - -- 병렬 실행 정보 -- 캐시 활용 정보 -- 아티팩트 보관 정보 - -## 🚀 사용 방법 - -### 1. Pull Request 생성 - -```bash -git checkout -b feature/parallel-build -# 코드 변경 -git add . -git commit -m "Test parallel build" -git push origin feature/parallel-build -# GitHub에서 PR 생성 -``` - -### 2. 병렬 빌드 실행 - -- PR 생성 시 자동으로 병렬 빌드 시작 -- Actions 탭에서 진행 상황 확인 -- Storybook과 Electron이 동시에 빌드됨 - -### 3. 결과 확인 - -- 빌드 완료 후 PR에 통합 댓글 자동 작성 -- 다운로드 링크로 모든 빌드 결과 확인 - -## ⚡ 성능 비교 - -### 기존 (순차 실행): - -``` -Setup (2분) → Storybook (3분) → Electron (5분) = 총 10분 -``` - -### 새로운 (병렬 실행): - -``` -Setup (2분) → [Storybook (3분) + Electron (5분)] = 총 7분 -``` - -**시간 단축: 약 30% 향상** - -## 🛠️ 문제 해결 - -### 일반적인 문제들: - -#### 1. 캐시 다운로드 실패 - -``` -Error: Download artifact failed -``` - -**해결방법**: setup 단계에서 의존성 설치 확인 - -#### 2. 병렬 빌드 충돌 - -``` -Error: Build conflict -``` - -**해결방법**: 각 빌드가 독립적인 디렉토리에서 실행됨 - -#### 3. 아티팩트 업로드 실패 - -``` -Error: Upload artifact failed -``` - -**해결방법**: 빌드된 파일 경로 확인 - -## 🎉 완료! - -이제 다음이 해결됩니다: - -- ✅ Storybook과 Electron 병렬 빌드 -- ✅ 빌드 시간 30% 단축 -- ✅ 통합 PR 댓글로 모든 결과 확인 -- ✅ 리소스 효율성 향상 -- ✅ 캐시 공유로 의존성 설치 최적화 - -## 📚 참고사항 - -- **병렬 실행**: Storybook과 Electron이 동시에 빌드되어 시간 단축 -- **캐시 활용**: 공통 의존성을 한 번만 설치하고 공유 -- **통합 결과**: 하나의 PR 댓글로 모든 빌드 결과 확인 가능 -- **리소스 최적화**: 중복 작업 제거로 효율성 향상 diff --git a/STABILIZATION_LOGIC.md b/STABILIZATION_LOGIC.md new file mode 100644 index 0000000..ad0418f --- /dev/null +++ b/STABILIZATION_LOGIC.md @@ -0,0 +1,348 @@ +# 안정화 로직 케이스별 정리 + +## 개요 + +안정화 로직은 **시간 기반 주기 제어**와 **점수 기반 안정화 검사** 두 단계로 구성됩니다. + +--- + +## 방지할 수 있는 상황 ✅ + +### 1. 노이즈로 인한 급격한 레벨 전환 + +**상황**: 카메라 노이즈, 측정 오차로 인해 점수가 급격히 변동 +**예시**: + +- L3(기린) 상태에서 일시적으로 점수가 1.3으로 올라가 L4(거북이)로 전환 +- 실제 자세는 변하지 않았는데 측정 오차로 인한 변화 + +**방지 메커니즘**: + +- **시간 기반**: 최소 50-200ms 주기로 검사하여 일시적 변화 무시 +- **점수 기반**: 이전 점수들의 평균과 비교하여 급격한 변화 필터링 +- **결과**: 안정적인 자세에서는 레벨이 자주 바뀌지 않음 + +--- + +### 2. 일시적인 자세 변화 (순간적인 움직임) + +**상황**: 사용자가 잠깐 고개를 돌리거나 몸을 움직임 +**예시**: + +- 책상에서 일하다가 잠깐 옆을 보는 경우 +- 재채기, 기침 등 일시적인 움직임 + +**방지 메커니즘**: + +- **평균 기반 검사**: 최근 300ms 내 점수들의 평균과 비교 +- **Threshold**: 0.6 또는 1.2 이내의 변화만 허용 +- **결과**: 일시적 변화는 무시되고 안정적인 자세만 반영 + +--- + +### 3. 프레임 드롭/스파이크 + +**상황**: 카메라 프레임이 드롭되거나 특정 프레임에서 이상값 발생 +**예시**: + +- 프레임 레이트가 불안정한 경우 +- 특정 프레임에서 포즈 인식 실패 + +**방지 메커니즘**: + +- **버퍼 기반**: 최근 300ms 내 여러 프레임의 평균 사용 +- **최소 버퍼**: 3개 이상의 데이터가 있어야 신뢰성 있는 판단 +- **결과**: 개별 프레임의 이상값이 전체 판단에 큰 영향 없음 + +--- + +### 4. 카메라 움직임/조명 변화 + +**상황**: 카메라가 흔들리거나 조명이 변하는 경우 +**예시**: + +- 노트북을 옮기는 경우 +- 조명이 켜지거나 꺼지는 경우 + +**방지 메커니즘**: + +- **시간 지연**: 최소 주기(50-200ms) 동안 변화가 지속되어야 반영 +- **평균 비교**: 단일 프레임의 급격한 변화는 무시 +- **결과**: 일시적인 환경 변화는 필터링됨 + +--- + +### 5. 레벨 경계 근처에서의 진동 + +**상황**: 점수가 경계값 근처에서 왔다갔다 하는 경우 +**예시**: + +- 점수 1.1 ↔ 1.3 사이에서 L3 ↔ L4 전환 반복 +- 실제로는 경계 근처에서 미세하게 변동 + +**방지 메커니즘**: + +- **Threshold 검사**: 평균과의 차이가 threshold 이내여야 업데이트 +- **시간 주기**: 최소 주기 동안 지속되어야 반영 +- **결과**: 경계 근처에서 불필요한 전환 방지 + +--- + +## 불리한 상황 ❌ + +### 1. 실제로 빠르게 자세를 바꾸는 경우 + +**상황**: 사용자가 의도적으로 자세를 빠르게 교정 +**예시**: + +- 거북목 자세에서 갑자기 고개를 들고 올바른 자세로 교정 +- 점수가 1.5 → 0.5로 빠르게 변화 + +**문제점**: + +- **시간 지연**: 최소 50-200ms 주기로 인해 즉시 반영되지 않음 +- **평균 기반**: 이전 점수들의 평균과 비교하여 급격한 변화가 억제될 수 있음 +- **결과**: 실제 자세 개선이 화면에 반영되는데 지연 발생 + +**영향도**: ⚠️ 중간 (경계 전환은 50ms로 빠르게 처리) + +--- + +### 2. 점진적이지만 지속적인 자세 악화 + +**상황**: 자세가 서서히 나빠지지만 각 프레임의 변화는 작음 +**예시**: + +- 점수가 0.3 → 0.5 → 0.7 → 0.9 → 1.1로 서서히 증가 +- 각 변화는 threshold(0.6) 이내이지만 누적되면 레벨 전환 + +**문제점**: + +- **Threshold 검사**: 각 프레임의 변화가 작아서 통과 +- **평균 기반**: 최근 평균과 비교하므로 점진적 변화는 쉽게 통과 +- **결과**: 실제로는 자세가 악화되었는데 레벨 전환이 지연될 수 있음 + +**영향도**: ⚠️ 낮음 (점진적 변화는 자연스럽게 반영됨) + +--- + +### 3. 경계 근처에서 오래 머무는 경우 + +**상황**: 점수가 경계값 근처에서 오래 유지되는 경우 +**예시**: + +- 점수 1.15 (L3)에서 1.25 (L4) 사이를 계속 왔다갔다 +- 실제로는 L4에 가까운 자세인데 L3으로 표시 + +**문제점**: + +- **Threshold**: 평균과의 차이가 작아서 업데이트는 되지만 +- **시간 주기**: 주기마다 검사하므로 실제 레벨과 다를 수 있음 +- **결과**: 경계 근처에서는 레벨 판정이 불안정할 수 있음 + +**영향도**: ⚠️ 낮음 (경계 전환은 50ms로 빠르게 처리) + +--- + +### 4. 초기 상태 (버퍼 부족) + +**상황**: 앱 시작 직후 또는 reset() 후 버퍼에 데이터가 부족 +**예시**: + +- 앱 시작 후 처음 300ms 동안 +- 캘리브레이션 후 처음 측정 + +**문제점**: + +- **최소 버퍼**: 버퍼 < 3개일 때는 무조건 통과 +- **평균 부정확**: 데이터가 적어서 평균이 부정확할 수 있음 +- **결과**: 초기에는 안정화 효과가 약함 + +**영향도**: ⚠️ 매우 낮음 (초기 상태는 짧은 시간만 지속) + +--- + +### 5. 매우 빠른 자세 변화 반복 + +**상황**: 사용자가 의도적으로 자세를 빠르게 바꾸는 경우 +**예시**: + +- 고개를 위아래로 빠르게 움직임 +- 테스트 목적으로 자세를 의도적으로 변경 + +**문제점**: + +- **시간 주기**: 최소 주기로 인해 모든 변화를 반영하지 못함 +- **평균 기반**: 빠른 변화가 평균에 섞여서 정확도 저하 +- **결과**: 실제 자세 변화를 제대로 추적하지 못할 수 있음 + +**영향도**: ⚠️ 매우 낮음 (일반적인 사용 시나리오가 아님) + +--- + +## 트레이드오프 요약 + +| 측면 | 장점 | 단점 | +| ------------- | ------------------------ | -------------------------------- | +| **반응 속도** | 노이즈 필터링으로 안정적 | 실제 변화 반영에 지연 (50-200ms) | +| **정확도** | 일시적 변화 무시로 정확 | 점진적 변화는 잘 감지 | +| **안정성** | 급격한 전환 방지 | 경계 근처에서 약간 불안정 | +| **성능** | 불필요한 검사 방지 | 초기 상태에서 효과 약함 | + +--- + +## 권장 사용 시나리오 + +✅ **이 로직이 적합한 경우**: + +- 일반적인 업무 환경 (안정적인 자세 유지) +- 장시간 모니터링 (노이즈 필터링 중요) +- 사용자 피드백을 안정적으로 제공해야 하는 경우 + +❌ **이 로직이 부적합한 경우**: + +- 실시간 게임이나 빠른 반응이 필요한 경우 +- 매우 빠른 자세 변화를 정확히 추적해야 하는 경우 +- 초기 몇 초 동안의 정확도가 중요한 경우 + +--- + +## 1단계: 업데이트 주기 결정 + +매 프레임마다 현재 상황에 따라 업데이트 주기를 결정합니다. + +### 케이스 1-1: 거북이/기린 경계 전환 (레벨 3 ↔ 4) + +- **조건**: `lastStableState.cls === 3 && currentClassification.cls === 4` 또는 그 반대 +- **주기**: **50ms** +- **설명**: 가장 중요한 경계(기린↔거북이) 전환 시 가장 빠르게 반응 + +### 케이스 1-2: 일반 레벨 변경 (경계 전환이 아닌 레벨 변경) + +- **조건**: `levelChanged === true` && `isBoundaryCrossing === false` +- **예시**: L1→L2, L2→L3, L4→L5, L5→L6 등 +- **주기**: **150ms** +- **설명**: 경계 전환이 아닌 다른 레벨 간 전환 + +### 케이스 1-3: 레벨 유지 (같은 레벨 내 점수 변화) + +- **조건**: `levelChanged === false` +- **예시**: L3 내에서 점수만 변하는 경우 +- **주기**: **200ms** +- **설명**: 같은 레벨 내에서는 가장 느리게 업데이트 + +### 주기 미경과 시 동작 + +- **조건**: `timeSinceLastUpdate < requiredInterval` +- **동작**: 안정화 검사 없이 `lastStableState` 즉시 반환 +- **효과**: 불필요한 검사 방지 및 성능 최적화 + +--- + +## 2단계: 안정화 검사 + +주기가 경과했을 때만 안정화 검사를 수행합니다. + +### 안정화 검사 파라미터 + +- **windowMs**: 300ms (버퍼에 유지할 시간) +- **threshold**: 0.6 (기본 임계값) +- **minBufferSize**: 3 (최소 버퍼 크기) + +### 케이스 2-1: 거북이/기린 경계 전환 시 + +- **threshold**: **1.2** (기본값 0.6의 2배) +- **로직**: + 1. 버퍼 크기 < 3이면 → **통과** (즉시 업데이트) + 2. 이전 점수들의 평균 계산 + 3. `|현재점수 - 평균| <= 1.2`이면 → **통과** + 4. 그 외 → **실패** (이전 상태 유지) + +### 케이스 2-2: 일반 상황 (경계 전환이 아닌 경우) + +- **threshold**: **0.6** (기본값) +- **로직**: + 1. 버퍼 크기 < 3이면 → **통과** (즉시 업데이트) + 2. 이전 점수들의 평균 계산 + 3. `|현재점수 - 평균| <= 0.6`이면 → **통과** + 4. 그 외 → **실패** (이전 상태 유지) + +### 안정화 검사 상세 로직 + +``` +1. 버퍼에 현재 점수 추가 (매 프레임) +2. 300ms 이전 데이터 제거 +3. 버퍼 크기 확인 + - < 3개 → 통과 (데이터 부족) +4. 이전 점수들(현재 점수 제외)의 평균 계산 +5. |현재점수 - 평균| 계산 +6. threshold와 비교 + - <= threshold → 통과 + - > threshold → 실패 +``` + +--- + +## 3단계: 최종 결과 반환 + +### 케이스 3-1: 안정화 검사 통과 + +- **동작**: `lastStableState = currentClassification` 업데이트 +- **반환**: 새로운 안정화된 상태 + +### 케이스 3-2: 안정화 검사 실패 + +- **동작**: `lastStableState` 유지 (변경 없음) +- **반환**: 이전 안정화된 상태 + +### 케이스 3-3: 초기 상태 (lastStableState === null) + +- **반환**: 기본 "측정중" 상태 + +--- + +## 전체 플로우 예시 + +### 예시 1: 거북이 → 기린 전환 (L4 → L3) + +``` +1. 현재 점수: 1.0 (L3), 이전: 1.5 (L4) +2. 레벨 변경 감지 → isBoundaryCrossing = true +3. 주기 확인: 50ms 경과 여부 확인 +4. 주기 경과 시: + - threshold = 1.2 (완화) + - 안정화 검사 수행 + - 통과 시 → L3로 업데이트 +``` + +### 예시 2: 같은 레벨 내 점수 변화 (L3 내에서) + +``` +1. 현재 점수: 0.5 (L3), 이전: 0.3 (L3) +2. 레벨 변경 없음 → levelChanged = false +3. 주기 확인: 200ms 경과 여부 확인 +4. 주기 경과 시: + - threshold = 0.6 (기본) + - 안정화 검사 수행 + - 통과 시 → 점수만 업데이트 +``` + +### 예시 3: 안정화 검사 실패 + +``` +1. 현재 점수: 2.0, 이전 평균: 0.5 +2. 차이: |2.0 - 0.5| = 1.5 +3. threshold = 0.6 +4. 1.5 > 0.6 → 실패 +5. 이전 상태 유지 +``` + +--- + +## 핵심 특징 + +1. **적응형 주기**: 상황에 따라 다른 업데이트 주기 적용 +2. **경계 전환 특별 처리**: 거북이/기린 경계는 가장 빠르고 완화된 검사 +3. **이중 안정화**: 시간 기반 + 점수 기반 안정화 +4. **버퍼 기반 평균**: 최근 300ms 내 점수들의 평균과 비교 +5. **현재 점수 제외**: 평균 계산 시 현재 점수는 제외하여 편향 방지 diff --git a/build.sh b/build.sh index cf1ef4d..bdc6912 100755 --- a/build.sh +++ b/build.sh @@ -1,36 +1,28 @@ -#!/bin/bash +#!/bin/sh +set -e # 에러 발생 시 즉시 종료 -# Web 앱 빌드 스크립트 -echo "🚀 Starting web app build process..." +# 스크립트가 있는 디렉토리의 상위 디렉토리로 이동 +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd "$SCRIPT_DIR/.." -# output 디렉토리 생성 +# output 디렉토리 생성 (이미 존재해도 에러 없음) mkdir -p output -# 웹 앱 빌드 -echo "📦 Building web app..." -cd apps/web -npm ci -npm run build +# 현재 디렉토리의 모든 내용을 output으로 복사 +# 숨김 파일 포함, .git과 node_modules는 제외 +for item in .* *; do + # 스킵할 항목들 + case "$item" in + '.' | '..' | '.git' | 'node_modules' | 'output') + continue + ;; + esac + + # 파일/디렉토리가 존재하는지 확인 후 복사 + [ -e "$item" ] && cp -R "$item" output/ +done -# 빌드 결과를 output으로 복사 -echo "📋 Copying build artifacts..." -cp -r dist/* ../../output/ - -# Electron 앱 빌드는 제외 (web 앱만 빌드) - -# 빌드 정보 생성 -echo "📝 Creating build info..." -cd ../.. -cat > output/build-info.json << EOF -{ - "buildTime": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", - "commit": "$(git rev-parse HEAD)", - "branch": "$(git rev-parse --abbrev-ref HEAD)", - "version": "$(node -p "require('./package.json').version")", - "app": "web" -} -EOF - -echo "✅ Web app build completed successfully!" -echo "📁 Output directory contents:" -ls -la output/ +# zighang-zighang-frontend 디렉토리로 복사 (존재하는 경우에만) +if [ -d "gubugionandon-FE" ]; then + cp -R output/* gubugionandon-FE/ 2>/dev/null || true +fi \ No newline at end of file diff --git a/buildResources/entitlements.mac.plist b/buildResources/entitlements.mac.plist index 2958f0d..0817ef6 100644 --- a/buildResources/entitlements.mac.plist +++ b/buildResources/entitlements.mac.plist @@ -13,5 +13,4 @@ com.apple.security.device.camera - - + \ No newline at end of file diff --git a/buildResources/icon.icns b/buildResources/icon.icns index d20a6d1..762d11e 100644 Binary files a/buildResources/icon.icns and b/buildResources/icon.icns differ diff --git a/buildResources/icon.png b/buildResources/icon.png index 839ed57..ece29e2 100644 Binary files a/buildResources/icon.png and b/buildResources/icon.png differ diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..52bca52 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,79 @@ +import js from '@eslint/js'; +import tseslint from '@typescript-eslint/eslint-plugin'; +import tsparser from '@typescript-eslint/parser'; +import prettier from 'eslint-config-prettier'; +import react from 'eslint-plugin-react'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import globals from 'globals'; + +export default [ + { + ignores: [ + '**/dist/**', + '**/node_modules/**', + '**/build/**', + '**/*.config.js', + '**/*.config.mjs', + '**/*.config.ts', + '.electron-builder.config.js', + 'scripts/**', + '**/*.d.ts', + ], + }, + js.configs.recommended, + { + files: ['**/*.{js,jsx,ts,tsx}'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: { + ...globals.browser, + ...globals.es2021, + ...globals.node, + React: 'readonly', //React를 전역으로 인식시키기기 + }, + parser: tsparser, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + project: false, + }, + }, + plugins: { + '@typescript-eslint': tseslint, + react, + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + settings: { + react: { + version: 'detect', + }, + }, + rules: { + ...tseslint.configs.recommended.rules, + ...react.configs.recommended.rules, + ...reactHooks.configs.recommended.rules, + ...prettier.rules, + 'react/react-in-jsx-scope': 'off', + 'react-hooks/refs': 'off', + 'react-hooks/incompatible-library': 'off', + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + '@typescript-eslint/no-unused-vars': [ + 'warn', + { argsIgnorePattern: '^_' }, + ], + }, + }, + { + files: ['**/*.d.ts'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + }, + }, +]; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index c5c57c0..0000000 --- a/package-lock.json +++ /dev/null @@ -1,11197 +0,0 @@ -{ - "name": "electron-app", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "electron-app", - "version": "1.0.0", - "hasInstallScript": true, - "dependencies": { - "@hookform/resolvers": "^5.2.2", - "@mediapipe/tasks-vision": "^0.10.22-rc.20250304", - "@tailwindcss/vite": "^4.1.14", - "@tanstack/react-query": "^5.0.0", - "axios": "^1.6.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.0.0", - "dts-for-context-bridge": "^0.7.1", - "electron-updater": "^6.0.0", - "framer-motion": "^12.23.24", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-hook-form": "^7.65.0", - "react-router-dom": "^7.9.4", - "react-webcam": "^7.2.0", - "tailwind-merge": "^2.0.0", - "tailwindcss": "^4.1.14", - "zod": "^4.1.12", - "zustand": "^5.0.8" - }, - "devDependencies": { - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "^8.46.1", - "@typescript-eslint/parser": "^8.46.1", - "@vitejs/plugin-react": "^4.0.0", - "autoprefixer": "^10.4.0", - "cross-env": "^7.0.3", - "electron": "^32.0.0", - "electron-builder": "^25.1.8", - "electron-devtools-installer": "^3.2.0", - "eslint": "^8.57.1", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-prettier": "^5.5.4", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^7.0.0", - "eslint-plugin-react-refresh": "^0.4.24", - "husky": "^9.1.7", - "lint-staged": "^16.2.4", - "postcss": "^8.4.0", - "prettier": "^3.6.2", - "prettier-plugin-tailwindcss": "^0.7.1", - "typescript": "^5.0.0", - "vite": "^5.0.0", - "vite-plugin-svgr": "^4.5.0" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@esbuild/darwin-arm64": "latest", - "@esbuild/darwin-x64": "latest", - "@esbuild/linux-x64": "latest", - "@esbuild/win32-x64": "latest", - "@rollup/rollup-darwin-arm64": "latest", - "@rollup/rollup-darwin-x64": "latest", - "@rollup/rollup-linux-x64-gnu": "latest", - "@rollup/rollup-win32-x64-msvc": "latest", - "@tailwindcss/oxide-darwin-arm64": "latest", - "@tailwindcss/oxide-darwin-x64": "latest", - "@tailwindcss/oxide-linux-x64-gnu": "latest", - "@tailwindcss/oxide-win32-x64-msvc": "latest", - "lightningcss-darwin-arm64": "latest", - "lightningcss-darwin-x64": "latest", - "lightningcss-linux-x64-gnu": "latest", - "lightningcss-win32-x64-msvc": "latest" - } - }, - "apps/electron": { - "name": "electron-wrapper", - "version": "1.0.0", - "extraneous": true, - "dependencies": { - "api": "*", - "dts-for-context-bridge": "^0.7.1", - "electron-updater": "^6.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, - "devDependencies": { - "cross-env": "^7.0.3", - "electron": "32.0.0", - "electron-builder": "^25.1.8", - "electron-devtools-installer": "^3.2.0", - "typescript": "^5.0.0", - "vite": "^5.0.0" - }, - "engines": { - "node": ">=v18.0.0", - "pnpm": ">=8.0.0" - } - }, - "apps/web": { - "version": "0.0.0", - "extraneous": true, - "dependencies": { - "@mediapipe/tasks-vision": "^0.10.22-rc.20250304", - "@tailwindcss/vite": "^4.1.14", - "@tanstack/react-query": "^5.0.0", - "api": "*", - "axios": "^1.6.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router-dom": "^7.9.4", - "react-webcam": "^7.2.0", - "zustand": "^5.0.8" - }, - "devDependencies": { - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "@types/react-router-dom": "^5.3.3", - "@vitejs/plugin-react": "^4.0.0", - "autoprefixer": "^10.4.0", - "config": "*", - "postcss": "^8.4.0", - "tailwindcss": "^4.1.14", - "tsconfig": "*", - "typescript": "^5.0.0", - "vite": "^5.0.0", - "vite-plugin-svgr": "^4.5.0" - }, - "optionalDependencies": { - "@esbuild/darwin-arm64": "latest", - "@esbuild/darwin-x64": "latest", - "@esbuild/linux-x64": "latest", - "@esbuild/win32-x64": "latest", - "@rollup/rollup-darwin-arm64": "latest", - "@rollup/rollup-darwin-x64": "latest", - "@rollup/rollup-linux-x64-gnu": "latest", - "@rollup/rollup-win32-x64-msvc": "latest", - "@tailwindcss/oxide-darwin-arm64": "latest", - "@tailwindcss/oxide-darwin-x64": "latest", - "@tailwindcss/oxide-linux-x64-gnu": "latest", - "@tailwindcss/oxide-win32-x64-msvc": "latest", - "lightningcss-darwin-arm64": "latest", - "lightningcss-darwin-x64": "latest", - "lightningcss-linux-x64-gnu": "latest", - "lightningcss-win32-x64-msvc": "latest" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", - "@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.27.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.4" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@develar/schema-utils": { - "version": "2.6.5", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.0", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/@electron/asar": { - "version": "3.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^5.0.0", - "glob": "^7.1.6", - "minimatch": "^3.0.4" - }, - "bin": { - "asar": "bin/asar.js" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/@electron/asar/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@electron/asar/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@electron/asar/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@electron/get": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@electron/get/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@electron/get/node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/get/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@electron/get/node_modules/universalify": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@electron/notarize": { - "version": "2.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.1", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/notarize/node_modules/fs-extra": { - "version": "9.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/osx-sign": { - "version": "1.3.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "compare-version": "^0.1.2", - "debug": "^4.3.4", - "fs-extra": "^10.0.0", - "isbinaryfile": "^4.0.8", - "minimist": "^1.2.6", - "plist": "^3.0.5" - }, - "bin": { - "electron-osx-flat": "bin/electron-osx-flat.js", - "electron-osx-sign": "bin/electron-osx-sign.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { - "version": "4.0.10", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/@electron/rebuild": { - "version": "3.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.1.1", - "detect-libc": "^2.0.1", - "fs-extra": "^10.0.0", - "got": "^11.7.0", - "node-abi": "^3.45.0", - "node-api-version": "^0.2.0", - "node-gyp": "^9.0.0", - "ora": "^5.1.0", - "read-binary-file-arch": "^1.0.6", - "semver": "^7.3.5", - "tar": "^6.0.5", - "yargs": "^17.0.1" - }, - "bin": { - "electron-rebuild": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/@electron/rebuild/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@electron/rebuild/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@electron/rebuild/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@electron/rebuild/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@electron/rebuild/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/rebuild/node_modules/minipass": { - "version": "5.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/rebuild/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/rebuild/node_modules/tar": { - "version": "6.2.1", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/rebuild/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/@electron/universal": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@electron/asar": "^3.2.7", - "@malept/cross-spawn-promise": "^2.0.0", - "debug": "^4.3.1", - "dir-compare": "^4.2.0", - "fs-extra": "^11.1.1", - "minimatch": "^9.0.3", - "plist": "^3.1.0" - }, - "engines": { - "node": ">=16.4" - } - }, - "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", - "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", - "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "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==", - "license": "MIT", - "dependencies": { - "@standard-schema/utils": "^0.3.0" - }, - "peerDependencies": { - "react-hook-form": "^7.55.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@malept/cross-spawn-promise": { - "version": "2.0.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" - } - ], - "license": "Apache-2.0", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/@malept/flatpak-bundler": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.0", - "lodash": "^4.17.15", - "tmp-promise": "^3.0.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { - "version": "9.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mediapipe/tasks-vision": { - "version": "0.10.22-rc.20250304", - "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.22-rc.20250304.tgz", - "integrity": "sha512-dElxVXMFGthshfIj+qAVm8KE2jmNo2p8oXFib8WzEjb7GNaX/ClWBc8UJfoSZwjEMVrdHJ4YUfa7P3ifl6MIWw==", - "license": "Apache-2.0" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/fs": { - "version": "2.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", - "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", - "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", - "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", - "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@standard-schema/utils": { - "version": "0.3.0", - "license": "MIT" - }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/babel-preset": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", - "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", - "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", - "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", - "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", - "@svgr/babel-plugin-transform-svg-component": "8.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@svgr/core": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^8.1.3", - "snake-case": "^3.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.21.3", - "entities": "^4.4.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/plugin-jsx": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.21.3", - "@svgr/babel-preset": "8.1.0", - "@svgr/hast-util-to-babel-ast": "8.0.0", - "svg-parser": "^2.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - }, - "peerDependencies": { - "@svgr/core": "*" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tailwindcss/node": { - "version": "4.1.14", - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.4", - "enhanced-resolve": "^5.18.3", - "jiti": "^2.6.0", - "lightningcss": "1.30.1", - "magic-string": "^0.30.19", - "source-map-js": "^1.2.1", - "tailwindcss": "4.1.14" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.1.14", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.4", - "tar": "^7.5.1" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.14", - "@tailwindcss/oxide-darwin-arm64": "4.1.14", - "@tailwindcss/oxide-darwin-x64": "4.1.14", - "@tailwindcss/oxide-freebsd-x64": "4.1.14", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", - "@tailwindcss/oxide-linux-x64-musl": "4.1.14", - "@tailwindcss/oxide-wasm32-wasi": "4.1.14", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz", - "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz", - "integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz", - "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz", - "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz", - "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz", - "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz", - "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz", - "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz", - "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz", - "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.0.5", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", - "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz", - "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide/node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz", - "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide/node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz", - "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.1.14", - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.1.14", - "@tailwindcss/oxide": "4.1.14", - "tailwindcss": "4.1.14" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7" - } - }, - "node_modules/@tanstack/query-core": { - "version": "5.90.5", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "5.90.5", - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.90.5" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ts-morph/common": { - "version": "0.12.3", - "license": "MIT", - "dependencies": { - "fast-glob": "^3.2.7", - "minimatch": "^3.0.4", - "mkdirp": "^1.0.4", - "path-browserify": "^1.0.1" - } - }, - "node_modules/@ts-morph/common/node_modules/brace-expansion": { - "version": "1.1.12", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "3.1.2", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "license": "MIT" - }, - "node_modules/@types/fs-extra": { - "version": "9.0.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/history": { - "version": "4.7.11", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.8.1", - "devOptional": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.14.0" - } - }, - "node_modules/@types/node/node_modules/undici-types": { - "version": "7.14.0", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/plist": { - "version": "3.0.5", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/q": { - "version": "1.5.8", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.26", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@types/react-router": { - "version": "5.1.20", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.3.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/verror": { - "version": "1.10.11", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/type-utils": "8.46.1", - "@typescript-eslint/utils": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.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.46.1", - "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", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", - "debug": "^4.3.4" - }, - "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.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.1", - "@typescript-eslint/types": "^8.46.1", - "debug": "^4.3.4" - }, - "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.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1" - }, - "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.46.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1", - "@typescript-eslint/utils": "8.46.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.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.46.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.46.1", - "@typescript-eslint/tsconfig-utils": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.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/utils": { - "version": "8.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1" - }, - "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.46.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.46.1", - "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/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "dev": true, - "license": "ISC" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/7zip-bin": { - "version": "5.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "node_modules/acorn": { - "version": "8.15.0", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-escapes": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/app-builder-bin": { - "version": "5.0.0-alpha.10", - "dev": true, - "license": "MIT" - }, - "node_modules/app-builder-lib": { - "version": "25.1.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@develar/schema-utils": "~2.6.5", - "@electron/notarize": "2.5.0", - "@electron/osx-sign": "1.3.1", - "@electron/rebuild": "3.6.1", - "@electron/universal": "2.0.1", - "@malept/flatpak-bundler": "^0.4.0", - "@types/fs-extra": "9.0.13", - "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.9", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chromium-pickle-js": "^0.2.0", - "config-file-ts": "0.2.8-rc1", - "debug": "^4.3.4", - "dotenv": "^16.4.5", - "dotenv-expand": "^11.0.6", - "ejs": "^3.1.8", - "electron-publish": "25.1.7", - "form-data": "^4.0.0", - "fs-extra": "^10.1.0", - "hosted-git-info": "^4.1.0", - "is-ci": "^3.0.0", - "isbinaryfile": "^5.0.0", - "js-yaml": "^4.1.0", - "json5": "^2.2.3", - "lazy-val": "^1.0.5", - "minimatch": "^10.0.0", - "resedit": "^1.7.0", - "sanitize-filename": "^1.6.3", - "semver": "^7.3.8", - "tar": "^6.1.12", - "temp-file": "^3.4.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "dmg-builder": "25.1.8", - "electron-builder-squirrel-windows": "25.1.8" - } - }, - "node_modules/app-builder-lib/node_modules/minimatch": { - "version": "10.0.3", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/app-builder-lib/node_modules/minipass": { - "version": "5.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/app-builder-lib/node_modules/tar": { - "version": "6.2.1", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/app-builder-lib/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/aproba": { - "version": "2.1.0", - "dev": true, - "license": "ISC" - }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/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, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/archiver-utils/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/archiver-utils/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/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, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.0" - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.6", - "dev": true, - "license": "MIT" - }, - "node_modules/async-exit-hook": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/async-function": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "license": "MIT" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.21", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.4", - "caniuse-lite": "^1.0.30001702", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.12.2", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.17", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "dev": true, - "license": "MIT" - }, - "node_modules/bluebird-lst": { - "version": "1.0.9", - "dev": true, - "license": "MIT", - "dependencies": { - "bluebird": "^3.5.5" - } - }, - "node_modules/boolean": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.26.3", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/builder-util": { - "version": "25.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/debug": "^4.1.6", - "7zip-bin": "~5.2.0", - "app-builder-bin": "5.0.0-alpha.10", - "bluebird-lst": "^1.0.9", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "debug": "^4.3.4", - "fs-extra": "^10.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "is-ci": "^3.0.0", - "js-yaml": "^4.1.0", - "source-map-support": "^0.5.19", - "stat-mode": "^1.0.0", - "temp-file": "^3.4.0" - } - }, - "node_modules/builder-util-runtime": { - "version": "9.2.10", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/builder-util/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/builder-util/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/builder-util/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/builder-util/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/builder-util/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/builder-util/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacache": { - "version": "16.1.3", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacache/node_modules/tar": { - "version": "6.2.1", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001751", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "2.4.2", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/chromium-pickle-js": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/ci-info": { - "version": "3.9.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "license": "Apache-2.0", - "dependencies": { - "clsx": "^2.1.1" - }, - "funding": { - "url": "https://polar.sh/cva" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cliui/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cliui/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/coa": { - "version": "2.0.2", - "license": "MIT", - "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/code-block-writer": { - "version": "11.0.3", - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "1.9.3", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "dev": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "5.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/compare-version": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "license": "MIT" - }, - "node_modules/config-file-ts": { - "version": "0.2.8-rc1", - "dev": true, - "license": "MIT", - "dependencies": { - "glob": "^10.3.12", - "typescript": "^5.4.3" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "dev": true, - "license": "ISC" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "1.0.2", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "dev": true, - "license": "MIT", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/crc": { - "version": "3.8.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.1.0" - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cross-env": { - "version": "7.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "devOptional": true, - "license": "MIT" - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/defaults": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/dir-compare": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "minimatch": "^3.0.5", - "p-limit": "^3.1.0 " - } - }, - "node_modules/dir-compare/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/dir-compare/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/dmg-builder": { - "version": "25.1.8", - "dev": true, - "license": "MIT", - "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "fs-extra": "^10.1.0", - "iconv-lite": "^0.6.2", - "js-yaml": "^4.1.0" - }, - "optionalDependencies": { - "dmg-license": "^1.0.11" - } - }, - "node_modules/dmg-license": { - "version": "1.0.11", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - }, - "bin": { - "dmg-license": "bin/dmg-license.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-expand": { - "version": "11.0.7", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^16.4.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dts-for-context-bridge": { - "version": "0.7.1", - "license": "MIT", - "dependencies": { - "coa": "2.0.2", - "ts-morph": "13.0.2" - }, - "bin": { - "dts-cb": "bin/index.js" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/ejs": { - "version": "3.1.10", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron": { - "version": "32.0.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-32.0.0.tgz", - "integrity": "sha512-rs+VkhztJd2LvRX7d3ikKH+EIHMW4vKM2l5qp7Dx/dLQAKKz3IFNKyYhYzczDnqO+/jUvx0ic0SQvqpv1/ZAsw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^20.9.0", - "extract-zip": "^2.0.1" - }, - "bin": { - "electron": "cli.js" - }, - "engines": { - "node": ">= 12.20.55" - } - }, - "node_modules/electron-builder": { - "version": "25.1.8", - "dev": true, - "license": "MIT", - "dependencies": { - "app-builder-lib": "25.1.8", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "dmg-builder": "25.1.8", - "fs-extra": "^10.1.0", - "is-ci": "^3.0.0", - "lazy-val": "^1.0.5", - "simple-update-notifier": "2.0.0", - "yargs": "^17.6.2" - }, - "bin": { - "electron-builder": "cli.js", - "install-app-deps": "install-app-deps.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/electron-builder-squirrel-windows": { - "version": "25.1.8", - "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.1.8.tgz", - "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "app-builder-lib": "25.1.8", - "archiver": "^5.3.1", - "builder-util": "25.1.7", - "fs-extra": "^10.1.0" - } - }, - "node_modules/electron-builder/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/electron-builder/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/electron-builder/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/electron-builder/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-builder/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-builder/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-devtools-installer": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "rimraf": "^3.0.2", - "semver": "^7.2.1", - "tslib": "^2.1.0", - "unzip-crx-3": "^0.2.0" - } - }, - "node_modules/electron-publish": { - "version": "25.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^9.0.11", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "fs-extra": "^10.1.0", - "lazy-val": "^1.0.5", - "mime": "^2.5.2" - } - }, - "node_modules/electron-publish/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/electron-publish/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/electron-publish/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/electron-publish/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-publish/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-publish/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.237", - "dev": true, - "license": "ISC" - }, - "node_modules/electron-updater": { - "version": "6.6.2", - "license": "MIT", - "dependencies": { - "builder-util-runtime": "9.3.1", - "fs-extra": "^10.1.0", - "js-yaml": "^4.1.0", - "lazy-val": "^1.0.5", - "lodash.escaperegexp": "^4.1.2", - "lodash.isequal": "^4.5.0", - "semver": "^7.6.3", - "tiny-typed-emitter": "^2.1.0" - } - }, - "node_modules/electron-updater/node_modules/builder-util-runtime": { - "version": "9.3.1", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/electron/node_modules/@types/node": { - "version": "20.19.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz", - "integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "license": "MIT" - }, - "node_modules/encoding": { - "version": "0.1.13", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/error-ex": { - "version": "1.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.6", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.4", - "safe-array-concat": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/escalade": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/parser": "^7.24.4", - "hermes-parser": "^0.25.1", - "zod": "^3.22.4 || ^4.0.0", - "zod-validation-error": "^3.0.3 || ^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.24", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": ">=8.40" - } - }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.4.1", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", - "optional": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.19.1", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.4", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/framer-motion": { - "version": "12.23.24", - "license": "MIT", - "dependencies": { - "motion-dom": "^12.23.23", - "motion-utils": "^12.23.6", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "dev": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gauge/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "10.4.5", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-agent": { - "version": "3.0.0", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "11.8.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "dev": true, - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.2", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hermes-estree": { - "version": "0.25.1", - "dev": true, - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.25.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hermes-estree": "0.25.1" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/husky": { - "version": "9.1.7", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/iconv-corefoundation": { - "version": "1.1.7", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - }, - "engines": { - "node": "^8.11.2 || >=10" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "dev": true, - "license": "ISC" - }, - "node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "license": "ISC" - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip-address": { - "version": "10.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/is-map": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/isbinaryfile": { - "version": "5.0.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jake": { - "version": "10.9.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/json5": { - "version": "2.2.3", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.2.0", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/jszip": { - "version": "3.10.1", - "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/lazy-val": { - "version": "1.0.5", - "license": "MIT" - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/lightningcss": { - "version": "1.30.1", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.30.1", - "lightningcss-darwin-x64": "1.30.1", - "lightningcss-freebsd-x64": "1.30.1", - "lightningcss-linux-arm-gnueabihf": "1.30.1", - "lightningcss-linux-arm64-gnu": "1.30.1", - "lightningcss-linux-arm64-musl": "1.30.1", - "lightningcss-linux-x64-gnu": "1.30.1", - "lightningcss-linux-x64-musl": "1.30.1", - "lightningcss-win32-arm64-msvc": "1.30.1", - "lightningcss-win32-x64-msvc": "1.30.1" - } - }, - "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" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", - "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", - "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", - "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", - "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", - "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", - "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", - "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", - "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.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" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss/node_modules/lightningcss-darwin-arm64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", - "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss/node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", - "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "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", - "dev": true, - "license": "MIT" - }, - "node_modules/lint-staged": { - "version": "16.2.4", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^14.0.1", - "listr2": "^9.0.4", - "micromatch": "^4.0.8", - "nano-spawn": "^2.0.0", - "pidtree": "^0.6.0", - "string-argv": "^0.3.2", - "yaml": "^2.8.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/commander": { - "version": "14.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/listr2": { - "version": "9.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/listr2/node_modules/ansi-styles": { - "version": "6.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/listr2/node_modules/cli-truncate": { - "version": "5.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^7.1.0", - "string-width": "^8.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.6.0", - "dev": true, - "license": "MIT" - }, - "node_modules/listr2/node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/node_modules/slice-ansi": { - "version": "7.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/listr2/node_modules/string-width": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/listr2/node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "license": "MIT" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-update": { - "version": "6.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/cli-cursor": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.6.0", - "dev": true, - "license": "MIT" - }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/onetime": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/restore-cursor": { - "version": "5.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.19", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "dev": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/agent-base": { - "version": "6.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/make-fetch-happen/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/matcher": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/matcher/node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime": { - "version": "2.6.0", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "9.0.5", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-fetch/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-fetch/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/minizlib": { - "version": "2.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/motion-dom": { - "version": "12.23.23", - "license": "MIT", - "dependencies": { - "motion-utils": "^12.23.6" - } - }, - "node_modules/motion-utils": { - "version": "12.23.6", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/nano-spawn": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/no-case": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-abi": { - "version": "3.78.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "1.7.2", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/node-api-version": { - "version": "0.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - } - }, - "node_modules/node-gyp": { - "version": "9.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/node-gyp/node_modules/minipass": { - "version": "5.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/node-gyp/node_modules/tar": { - "version": "6.2.1", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/node-releases": { - "version": "2.0.25", - "dev": true, - "license": "MIT" - }, - "node_modules/nopt": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/pako": { - "version": "1.0.11", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "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-browserify": { - "version": "1.0.1", - "license": "MIT" - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "dev": true, - "license": "ISC" - }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pe-library": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/plist": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.6.2", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/prettier-plugin-tailwindcss": { - "version": "0.7.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.19" - }, - "peerDependencies": { - "@ianvs/prettier-plugin-sort-imports": "*", - "@prettier/plugin-hermes": "*", - "@prettier/plugin-oxc": "*", - "@prettier/plugin-pug": "*", - "@shopify/prettier-plugin-liquid": "*", - "@trivago/prettier-plugin-sort-imports": "*", - "@zackad/prettier-plugin-twig": "*", - "prettier": "^3.0", - "prettier-plugin-astro": "*", - "prettier-plugin-css-order": "*", - "prettier-plugin-jsdoc": "*", - "prettier-plugin-marko": "*", - "prettier-plugin-multiline-arrays": "*", - "prettier-plugin-organize-attributes": "*", - "prettier-plugin-organize-imports": "*", - "prettier-plugin-sort-imports": "*", - "prettier-plugin-svelte": "*" - }, - "peerDependenciesMeta": { - "@ianvs/prettier-plugin-sort-imports": { - "optional": true - }, - "@prettier/plugin-hermes": { - "optional": true - }, - "@prettier/plugin-oxc": { - "optional": true - }, - "@prettier/plugin-pug": { - "optional": true - }, - "@shopify/prettier-plugin-liquid": { - "optional": true - }, - "@trivago/prettier-plugin-sort-imports": { - "optional": true - }, - "@zackad/prettier-plugin-twig": { - "optional": true - }, - "prettier-plugin-astro": { - "optional": true - }, - "prettier-plugin-css-order": { - "optional": true - }, - "prettier-plugin-jsdoc": { - "optional": true - }, - "prettier-plugin-marko": { - "optional": true - }, - "prettier-plugin-multiline-arrays": { - "optional": true - }, - "prettier-plugin-organize-attributes": { - "optional": true - }, - "prettier-plugin-organize-imports": { - "optional": true - }, - "prettier-plugin-sort-imports": { - "optional": true - }, - "prettier-plugin-svelte": { - "optional": true - } - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/progress": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "dev": true, - "license": "ISC" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "dev": true, - "license": "MIT", - "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", - "dev": true, - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "license": "MIT" - }, - "node_modules/pump": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react": { - "version": "18.3.1", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-hook-form": { - "version": "7.66.0", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.66.0.tgz", - "integrity": "sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-hook-form" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18 || ^19" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-router": { - "version": "7.9.4", - "license": "MIT", - "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/react-router-dom": { - "version": "7.9.4", - "license": "MIT", - "dependencies": { - "react-router": "7.9.4" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, - "node_modules/react-webcam": { - "version": "7.2.0", - "license": "MIT", - "peerDependencies": { - "react": ">=16.2.0", - "react-dom": ">=16.2.0" - } - }, - "node_modules/read-binary-file-arch": { - "version": "1.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "bin": { - "read-binary-file-arch": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resedit": { - "version": "1.7.2", - "dev": true, - "license": "MIT", - "dependencies": { - "pe-library": "^0.4.1" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/responselike": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "node_modules/retry": { - "version": "0.12.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/roarr": { - "version": "2.15.4", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/rollup": { - "version": "4.52.5", - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.5", - "@rollup/rollup-android-arm64": "4.52.5", - "@rollup/rollup-darwin-arm64": "4.52.5", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-freebsd-arm64": "4.52.5", - "@rollup/rollup-freebsd-x64": "4.52.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", - "@rollup/rollup-linux-arm-musleabihf": "4.52.5", - "@rollup/rollup-linux-arm64-gnu": "4.52.5", - "@rollup/rollup-linux-arm64-musl": "4.52.5", - "@rollup/rollup-linux-loong64-gnu": "4.52.5", - "@rollup/rollup-linux-ppc64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-musl": "4.52.5", - "@rollup/rollup-linux-s390x-gnu": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-linux-x64-musl": "4.52.5", - "@rollup/rollup-openharmony-arm64": "4.52.5", - "@rollup/rollup-win32-arm64-msvc": "4.52.5", - "@rollup/rollup-win32-ia32-msvc": "4.52.5", - "@rollup/rollup-win32-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/sanitize-filename": { - "version": "1.6.3", - "dev": true, - "license": "WTFPL OR ISC", - "dependencies": { - "truncate-utf8-bytes": "^1.0.0" - } - }, - "node_modules/sax": { - "version": "1.4.1", - "license": "ISC" - }, - "node_modules/scheduler": { - "version": "0.23.2", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "7.7.3", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serialize-error/node_modules/type-fest": { - "version": "0.13.1", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "license": "MIT" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/snake-case": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "6.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "dev": true, - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/ssri": { - "version": "9.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ssri/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ssri/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/stat-mode": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sumchecker": { - "version": "3.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.1.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-parser": { - "version": "2.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/synckit": { - "version": "0.11.11", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, - "node_modules/tailwind-merge": { - "version": "2.6.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "4.1.14", - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tar": { - "version": "7.5.1", - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/chownr": { - "version": "3.0.0", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/tar/node_modules/minizlib": { - "version": "3.1.0", - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "5.0.0", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/temp-file": { - "version": "3.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "async-exit-hook": "^2.0.1", - "fs-extra": "^10.0.0" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/tiny-typed-emitter": { - "version": "2.1.0", - "license": "MIT" - }, - "node_modules/tmp": { - "version": "0.2.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/truncate-utf8-bytes": { - "version": "1.0.2", - "dev": true, - "license": "WTFPL", - "dependencies": { - "utf8-byte-length": "^1.0.1" - } - }, - "node_modules/ts-api-utils": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/ts-morph": { - "version": "13.0.2", - "license": "MIT", - "dependencies": { - "@ts-morph/common": "~0.12.2", - "code-block-writer": "^11.0.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "license": "0BSD" - }, - "node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unique-filename": { - "version": "2.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/unique-slug": { - "version": "3.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/universalify": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unzip-crx-3": { - "version": "0.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jszip": "^3.1.0", - "mkdirp": "^0.5.1", - "yaku": "^0.16.6" - } - }, - "node_modules/unzip-crx-3/node_modules/mkdirp": { - "version": "0.5.6", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf8-byte-length": { - "version": "1.0.5", - "dev": true, - "license": "(WTFPL OR MIT)" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/verror": { - "version": "1.10.1", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/vite": { - "version": "5.4.20", - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-plugin-svgr": { - "version": "4.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.2.0", - "@svgr/core": "^8.1.0", - "@svgr/plugin-jsx": "^8.1.0" - }, - "peerDependencies": { - "vite": ">=2.6.0" - } - }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yaku": { - "version": "0.16.7", - "dev": true, - "license": "MIT" - }, - "node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.8.1", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/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, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/zip-stream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/zip-stream/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, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/zod": { - "version": "4.1.12", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-validation-error": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - } - }, - "node_modules/zustand": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz", - "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=18.0.0", - "immer": ">=9.0.6", - "react": ">=18.0.0", - "use-sync-external-store": ">=1.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - }, - "use-sync-external-store": { - "optional": true - } - } - }, - "packages/api": { - "version": "0.0.0", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@tanstack/react-query": "^5.0.0", - "axios": "^1.6.0" - }, - "devDependencies": { - "config": "*", - "tsconfig": "*", - "typescript": "^5.0.0" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "packages/config": { - "version": "0.0.0", - "extraneous": true, - "license": "MIT" - }, - "packages/tsconfig": { - "version": "0.0.0", - "extraneous": true - }, - "packages/ui": { - "version": "0.0.0", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@tailwindcss/vite": "^4.1.14", - "class-variance-authority": "^0.7.1", - "clsx": "^2.0.0", - "framer-motion": "^12.23.24", - "tailwind-merge": "^2.0.0", - "tailwindcss": "^4.1.14" - }, - "devDependencies": { - "@chromatic-com/storybook": "^4.1.1", - "@storybook/addon-a11y": "^9.1.10", - "@storybook/addon-docs": "^9.1.10", - "@storybook/addon-onboarding": "^9.1.10", - "@storybook/addon-themes": "^9.1.13", - "@storybook/addon-vitest": "^9.1.10", - "@storybook/react-vite": "^9.1.10", - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "@vitest/browser": "^3.2.4", - "@vitest/coverage-v8": "^3.2.4", - "config": "*", - "playwright": "^1.56.0", - "storybook": "^9.1.10", - "tsconfig": "*", - "typescript": "^5.0.0", - "vitest": "^3.2.4" - } - } - } -} diff --git a/package.json b/package.json index d1fd21b..19cb3f6 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,35 @@ { - "name": "electron-app", + "name": "GBGR", "version": "1.0.0", - "description": "거부기 Electron Application", + "description": "거부기린", "author": { - "name": "Yerba Team", - "email": "your-email@example.com" + "name": "GBGR" }, - "homepage": "https://your-project-homepage.com", - "maintainer": "Yerba Team ", + "homepage": "https://bugi.co.kr", "private": true, "main": "dist/main/index.cjs", "engines": { - "npm": ">=8.0.0", + "pnpm": ">=8.0.0", "node": ">=18.0.0" }, - "packageManager": "npm@10.0.0", + "packageManager": "pnpm@9.0.0", "scripts": { "postinstall": "node scripts/update-electron-vendors.js", "dev": "node scripts/watch.js", - "dev:renderer": "vite src/renderer", - "build": "npm run build:main && npm run build:preload && npm run build:renderer", + "dev:renderer": "vite", + "build": "pnpm run build:main && pnpm run build:preload && pnpm run build:renderer", "build:main": "vite build src/main", "build:preload": "vite build src/preload", - "build:renderer": "vite build src/renderer", + "build:renderer": "vite build", "build:preload:types": "dts-cb -i \"src/preload/tsconfig.json\" -o \"src/preload/exposedInMainWorld.d.ts\"", - "compile": "cross-env MODE=production npm run build && electron-builder build --config .electron-builder.config.js --dir --config.asar=false", - "build:mac": "cross-env MODE=production npm run build && electron-builder build --config .electron-builder.config.js --mac", - "build:win": "cross-env MODE=production npm run build && electron-builder build --config .electron-builder.config.js --win", - "build:all": "cross-env MODE=production npm run build && electron-builder build --config .electron-builder.config.js --mac --win", + "start": "cross-env MODE=production electron .", + "start:prod": "cross-env MODE=production pnpm run build && cross-env MODE=production electron .", + "start:renderer": "vite preview --config vite.config.mts", + "start:renderer:prod": "pnpm run build:renderer && vite preview --config vite.config.mts", + "compile": "cross-env MODE=production pnpm run build && electron-builder build --config .electron-builder.config.js --dir --config.asar=false", + "build:mac": "cross-env MODE=production pnpm run build && electron-builder build --config .electron-builder.config.js --mac", + "build:win": "cross-env MODE=production pnpm run build && electron-builder build --config .electron-builder.config.js --win", + "build:all": "cross-env MODE=production pnpm run build && electron-builder build --config .electron-builder.config.js --mac --win", "watch": "node scripts/watch.js", "lint": "eslint . --ext js,ts,tsx --fix", "lint:check": "eslint . --ext js,ts,tsx", @@ -36,73 +38,61 @@ "typecheck:main": "tsc --noEmit -p src/main/tsconfig.json", "typecheck:preload": "tsc --noEmit -p src/preload/tsconfig.json", "typecheck:renderer": "tsc --noEmit -p src/renderer/tsconfig.json", - "typecheck": "npm run typecheck:main && npm run typecheck:preload && npm run typecheck:renderer" + "typecheck": "pnpm run typecheck:main && pnpm run typecheck:preload && pnpm run typecheck:renderer" }, "dependencies": { - "@hookform/resolvers": "^5.2.2", - "@mediapipe/tasks-vision": "^0.10.22-rc.20250304", - "@tailwindcss/vite": "^4.1.14", - "@tanstack/react-query": "^5.0.0", - "axios": "^1.6.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.0.0", - "dts-for-context-bridge": "^0.7.1", - "electron-updater": "^6.0.0", - "framer-motion": "^12.23.24", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-hook-form": "^7.65.0", - "react-router-dom": "^7.9.4", - "react-webcam": "^7.2.0", - "tailwind-merge": "^2.0.0", - "tailwindcss": "^4.1.14", - "zod": "^4.1.12", - "zustand": "^5.0.8" + "@hookform/resolvers": "5.2.2", + "@mediapipe/tasks-vision": "0.10.22-rc.20250304", + "@tailwindcss/vite": "4.1.16", + "@tanstack/react-query": "5.90.6", + "axios": "1.13.1", + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "dts-for-context-bridge": "0.7.1", + "electron-updater": "6.6.2", + "framer-motion": "12.23.24", + "react": "19.2.0", + "react-dom": "19.2.0", + "react-hook-form": "7.66.0", + "react-router-dom": "7.9.5", + "react-webcam": "7.2.0", + "recharts": "^3.3.0", + "zustand": "5.0.8" }, "devDependencies": { - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "^8.46.1", - "@typescript-eslint/parser": "^8.46.1", - "@vitejs/plugin-react": "^4.0.0", - "autoprefixer": "^10.4.0", - "cross-env": "^7.0.3", - "electron": "^32.0.0", - "electron-builder": "^25.1.8", - "electron-devtools-installer": "^3.2.0", - "eslint": "^8.57.1", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-prettier": "^5.5.4", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^7.0.0", - "eslint-plugin-react-refresh": "^0.4.24", - "husky": "^9.1.7", - "lint-staged": "^16.2.4", - "postcss": "^8.4.0", - "prettier": "^3.6.2", - "prettier-plugin-tailwindcss": "^0.7.1", - "typescript": "^5.0.0", - "vite": "^5.0.0", - "vite-plugin-svgr": "^4.5.0" - }, - "optionalDependencies": { - "@esbuild/darwin-arm64": "latest", - "@esbuild/darwin-x64": "latest", - "@esbuild/linux-x64": "latest", - "@esbuild/win32-x64": "latest", - "@rollup/rollup-darwin-arm64": "latest", - "@rollup/rollup-darwin-x64": "latest", - "@rollup/rollup-linux-x64-gnu": "latest", - "@rollup/rollup-win32-x64-msvc": "latest", - "@tailwindcss/oxide-darwin-arm64": "latest", - "@tailwindcss/oxide-darwin-x64": "latest", - "@tailwindcss/oxide-linux-x64-gnu": "latest", - "@tailwindcss/oxide-win32-x64-msvc": "latest", - "lightningcss-darwin-arm64": "latest", - "lightningcss-darwin-x64": "latest", - "lightningcss-linux-x64-gnu": "latest", - "lightningcss-win32-x64-msvc": "latest" + "@tailwindcss/vite": "4.1.16", + "@types/react": "19.2.2", + "@types/react-dom": "19.2.2", + "@types/react-router-dom": "5.3.3", + "@typescript-eslint/eslint-plugin": "8.46.2", + "@typescript-eslint/parser": "8.46.2", + "@vitejs/plugin-react": "5.1.0", + "autoprefixer": "10.4.21", + "cross-env": "10.1.0", + "dotenv": "^17.2.3", + "dts-for-context-bridge": "0.7.1", + "electron": "39.0.0", + "electron-builder": "26.0.12", + "electron-devtools-installer": "4.0.0", + "esbuild": "^0.25.12", + "eslint": "9.39.0", + "eslint-config-prettier": "10.1.8", + "eslint-plugin-prettier": "5.5.4", + "eslint-plugin-react": "7.37.5", + "eslint-plugin-react-hooks": "7.0.1", + "eslint-plugin-react-refresh": "0.4.24", + "globals": "^16.5.0", + "husky": "9.1.7", + "lint-staged": "16.2.6", + "postcss": "8.5.6", + "prettier": "3.6.2", + "prettier-plugin-tailwindcss": "0.7.1", + "tailwind-merge": "3.3.1", + "tailwindcss": "4.1.16", + "typescript": "5.9.3", + "vite": "7.1.12", + "vite-plugin-svgr": "4.5.0", + "zod": "4.1.12" }, "lint-staged": { "*.{js,jsx,ts,tsx}": [ @@ -110,5 +100,14 @@ "prettier --write" ], "*.{json,css,md}": "prettier --write" + }, + "electronLanguagesInfoPlistStrings": { + "ko": { + "CFBundleName": "거부기린", + "CFBundleDisplayName": "거부기린", + "NSHumanReadableCopyright": "Copyright © 2025 GBGR", + "NSCameraUsageDescription": "거부기린은 사용자의 자세를 실시간으로 분석하기 위해 카메라에 접근합니다.", + "NSMicrophoneUsageDescription": "거부기린은 사용자의 자세를 실시간으로 분석하기 위해 마이크에 접근합니다." + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..da81940 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,9895 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + '@hookform/resolvers': + specifier: 5.2.2 + version: 5.2.2(react-hook-form@7.66.0(react@19.2.0)) + '@mediapipe/tasks-vision': + specifier: 0.10.22-rc.20250304 + version: 0.10.22-rc.20250304 + '@tailwindcss/vite': + specifier: 4.1.16 + version: 4.1.16(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@tanstack/react-query': + specifier: 5.90.6 + version: 5.90.6(react@19.2.0) + axios: + specifier: 1.13.1 + version: 1.13.1 + class-variance-authority: + specifier: 0.7.1 + version: 0.7.1 + clsx: + specifier: 2.1.1 + version: 2.1.1 + dts-for-context-bridge: + specifier: 0.7.1 + version: 0.7.1 + electron-updater: + specifier: 6.6.2 + version: 6.6.2 + framer-motion: + specifier: 12.23.24 + version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: + specifier: 19.2.0 + version: 19.2.0 + react-dom: + specifier: 19.2.0 + version: 19.2.0(react@19.2.0) + react-hook-form: + specifier: 7.66.0 + version: 7.66.0(react@19.2.0) + react-router-dom: + specifier: 7.9.5 + version: 7.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-webcam: + specifier: 7.2.0 + version: 7.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + recharts: + specifier: ^3.3.0 + version: 3.3.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@16.13.1)(react@19.2.0)(redux@5.0.1) + zustand: + specifier: 5.0.8 + version: 5.0.8(@types/react@19.2.2)(immer@10.2.0)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + devDependencies: + '@types/react': + specifier: 19.2.2 + version: 19.2.2 + '@types/react-dom': + specifier: 19.2.2 + version: 19.2.2(@types/react@19.2.2) + '@types/react-router-dom': + specifier: 5.3.3 + version: 5.3.3 + '@typescript-eslint/eslint-plugin': + specifier: 8.46.2 + version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: 8.46.2 + version: 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@vitejs/plugin-react': + specifier: 5.1.0 + version: 5.1.0(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + autoprefixer: + specifier: 10.4.21 + version: 10.4.21(postcss@8.5.6) + cross-env: + specifier: 10.1.0 + version: 10.1.0 + dotenv: + specifier: ^17.2.3 + version: 17.2.3 + electron: + specifier: 39.0.0 + version: 39.0.0 + electron-builder: + specifier: 26.0.12 + version: 26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)) + electron-devtools-installer: + specifier: 4.0.0 + version: 4.0.0 + esbuild: + specifier: ^0.25.12 + version: 0.25.12 + eslint: + specifier: 9.39.0 + version: 9.39.0(jiti@2.6.1) + eslint-config-prettier: + specifier: 10.1.8 + version: 10.1.8(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-prettier: + specifier: 5.5.4 + version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@2.6.1)))(eslint@9.39.0(jiti@2.6.1))(prettier@3.6.2) + eslint-plugin-react: + specifier: 7.37.5 + version: 7.37.5(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-react-hooks: + specifier: 7.0.1 + version: 7.0.1(eslint@9.39.0(jiti@2.6.1)) + eslint-plugin-react-refresh: + specifier: 0.4.24 + version: 0.4.24(eslint@9.39.0(jiti@2.6.1)) + globals: + specifier: ^16.5.0 + version: 16.5.0 + husky: + specifier: 9.1.7 + version: 9.1.7 + lint-staged: + specifier: 16.2.6 + version: 16.2.6 + postcss: + specifier: 8.5.6 + version: 8.5.6 + prettier: + specifier: 3.6.2 + version: 3.6.2 + prettier-plugin-tailwindcss: + specifier: 0.7.1 + version: 0.7.1(prettier@3.6.2) + tailwind-merge: + specifier: 3.3.1 + version: 3.3.1 + tailwindcss: + specifier: 4.1.16 + version: 4.1.16 + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: 7.1.12 + version: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + vite-plugin-svgr: + specifier: 4.5.0 + version: 4.5.0(rollup@4.52.5)(typescript@5.9.3)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + zod: + specifier: 4.1.12 + version: 4.1.12 + +packages: + 7zip-bin@5.2.0: + resolution: + { + integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==, + } + + '@babel/code-frame@7.27.1': + resolution: + { + integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==, + } + engines: { node: '>=6.9.0' } + + '@babel/compat-data@7.28.5': + resolution: + { + integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==, + } + engines: { node: '>=6.9.0' } + + '@babel/core@7.28.5': + resolution: + { + integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==, + } + engines: { node: '>=6.9.0' } + + '@babel/generator@7.28.5': + resolution: + { + integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-compilation-targets@7.27.2': + resolution: + { + integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-globals@7.28.0': + resolution: + { + integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-module-imports@7.27.1': + resolution: + { + integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-module-transforms@7.28.3': + resolution: + { + integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: + { + integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-string-parser@7.27.1': + resolution: + { + integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-validator-identifier@7.28.5': + resolution: + { + integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-validator-option@7.27.1': + resolution: + { + integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==, + } + engines: { node: '>=6.9.0' } + + '@babel/helpers@7.28.4': + resolution: + { + integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==, + } + engines: { node: '>=6.9.0' } + + '@babel/parser@7.28.5': + resolution: + { + integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==, + } + engines: { node: '>=6.0.0' } + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: + { + integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: + { + integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.27.2': + resolution: + { + integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==, + } + engines: { node: '>=6.9.0' } + + '@babel/traverse@7.28.5': + resolution: + { + integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==, + } + engines: { node: '>=6.9.0' } + + '@babel/types@7.28.5': + resolution: + { + integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==, + } + engines: { node: '>=6.9.0' } + + '@develar/schema-utils@2.6.5': + resolution: + { + integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==, + } + engines: { node: '>= 8.9.0' } + + '@electron/asar@3.2.18': + resolution: + { + integrity: sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==, + } + engines: { node: '>=10.12.0' } + hasBin: true + + '@electron/asar@3.4.1': + resolution: + { + integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==, + } + engines: { node: '>=10.12.0' } + hasBin: true + + '@electron/fuses@1.8.0': + resolution: + { + integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==, + } + hasBin: true + + '@electron/get@2.0.3': + resolution: + { + integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==, + } + engines: { node: '>=12' } + + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': + resolution: + { + tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2, + } + version: 10.2.0-electron.1 + engines: { node: '>=12.13.0' } + hasBin: true + + '@electron/notarize@2.5.0': + resolution: + { + integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==, + } + engines: { node: '>= 10.0.0' } + + '@electron/osx-sign@1.3.1': + resolution: + { + integrity: sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==, + } + engines: { node: '>=12.0.0' } + hasBin: true + + '@electron/rebuild@3.7.0': + resolution: + { + integrity: sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==, + } + engines: { node: '>=12.13.0' } + hasBin: true + + '@electron/universal@2.0.1': + resolution: + { + integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==, + } + engines: { node: '>=16.4' } + + '@electron/windows-sign@1.2.2': + resolution: + { + integrity: sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==, + } + engines: { node: '>=14.14' } + hasBin: true + + '@epic-web/invariant@1.0.0': + resolution: + { + integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==, + } + + '@esbuild/aix-ppc64@0.25.12': + resolution: + { + integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: + { + integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: + { + integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: + { + integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: + { + integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: + { + integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: + { + integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: + { + integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: + { + integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: + { + integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: + { + integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: + { + integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==, + } + engines: { node: '>=18' } + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: + { + integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==, + } + engines: { node: '>=18' } + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: + { + integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: + { + integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==, + } + engines: { node: '>=18' } + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: + { + integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==, + } + engines: { node: '>=18' } + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: + { + integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: + { + integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: + { + integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: + { + integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: + { + integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: + { + integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: + { + integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: + { + integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: + { + integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: + { + integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.0': + resolution: + { + integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: + { + integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + + '@eslint/config-array@0.21.1': + resolution: + { + integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/config-helpers@0.4.2': + resolution: + { + integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/core@0.17.0': + resolution: + { + integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/eslintrc@3.3.1': + resolution: + { + integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/js@9.39.0': + resolution: + { + integrity: sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/object-schema@2.1.7': + resolution: + { + integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/plugin-kit@0.4.1': + resolution: + { + integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@gar/promisify@1.1.3': + resolution: + { + integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==, + } + + '@hookform/resolvers@5.2.2': + resolution: + { + integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==, + } + peerDependencies: + react-hook-form: ^7.55.0 + + '@humanfs/core@0.19.1': + resolution: + { + integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, + } + engines: { node: '>=18.18.0' } + + '@humanfs/node@0.16.7': + resolution: + { + integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==, + } + engines: { node: '>=18.18.0' } + + '@humanwhocodes/module-importer@1.0.1': + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: '>=12.22' } + + '@humanwhocodes/retry@0.4.3': + resolution: + { + integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==, + } + engines: { node: '>=18.18' } + + '@isaacs/balanced-match@4.0.1': + resolution: + { + integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==, + } + engines: { node: 20 || >=22 } + + '@isaacs/brace-expansion@5.0.0': + resolution: + { + integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==, + } + engines: { node: 20 || >=22 } + + '@isaacs/cliui@8.0.2': + resolution: + { + integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, + } + engines: { node: '>=12' } + + '@jridgewell/gen-mapping@0.3.13': + resolution: + { + integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, + } + + '@jridgewell/remapping@2.3.5': + resolution: + { + integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, + } + + '@jridgewell/resolve-uri@3.1.2': + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: '>=6.0.0' } + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: + { + integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, + } + + '@jridgewell/trace-mapping@0.3.31': + resolution: + { + integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, + } + + '@malept/cross-spawn-promise@2.0.0': + resolution: + { + integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==, + } + engines: { node: '>= 12.13.0' } + + '@malept/flatpak-bundler@0.4.0': + resolution: + { + integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==, + } + engines: { node: '>= 10.0.0' } + + '@mediapipe/tasks-vision@0.10.22-rc.20250304': + resolution: + { + integrity: sha512-dElxVXMFGthshfIj+qAVm8KE2jmNo2p8oXFib8WzEjb7GNaX/ClWBc8UJfoSZwjEMVrdHJ4YUfa7P3ifl6MIWw==, + } + + '@nodelib/fs.scandir@2.1.5': + resolution: + { + integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, + } + engines: { node: '>= 8' } + + '@nodelib/fs.stat@2.0.5': + resolution: + { + integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, + } + engines: { node: '>= 8' } + + '@nodelib/fs.walk@1.2.8': + resolution: + { + integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, + } + engines: { node: '>= 8' } + + '@npmcli/fs@2.1.2': + resolution: + { + integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + '@npmcli/move-file@2.0.1': + resolution: + { + integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + deprecated: This functionality has been moved to @npmcli/fs + + '@pkgjs/parseargs@0.11.0': + resolution: + { + integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, + } + engines: { node: '>=14' } + + '@pkgr/core@0.2.9': + resolution: + { + integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==, + } + engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 } + + '@reduxjs/toolkit@2.10.1': + resolution: + { + integrity: sha512-/U17EXQ9Do9Yx4DlNGU6eVNfZvFJfYpUtRRdLf19PbPjdWBxNlxGZXywQZ1p1Nz8nMkWplTI7iD/23m07nolDA==, + } + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + + '@rolldown/pluginutils@1.0.0-beta.43': + resolution: + { + integrity: sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==, + } + + '@rollup/pluginutils@5.3.0': + resolution: + { + integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==, + } + engines: { node: '>=14.0.0' } + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: + { + integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==, + } + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.52.5': + resolution: + { + integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==, + } + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: + { + integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==, + } + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.52.5': + resolution: + { + integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==, + } + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: + { + integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==, + } + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: + { + integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==, + } + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: + { + integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==, + } + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: + { + integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==, + } + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: + { + integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==, + } + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: + { + integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==, + } + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: + { + integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==, + } + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: + { + integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==, + } + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: + { + integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==, + } + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: + { + integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==, + } + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: + { + integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==, + } + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: + { + integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==, + } + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: + { + integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==, + } + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: + { + integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==, + } + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: + { + integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==, + } + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: + { + integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==, + } + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: + { + integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==, + } + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: + { + integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==, + } + cpu: [x64] + os: [win32] + + '@sindresorhus/is@4.6.0': + resolution: + { + integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==, + } + engines: { node: '>=10' } + + '@standard-schema/spec@1.0.0': + resolution: + { + integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==, + } + + '@standard-schema/utils@0.3.0': + resolution: + { + integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==, + } + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': + resolution: + { + integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': + resolution: + { + integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': + resolution: + { + integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': + resolution: + { + integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0': + resolution: + { + integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0': + resolution: + { + integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0': + resolution: + { + integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0': + resolution: + { + integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==, + } + engines: { node: '>=12' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-preset@8.1.0': + resolution: + { + integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==, + } + engines: { node: '>=14' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/core@8.1.0': + resolution: + { + integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==, + } + engines: { node: '>=14' } + + '@svgr/hast-util-to-babel-ast@8.0.0': + resolution: + { + integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==, + } + engines: { node: '>=14' } + + '@svgr/plugin-jsx@8.1.0': + resolution: + { + integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==, + } + engines: { node: '>=14' } + peerDependencies: + '@svgr/core': '*' + + '@szmarczak/http-timer@4.0.6': + resolution: + { + integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==, + } + engines: { node: '>=10' } + + '@tailwindcss/node@4.1.16': + resolution: + { + integrity: sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==, + } + + '@tailwindcss/oxide-android-arm64@4.1.16': + resolution: + { + integrity: sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==, + } + engines: { node: '>= 10' } + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.16': + resolution: + { + integrity: sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==, + } + engines: { node: '>= 10' } + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.16': + resolution: + { + integrity: sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==, + } + engines: { node: '>= 10' } + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.16': + resolution: + { + integrity: sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==, + } + engines: { node: '>= 10' } + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16': + resolution: + { + integrity: sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==, + } + engines: { node: '>= 10' } + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.16': + resolution: + { + integrity: sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==, + } + engines: { node: '>= 10' } + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.16': + resolution: + { + integrity: sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==, + } + engines: { node: '>= 10' } + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.16': + resolution: + { + integrity: sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==, + } + engines: { node: '>= 10' } + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.16': + resolution: + { + integrity: sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==, + } + engines: { node: '>= 10' } + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.16': + resolution: + { + integrity: sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==, + } + engines: { node: '>=14.0.0' } + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.16': + resolution: + { + integrity: sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==, + } + engines: { node: '>= 10' } + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.16': + resolution: + { + integrity: sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==, + } + engines: { node: '>= 10' } + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.16': + resolution: + { + integrity: sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==, + } + engines: { node: '>= 10' } + + '@tailwindcss/vite@4.1.16': + resolution: + { + integrity: sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg==, + } + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tanstack/query-core@5.90.6': + resolution: + { + integrity: sha512-AnZSLF26R8uX+tqb/ivdrwbVdGemdEDm1Q19qM6pry6eOZ6bEYiY7mWhzXT1YDIPTNEVcZ5kYP9nWjoxDLiIVw==, + } + + '@tanstack/react-query@5.90.6': + resolution: + { + integrity: sha512-gB1sljYjcobZKxjPbKSa31FUTyr+ROaBdoH+wSSs9Dk+yDCmMs+TkTV3PybRRVLC7ax7q0erJ9LvRWnMktnRAw==, + } + peerDependencies: + react: ^18 || ^19 + + '@tootallnate/once@2.0.0': + resolution: + { + integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==, + } + engines: { node: '>= 10' } + + '@ts-morph/common@0.12.3': + resolution: + { + integrity: sha512-4tUmeLyXJnJWvTFOKtcNJ1yh0a3SsTLi2MUoyj8iUNznFRN1ZquaNe7Oukqrnki2FzZkm0J9adCNLDZxUzvj+w==, + } + + '@types/babel__core@7.20.5': + resolution: + { + integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, + } + + '@types/babel__generator@7.27.0': + resolution: + { + integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==, + } + + '@types/babel__template@7.4.4': + resolution: + { + integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, + } + + '@types/babel__traverse@7.28.0': + resolution: + { + integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==, + } + + '@types/cacheable-request@6.0.3': + resolution: + { + integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==, + } + + '@types/d3-array@3.2.2': + resolution: + { + integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==, + } + + '@types/d3-color@3.1.3': + resolution: + { + integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==, + } + + '@types/d3-ease@3.0.2': + resolution: + { + integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==, + } + + '@types/d3-interpolate@3.0.4': + resolution: + { + integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==, + } + + '@types/d3-path@3.1.1': + resolution: + { + integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==, + } + + '@types/d3-scale@4.0.9': + resolution: + { + integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==, + } + + '@types/d3-shape@3.1.7': + resolution: + { + integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==, + } + + '@types/d3-time@3.0.4': + resolution: + { + integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==, + } + + '@types/d3-timer@3.0.2': + resolution: + { + integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==, + } + + '@types/debug@4.1.12': + resolution: + { + integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==, + } + + '@types/estree@1.0.8': + resolution: + { + integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, + } + + '@types/fs-extra@9.0.13': + resolution: + { + integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==, + } + + '@types/history@4.7.11': + resolution: + { + integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==, + } + + '@types/http-cache-semantics@4.0.4': + resolution: + { + integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==, + } + + '@types/json-schema@7.0.15': + resolution: + { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } + + '@types/keyv@3.1.4': + resolution: + { + integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==, + } + + '@types/ms@2.1.0': + resolution: + { + integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==, + } + + '@types/node@22.19.0': + resolution: + { + integrity: sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA==, + } + + '@types/node@24.10.0': + resolution: + { + integrity: sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==, + } + + '@types/plist@3.0.5': + resolution: + { + integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==, + } + + '@types/q@1.5.8': + resolution: + { + integrity: sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==, + } + + '@types/react-dom@19.2.2': + resolution: + { + integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==, + } + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react-router-dom@5.3.3': + resolution: + { + integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==, + } + + '@types/react-router@5.1.20': + resolution: + { + integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==, + } + + '@types/react@19.2.2': + resolution: + { + integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==, + } + + '@types/responselike@1.0.3': + resolution: + { + integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==, + } + + '@types/use-sync-external-store@0.0.6': + resolution: + { + integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==, + } + + '@types/verror@1.10.11': + resolution: + { + integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==, + } + + '@types/yauzl@2.10.3': + resolution: + { + integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==, + } + + '@typescript-eslint/eslint-plugin@8.46.2': + resolution: + { + integrity: sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + '@typescript-eslint/parser': ^8.46.2 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.46.2': + resolution: + { + integrity: sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.46.2': + resolution: + { + integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.46.2': + resolution: + { + integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@typescript-eslint/tsconfig-utils@8.46.2': + resolution: + { + integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.46.2': + resolution: + { + integrity: sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.46.2': + resolution: + { + integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@typescript-eslint/typescript-estree@8.46.2': + resolution: + { + integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.46.2': + resolution: + { + integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.46.2': + resolution: + { + integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@vitejs/plugin-react@5.1.0': + resolution: + { + integrity: sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@xmldom/xmldom@0.8.11': + resolution: + { + integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==, + } + engines: { node: '>=10.0.0' } + + abbrev@1.1.1: + resolution: + { + integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==, + } + + acorn-jsx@5.3.2: + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: + { + integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==, + } + engines: { node: '>=0.4.0' } + hasBin: true + + agent-base@6.0.2: + resolution: + { + integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==, + } + engines: { node: '>= 6.0.0' } + + agent-base@7.1.4: + resolution: + { + integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==, + } + engines: { node: '>= 14' } + + agentkeepalive@4.6.0: + resolution: + { + integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==, + } + engines: { node: '>= 8.0.0' } + + aggregate-error@3.1.0: + resolution: + { + integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==, + } + engines: { node: '>=8' } + + ajv-keywords@3.5.2: + resolution: + { + integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==, + } + peerDependencies: + ajv: ^6.9.1 + + ajv@6.12.6: + resolution: + { + integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, + } + + ansi-escapes@7.1.1: + resolution: + { + integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==, + } + engines: { node: '>=18' } + + ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: '>=8' } + + ansi-regex@6.2.2: + resolution: + { + integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==, + } + engines: { node: '>=12' } + + ansi-styles@3.2.1: + resolution: + { + integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, + } + engines: { node: '>=4' } + + ansi-styles@4.3.0: + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: '>=8' } + + ansi-styles@6.2.3: + resolution: + { + integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==, + } + engines: { node: '>=12' } + + app-builder-bin@5.0.0-alpha.12: + resolution: + { + integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==, + } + + app-builder-lib@26.0.12: + resolution: + { + integrity: sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==, + } + engines: { node: '>=14.0.0' } + peerDependencies: + dmg-builder: 26.0.12 + electron-builder-squirrel-windows: 26.0.12 + + argparse@2.0.1: + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + + array-buffer-byte-length@1.0.2: + resolution: + { + integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==, + } + engines: { node: '>= 0.4' } + + array-includes@3.1.9: + resolution: + { + integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==, + } + engines: { node: '>= 0.4' } + + array.prototype.findlast@1.2.5: + resolution: + { + integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==, + } + engines: { node: '>= 0.4' } + + array.prototype.flat@1.3.3: + resolution: + { + integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==, + } + engines: { node: '>= 0.4' } + + array.prototype.flatmap@1.3.3: + resolution: + { + integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==, + } + engines: { node: '>= 0.4' } + + array.prototype.tosorted@1.1.4: + resolution: + { + integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==, + } + engines: { node: '>= 0.4' } + + arraybuffer.prototype.slice@1.0.4: + resolution: + { + integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==, + } + engines: { node: '>= 0.4' } + + assert-plus@1.0.0: + resolution: + { + integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==, + } + engines: { node: '>=0.8' } + + astral-regex@2.0.0: + resolution: + { + integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==, + } + engines: { node: '>=8' } + + async-exit-hook@2.0.1: + resolution: + { + integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==, + } + engines: { node: '>=0.12.0' } + + async-function@1.0.0: + resolution: + { + integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==, + } + engines: { node: '>= 0.4' } + + async@3.2.6: + resolution: + { + integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==, + } + + asynckit@0.4.0: + resolution: + { + integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, + } + + at-least-node@1.0.0: + resolution: + { + integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==, + } + engines: { node: '>= 4.0.0' } + + autoprefixer@10.4.21: + resolution: + { + integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==, + } + engines: { node: ^10 || ^12 || >=14 } + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: + { + integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, + } + engines: { node: '>= 0.4' } + + axios@1.13.1: + resolution: + { + integrity: sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==, + } + + balanced-match@1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } + + base64-js@1.5.1: + resolution: + { + integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, + } + + baseline-browser-mapping@2.8.23: + resolution: + { + integrity: sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ==, + } + hasBin: true + + bl@4.1.0: + resolution: + { + integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, + } + + boolean@3.2.0: + resolution: + { + integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==, + } + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + brace-expansion@1.1.12: + resolution: + { + integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==, + } + + brace-expansion@2.0.2: + resolution: + { + integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==, + } + + braces@3.0.3: + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: '>=8' } + + browserslist@4.27.0: + resolution: + { + integrity: sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + hasBin: true + + buffer-crc32@0.2.13: + resolution: + { + integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==, + } + + buffer-from@1.1.2: + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, + } + + buffer@5.7.1: + resolution: + { + integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, + } + + builder-util-runtime@9.3.1: + resolution: + { + integrity: sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==, + } + engines: { node: '>=12.0.0' } + + builder-util@26.0.11: + resolution: + { + integrity: sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==, + } + + cacache@16.1.3: + resolution: + { + integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + cacheable-lookup@5.0.4: + resolution: + { + integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==, + } + engines: { node: '>=10.6.0' } + + cacheable-request@7.0.4: + resolution: + { + integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==, + } + engines: { node: '>=8' } + + call-bind-apply-helpers@1.0.2: + resolution: + { + integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==, + } + engines: { node: '>= 0.4' } + + call-bind@1.0.8: + resolution: + { + integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==, + } + engines: { node: '>= 0.4' } + + call-bound@1.0.4: + resolution: + { + integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==, + } + engines: { node: '>= 0.4' } + + callsites@3.1.0: + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: '>=6' } + + camelcase@6.3.0: + resolution: + { + integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==, + } + engines: { node: '>=10' } + + caniuse-lite@1.0.30001753: + resolution: + { + integrity: sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw==, + } + + chalk@2.4.2: + resolution: + { + integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, + } + engines: { node: '>=4' } + + chalk@4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: '>=10' } + + chownr@2.0.0: + resolution: + { + integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==, + } + engines: { node: '>=10' } + + chromium-pickle-js@0.2.0: + resolution: + { + integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==, + } + + ci-info@3.9.0: + resolution: + { + integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==, + } + engines: { node: '>=8' } + + class-variance-authority@0.7.1: + resolution: + { + integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==, + } + + clean-stack@2.2.0: + resolution: + { + integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==, + } + engines: { node: '>=6' } + + cli-cursor@3.1.0: + resolution: + { + integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==, + } + engines: { node: '>=8' } + + cli-cursor@5.0.0: + resolution: + { + integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==, + } + engines: { node: '>=18' } + + cli-spinners@2.9.2: + resolution: + { + integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==, + } + engines: { node: '>=6' } + + cli-truncate@2.1.0: + resolution: + { + integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==, + } + engines: { node: '>=8' } + + cli-truncate@5.1.1: + resolution: + { + integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==, + } + engines: { node: '>=20' } + + cliui@8.0.1: + resolution: + { + integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==, + } + engines: { node: '>=12' } + + clone-response@1.0.3: + resolution: + { + integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==, + } + + clone@1.0.4: + resolution: + { + integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==, + } + engines: { node: '>=0.8' } + + clsx@2.1.1: + resolution: + { + integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, + } + engines: { node: '>=6' } + + coa@2.0.2: + resolution: + { + integrity: sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==, + } + engines: { node: '>= 4.0' } + + code-block-writer@11.0.3: + resolution: + { + integrity: sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==, + } + + color-convert@1.9.3: + resolution: + { + integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, + } + + color-convert@2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: '>=7.0.0' } + + color-name@1.1.3: + resolution: + { + integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, + } + + color-name@1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + + colorette@2.0.20: + resolution: + { + integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, + } + + combined-stream@1.0.8: + resolution: + { + integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, + } + engines: { node: '>= 0.8' } + + commander@14.0.2: + resolution: + { + integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==, + } + engines: { node: '>=20' } + + commander@5.1.0: + resolution: + { + integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==, + } + engines: { node: '>= 6' } + + commander@9.5.0: + resolution: + { + integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==, + } + engines: { node: ^12.20.0 || >=14 } + + compare-version@0.1.2: + resolution: + { + integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==, + } + engines: { node: '>=0.10.0' } + + concat-map@0.0.1: + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } + + config-file-ts@0.2.8-rc1: + resolution: + { + integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==, + } + + convert-source-map@2.0.0: + resolution: + { + integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, + } + + cookie@1.0.2: + resolution: + { + integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==, + } + engines: { node: '>=18' } + + core-util-is@1.0.2: + resolution: + { + integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==, + } + + core-util-is@1.0.3: + resolution: + { + integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, + } + + cosmiconfig@8.3.6: + resolution: + { + integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==, + } + engines: { node: '>=14' } + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + crc@3.8.0: + resolution: + { + integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==, + } + + cross-dirname@0.1.0: + resolution: + { + integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==, + } + + cross-env@10.1.0: + resolution: + { + integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==, + } + engines: { node: '>=20' } + hasBin: true + + cross-spawn@7.0.6: + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: '>= 8' } + + csstype@3.1.3: + resolution: + { + integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, + } + + d3-array@3.2.4: + resolution: + { + integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==, + } + engines: { node: '>=12' } + + d3-color@3.1.0: + resolution: + { + integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==, + } + engines: { node: '>=12' } + + d3-ease@3.0.1: + resolution: + { + integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==, + } + engines: { node: '>=12' } + + d3-format@3.1.0: + resolution: + { + integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==, + } + engines: { node: '>=12' } + + d3-interpolate@3.0.1: + resolution: + { + integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==, + } + engines: { node: '>=12' } + + d3-path@3.1.0: + resolution: + { + integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==, + } + engines: { node: '>=12' } + + d3-scale@4.0.2: + resolution: + { + integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==, + } + engines: { node: '>=12' } + + d3-shape@3.2.0: + resolution: + { + integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==, + } + engines: { node: '>=12' } + + d3-time-format@4.1.0: + resolution: + { + integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==, + } + engines: { node: '>=12' } + + d3-time@3.1.0: + resolution: + { + integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==, + } + engines: { node: '>=12' } + + d3-timer@3.0.1: + resolution: + { + integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==, + } + engines: { node: '>=12' } + + data-view-buffer@1.0.2: + resolution: + { + integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==, + } + engines: { node: '>= 0.4' } + + data-view-byte-length@1.0.2: + resolution: + { + integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==, + } + engines: { node: '>= 0.4' } + + data-view-byte-offset@1.0.1: + resolution: + { + integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==, + } + engines: { node: '>= 0.4' } + + debug@4.4.3: + resolution: + { + integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, + } + engines: { node: '>=6.0' } + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js-light@2.5.1: + resolution: + { + integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==, + } + + decompress-response@6.0.0: + resolution: + { + integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==, + } + engines: { node: '>=10' } + + deep-is@0.1.4: + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + + defaults@1.0.4: + resolution: + { + integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==, + } + + defer-to-connect@2.0.1: + resolution: + { + integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==, + } + engines: { node: '>=10' } + + define-data-property@1.1.4: + resolution: + { + integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, + } + engines: { node: '>= 0.4' } + + define-properties@1.2.1: + resolution: + { + integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, + } + engines: { node: '>= 0.4' } + + delayed-stream@1.0.0: + resolution: + { + integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, + } + engines: { node: '>=0.4.0' } + + detect-libc@2.1.2: + resolution: + { + integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==, + } + engines: { node: '>=8' } + + detect-node@2.1.0: + resolution: + { + integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==, + } + + dir-compare@4.2.0: + resolution: + { + integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==, + } + + dmg-builder@26.0.12: + resolution: + { + integrity: sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==, + } + + dmg-license@1.0.11: + resolution: + { + integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==, + } + engines: { node: '>=8' } + os: [darwin] + hasBin: true + + doctrine@2.1.0: + resolution: + { + integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==, + } + engines: { node: '>=0.10.0' } + + dot-case@3.0.4: + resolution: + { + integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==, + } + + dotenv-expand@11.0.7: + resolution: + { + integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==, + } + engines: { node: '>=12' } + + dotenv@16.6.1: + resolution: + { + integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==, + } + engines: { node: '>=12' } + + dotenv@17.2.3: + resolution: + { + integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==, + } + engines: { node: '>=12' } + + dts-for-context-bridge@0.7.1: + resolution: + { + integrity: sha512-Tm5kJlCtOmNcbc0N/bvGREhrhjFoACJqDUTxW+X2JL114+8CGiAWn80lDE/3S6P1OcrfuI8+Bzd3/iNCxx2ciA==, + } + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + hasBin: true + + dunder-proto@1.0.1: + resolution: + { + integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==, + } + engines: { node: '>= 0.4' } + + eastasianwidth@0.2.0: + resolution: + { + integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, + } + + ejs@3.1.10: + resolution: + { + integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==, + } + engines: { node: '>=0.10.0' } + hasBin: true + + electron-builder-squirrel-windows@26.0.12: + resolution: + { + integrity: sha512-kpwXM7c/ayRUbYVErQbsZ0nQZX4aLHQrPEG9C4h9vuJCXylwFH8a7Jgi2VpKIObzCXO7LKHiCw4KdioFLFOgqA==, + } + + electron-builder@26.0.12: + resolution: + { + integrity: sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==, + } + engines: { node: '>=14.0.0' } + hasBin: true + + electron-devtools-installer@4.0.0: + resolution: + { + integrity: sha512-9Tntu/jtfSn0n6N/ZI6IdvRqXpDyLQiDuuIbsBI+dL+1Ef7C8J2JwByw58P3TJiNeuqyV3ZkphpNWuZK5iSY2w==, + } + + electron-publish@26.0.11: + resolution: + { + integrity: sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==, + } + + electron-to-chromium@1.5.244: + resolution: + { + integrity: sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==, + } + + electron-updater@6.6.2: + resolution: + { + integrity: sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw==, + } + + electron-winstaller@5.4.0: + resolution: + { + integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==, + } + engines: { node: '>=8.0.0' } + + electron@39.0.0: + resolution: + { + integrity: sha512-UejnuOK4jpRZUq7MkEAnR/szsRWLKBJAdvn6j3xdQLT57fVv13VSNdaUHHjSheaqGzNhCGIdkPsPJnGJVh5kiA==, + } + engines: { node: '>= 12.20.55' } + hasBin: true + + emoji-regex@10.6.0: + resolution: + { + integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==, + } + + emoji-regex@8.0.0: + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } + + emoji-regex@9.2.2: + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, + } + + encoding@0.1.13: + resolution: + { + integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==, + } + + end-of-stream@1.4.5: + resolution: + { + integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==, + } + + enhanced-resolve@5.18.3: + resolution: + { + integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==, + } + engines: { node: '>=10.13.0' } + + entities@4.5.0: + resolution: + { + integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==, + } + engines: { node: '>=0.12' } + + env-paths@2.2.1: + resolution: + { + integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, + } + engines: { node: '>=6' } + + environment@1.1.0: + resolution: + { + integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==, + } + engines: { node: '>=18' } + + err-code@2.0.3: + resolution: + { + integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==, + } + + error-ex@1.3.4: + resolution: + { + integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==, + } + + es-abstract@1.24.0: + resolution: + { + integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==, + } + engines: { node: '>= 0.4' } + + es-define-property@1.0.1: + resolution: + { + integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, + } + engines: { node: '>= 0.4' } + + es-errors@1.3.0: + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: '>= 0.4' } + + es-iterator-helpers@1.2.1: + resolution: + { + integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==, + } + engines: { node: '>= 0.4' } + + es-object-atoms@1.1.1: + resolution: + { + integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==, + } + engines: { node: '>= 0.4' } + + es-set-tostringtag@2.1.0: + resolution: + { + integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==, + } + engines: { node: '>= 0.4' } + + es-shim-unscopables@1.1.0: + resolution: + { + integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==, + } + engines: { node: '>= 0.4' } + + es-to-primitive@1.3.0: + resolution: + { + integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==, + } + engines: { node: '>= 0.4' } + + es-toolkit@1.41.0: + resolution: + { + integrity: sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==, + } + + es6-error@4.1.1: + resolution: + { + integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==, + } + + esbuild@0.25.12: + resolution: + { + integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==, + } + engines: { node: '>=18' } + hasBin: true + + escalade@3.2.0: + resolution: + { + integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, + } + engines: { node: '>=6' } + + escape-string-regexp@1.0.5: + resolution: + { + integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, + } + engines: { node: '>=0.8.0' } + + escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: '>=10' } + + eslint-config-prettier@10.1.8: + resolution: + { + integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==, + } + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-prettier@5.5.4: + resolution: + { + integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-react-hooks@7.0.1: + resolution: + { + integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==, + } + 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 + + eslint-plugin-react-refresh@0.4.24: + resolution: + { + integrity: sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==, + } + peerDependencies: + eslint: '>=8.40' + + eslint-plugin-react@7.37.5: + resolution: + { + integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==, + } + engines: { node: '>=4' } + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: + { + integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + eslint-visitor-keys@3.4.3: + resolution: + { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + eslint-visitor-keys@4.2.1: + resolution: + { + integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + eslint@9.39.0: + resolution: + { + integrity: sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: + { + integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + esquery@1.6.0: + resolution: + { + integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==, + } + engines: { node: '>=0.10' } + + esrecurse@4.3.0: + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: '>=4.0' } + + estraverse@5.3.0: + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: '>=4.0' } + + estree-walker@2.0.2: + resolution: + { + integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==, + } + + esutils@2.0.3: + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: '>=0.10.0' } + + eventemitter3@5.0.1: + resolution: + { + integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==, + } + + exponential-backoff@3.1.3: + resolution: + { + integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==, + } + + extract-zip@2.0.1: + resolution: + { + integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==, + } + engines: { node: '>= 10.17.0' } + hasBin: true + + extsprintf@1.4.1: + resolution: + { + integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==, + } + engines: { '0': node >=0.6.0 } + + fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + + fast-diff@1.3.0: + resolution: + { + integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==, + } + + fast-glob@3.3.3: + resolution: + { + integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==, + } + engines: { node: '>=8.6.0' } + + fast-json-stable-stringify@2.1.0: + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } + + fast-levenshtein@2.0.6: + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + + fastq@1.19.1: + resolution: + { + integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==, + } + + fd-slicer@1.1.0: + resolution: + { + integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==, + } + + fdir@6.5.0: + resolution: + { + integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, + } + engines: { node: '>=12.0.0' } + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: + { + integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, + } + engines: { node: '>=16.0.0' } + + filelist@1.0.4: + resolution: + { + integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==, + } + + fill-range@7.1.1: + resolution: + { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: '>=8' } + + find-up@5.0.0: + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: '>=10' } + + flat-cache@4.0.1: + resolution: + { + integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, + } + engines: { node: '>=16' } + + flatted@3.3.3: + resolution: + { + integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==, + } + + follow-redirects@1.15.11: + resolution: + { + integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==, + } + engines: { node: '>=4.0' } + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: + { + integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==, + } + engines: { node: '>= 0.4' } + + foreground-child@3.3.1: + resolution: + { + integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==, + } + engines: { node: '>=14' } + + form-data@4.0.4: + resolution: + { + integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==, + } + engines: { node: '>= 6' } + + fraction.js@4.3.7: + resolution: + { + integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==, + } + + framer-motion@12.23.24: + resolution: + { + integrity: sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==, + } + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + fs-extra@10.1.0: + resolution: + { + integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==, + } + engines: { node: '>=12' } + + fs-extra@11.3.2: + resolution: + { + integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==, + } + engines: { node: '>=14.14' } + + fs-extra@7.0.1: + resolution: + { + integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==, + } + engines: { node: '>=6 <7 || >=8' } + + fs-extra@8.1.0: + resolution: + { + integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==, + } + engines: { node: '>=6 <7 || >=8' } + + fs-extra@9.1.0: + resolution: + { + integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==, + } + engines: { node: '>=10' } + + fs-minipass@2.1.0: + resolution: + { + integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==, + } + engines: { node: '>= 8' } + + fs.realpath@1.0.0: + resolution: + { + integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, + } + + fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + + function-bind@1.1.2: + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } + + function.prototype.name@1.1.8: + resolution: + { + integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==, + } + engines: { node: '>= 0.4' } + + functions-have-names@1.2.3: + resolution: + { + integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, + } + + generator-function@2.0.1: + resolution: + { + integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==, + } + engines: { node: '>= 0.4' } + + gensync@1.0.0-beta.2: + resolution: + { + integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, + } + engines: { node: '>=6.9.0' } + + get-caller-file@2.0.5: + resolution: + { + integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==, + } + engines: { node: 6.* || 8.* || >= 10.* } + + get-east-asian-width@1.4.0: + resolution: + { + integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==, + } + engines: { node: '>=18' } + + get-intrinsic@1.3.0: + resolution: + { + integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==, + } + engines: { node: '>= 0.4' } + + get-proto@1.0.1: + resolution: + { + integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==, + } + engines: { node: '>= 0.4' } + + get-stream@5.2.0: + resolution: + { + integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==, + } + engines: { node: '>=8' } + + get-symbol-description@1.1.0: + resolution: + { + integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==, + } + engines: { node: '>= 0.4' } + + glob-parent@5.1.2: + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: '>= 6' } + + glob-parent@6.0.2: + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: '>=10.13.0' } + + glob@10.4.5: + resolution: + { + integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==, + } + hasBin: true + + glob@7.2.3: + resolution: + { + integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, + } + deprecated: Glob versions prior to v9 are no longer supported + + glob@8.1.0: + resolution: + { + integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==, + } + engines: { node: '>=12' } + deprecated: Glob versions prior to v9 are no longer supported + + global-agent@3.0.0: + resolution: + { + integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==, + } + engines: { node: '>=10.0' } + + globals@14.0.0: + resolution: + { + integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, + } + engines: { node: '>=18' } + + globals@16.5.0: + resolution: + { + integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==, + } + engines: { node: '>=18' } + + globalthis@1.0.4: + resolution: + { + integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==, + } + engines: { node: '>= 0.4' } + + gopd@1.2.0: + resolution: + { + integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==, + } + engines: { node: '>= 0.4' } + + got@11.8.6: + resolution: + { + integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==, + } + engines: { node: '>=10.19.0' } + + graceful-fs@4.2.11: + resolution: + { + integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, + } + + graphemer@1.4.0: + resolution: + { + integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, + } + + has-bigints@1.1.0: + resolution: + { + integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==, + } + engines: { node: '>= 0.4' } + + has-flag@3.0.0: + resolution: + { + integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, + } + engines: { node: '>=4' } + + has-flag@4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: '>=8' } + + has-property-descriptors@1.0.2: + resolution: + { + integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, + } + + has-proto@1.2.0: + resolution: + { + integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==, + } + engines: { node: '>= 0.4' } + + has-symbols@1.1.0: + resolution: + { + integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==, + } + engines: { node: '>= 0.4' } + + has-tostringtag@1.0.2: + resolution: + { + integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, + } + engines: { node: '>= 0.4' } + + hasown@2.0.2: + resolution: + { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: '>= 0.4' } + + hermes-estree@0.25.1: + resolution: + { + integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==, + } + + hermes-parser@0.25.1: + resolution: + { + integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==, + } + + hosted-git-info@4.1.0: + resolution: + { + integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==, + } + engines: { node: '>=10' } + + http-cache-semantics@4.2.0: + resolution: + { + integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==, + } + + http-proxy-agent@5.0.0: + resolution: + { + integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==, + } + engines: { node: '>= 6' } + + http-proxy-agent@7.0.2: + resolution: + { + integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==, + } + engines: { node: '>= 14' } + + http2-wrapper@1.0.3: + resolution: + { + integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==, + } + engines: { node: '>=10.19.0' } + + https-proxy-agent@5.0.1: + resolution: + { + integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==, + } + engines: { node: '>= 6' } + + https-proxy-agent@7.0.6: + resolution: + { + integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==, + } + engines: { node: '>= 14' } + + humanize-ms@1.2.1: + resolution: + { + integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==, + } + + husky@9.1.7: + resolution: + { + integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==, + } + engines: { node: '>=18' } + hasBin: true + + iconv-corefoundation@1.1.7: + resolution: + { + integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==, + } + engines: { node: ^8.11.2 || >=10 } + os: [darwin] + + iconv-lite@0.6.3: + resolution: + { + integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==, + } + engines: { node: '>=0.10.0' } + + ieee754@1.2.1: + resolution: + { + integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, + } + + ignore@5.3.2: + resolution: + { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: '>= 4' } + + ignore@7.0.5: + resolution: + { + integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==, + } + engines: { node: '>= 4' } + + immediate@3.0.6: + resolution: + { + integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, + } + + immer@10.2.0: + resolution: + { + integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==, + } + + import-fresh@3.3.1: + resolution: + { + integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==, + } + engines: { node: '>=6' } + + imurmurhash@0.1.4: + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: '>=0.8.19' } + + indent-string@4.0.0: + resolution: + { + integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, + } + engines: { node: '>=8' } + + infer-owner@1.0.4: + resolution: + { + integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==, + } + + inflight@1.0.6: + resolution: + { + integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, + } + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: + { + integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, + } + + internal-slot@1.1.0: + resolution: + { + integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==, + } + engines: { node: '>= 0.4' } + + internmap@2.0.3: + resolution: + { + integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==, + } + engines: { node: '>=12' } + + ip-address@10.0.1: + resolution: + { + integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==, + } + engines: { node: '>= 12' } + + is-array-buffer@3.0.5: + resolution: + { + integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==, + } + engines: { node: '>= 0.4' } + + is-arrayish@0.2.1: + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } + + is-async-function@2.1.1: + resolution: + { + integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==, + } + engines: { node: '>= 0.4' } + + is-bigint@1.1.0: + resolution: + { + integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==, + } + engines: { node: '>= 0.4' } + + is-boolean-object@1.2.2: + resolution: + { + integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==, + } + engines: { node: '>= 0.4' } + + is-callable@1.2.7: + resolution: + { + integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, + } + engines: { node: '>= 0.4' } + + is-ci@3.0.1: + resolution: + { + integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==, + } + hasBin: true + + is-core-module@2.16.1: + resolution: + { + integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==, + } + engines: { node: '>= 0.4' } + + is-data-view@1.0.2: + resolution: + { + integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==, + } + engines: { node: '>= 0.4' } + + is-date-object@1.1.0: + resolution: + { + integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==, + } + engines: { node: '>= 0.4' } + + is-extglob@2.1.1: + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: '>=0.10.0' } + + is-finalizationregistry@1.1.1: + resolution: + { + integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==, + } + engines: { node: '>= 0.4' } + + is-fullwidth-code-point@3.0.0: + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: '>=8' } + + is-fullwidth-code-point@5.1.0: + resolution: + { + integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==, + } + engines: { node: '>=18' } + + is-generator-function@1.1.2: + resolution: + { + integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==, + } + engines: { node: '>= 0.4' } + + is-glob@4.0.3: + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: '>=0.10.0' } + + is-interactive@1.0.0: + resolution: + { + integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==, + } + engines: { node: '>=8' } + + is-lambda@1.0.1: + resolution: + { + integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==, + } + + is-map@2.0.3: + resolution: + { + integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, + } + engines: { node: '>= 0.4' } + + is-negative-zero@2.0.3: + resolution: + { + integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==, + } + engines: { node: '>= 0.4' } + + is-number-object@1.1.1: + resolution: + { + integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==, + } + engines: { node: '>= 0.4' } + + is-number@7.0.0: + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: '>=0.12.0' } + + is-regex@1.2.1: + resolution: + { + integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==, + } + engines: { node: '>= 0.4' } + + is-set@2.0.3: + resolution: + { + integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, + } + engines: { node: '>= 0.4' } + + is-shared-array-buffer@1.0.4: + resolution: + { + integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==, + } + engines: { node: '>= 0.4' } + + is-string@1.1.1: + resolution: + { + integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==, + } + engines: { node: '>= 0.4' } + + is-symbol@1.1.1: + resolution: + { + integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==, + } + engines: { node: '>= 0.4' } + + is-typed-array@1.1.15: + resolution: + { + integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==, + } + engines: { node: '>= 0.4' } + + is-unicode-supported@0.1.0: + resolution: + { + integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==, + } + engines: { node: '>=10' } + + is-weakmap@2.0.2: + resolution: + { + integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, + } + engines: { node: '>= 0.4' } + + is-weakref@1.1.1: + resolution: + { + integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==, + } + engines: { node: '>= 0.4' } + + is-weakset@2.0.4: + resolution: + { + integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==, + } + engines: { node: '>= 0.4' } + + isarray@1.0.0: + resolution: + { + integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, + } + + isarray@2.0.5: + resolution: + { + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + } + + isbinaryfile@4.0.10: + resolution: + { + integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==, + } + engines: { node: '>= 8.0.0' } + + isbinaryfile@5.0.6: + resolution: + { + integrity: sha512-I+NmIfBHUl+r2wcDd6JwE9yWje/PIVY/R5/CmV8dXLZd5K+L9X2klAOwfAHNnondLXkbHyTAleQAWonpTJBTtw==, + } + engines: { node: '>= 18.0.0' } + + isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + iterator.prototype@1.1.5: + resolution: + { + integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==, + } + engines: { node: '>= 0.4' } + + jackspeak@3.4.3: + resolution: + { + integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, + } + + jake@10.9.4: + resolution: + { + integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==, + } + engines: { node: '>=10' } + hasBin: true + + jiti@2.6.1: + resolution: + { + integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==, + } + hasBin: true + + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + + js-yaml@4.1.0: + resolution: + { + integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, + } + hasBin: true + + jsesc@3.1.0: + resolution: + { + integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, + } + engines: { node: '>=6' } + hasBin: true + + json-buffer@3.0.1: + resolution: + { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } + + json-parse-even-better-errors@2.3.1: + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } + + json-schema-traverse@0.4.1: + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } + + json-stable-stringify-without-jsonify@1.0.1: + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } + + json-stringify-safe@5.0.1: + resolution: + { + integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==, + } + + json5@2.2.3: + resolution: + { + integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, + } + engines: { node: '>=6' } + hasBin: true + + jsonfile@4.0.0: + resolution: + { + integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==, + } + + jsonfile@6.2.0: + resolution: + { + integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==, + } + + jsx-ast-utils@3.3.5: + resolution: + { + integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==, + } + engines: { node: '>=4.0' } + + jszip@3.10.1: + resolution: + { + integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==, + } + + keyv@4.5.4: + resolution: + { + integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, + } + + lazy-val@1.0.5: + resolution: + { + integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==, + } + + levn@0.4.1: + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: '>= 0.8.0' } + + lie@3.3.0: + resolution: + { + integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==, + } + + lightningcss-android-arm64@1.30.2: + resolution: + { + integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==, + } + engines: { node: '>= 12.0.0' } + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: + { + integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==, + } + engines: { node: '>= 12.0.0' } + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: + { + integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==, + } + engines: { node: '>= 12.0.0' } + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: + { + integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==, + } + engines: { node: '>= 12.0.0' } + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: + { + integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==, + } + engines: { node: '>= 12.0.0' } + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: + { + integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==, + } + engines: { node: '>= 12.0.0' } + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: + { + integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==, + } + engines: { node: '>= 12.0.0' } + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: + { + integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==, + } + engines: { node: '>= 12.0.0' } + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: + { + integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==, + } + engines: { node: '>= 12.0.0' } + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: + { + integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==, + } + engines: { node: '>= 12.0.0' } + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: + { + integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==, + } + engines: { node: '>= 12.0.0' } + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: + { + integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==, + } + engines: { node: '>= 12.0.0' } + + lines-and-columns@1.2.4: + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } + + lint-staged@16.2.6: + resolution: + { + integrity: sha512-s1gphtDbV4bmW1eylXpVMk2u7is7YsrLl8hzrtvC70h4ByhcMLZFY01Fx05ZUDNuv1H8HO4E+e2zgejV1jVwNw==, + } + engines: { node: '>=20.17' } + hasBin: true + + listr2@9.0.5: + resolution: + { + integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==, + } + engines: { node: '>=20.0.0' } + + locate-path@6.0.0: + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: '>=10' } + + lodash.escaperegexp@4.1.2: + resolution: + { + integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==, + } + + lodash.isequal@4.5.0: + resolution: + { + integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==, + } + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash.merge@4.6.2: + resolution: + { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } + + lodash@4.17.21: + resolution: + { + integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, + } + + log-symbols@4.1.0: + resolution: + { + integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==, + } + engines: { node: '>=10' } + + log-update@6.1.0: + resolution: + { + integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==, + } + engines: { node: '>=18' } + + loose-envify@1.4.0: + resolution: + { + integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, + } + hasBin: true + + lower-case@2.0.2: + resolution: + { + integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==, + } + + lowercase-keys@2.0.0: + resolution: + { + integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==, + } + engines: { node: '>=8' } + + lru-cache@10.4.3: + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } + + lru-cache@5.1.1: + resolution: + { + integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, + } + + lru-cache@6.0.0: + resolution: + { + integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, + } + engines: { node: '>=10' } + + lru-cache@7.18.3: + resolution: + { + integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==, + } + engines: { node: '>=12' } + + magic-string@0.30.21: + resolution: + { + integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==, + } + + make-fetch-happen@10.2.1: + resolution: + { + integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + matcher@3.0.0: + resolution: + { + integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==, + } + engines: { node: '>=10' } + + math-intrinsics@1.1.0: + resolution: + { + integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, + } + engines: { node: '>= 0.4' } + + merge2@1.4.1: + resolution: + { + integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, + } + engines: { node: '>= 8' } + + micromatch@4.0.8: + resolution: + { + integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==, + } + engines: { node: '>=8.6' } + + mime-db@1.52.0: + resolution: + { + integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, + } + engines: { node: '>= 0.6' } + + mime-types@2.1.35: + resolution: + { + integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, + } + engines: { node: '>= 0.6' } + + mime@2.6.0: + resolution: + { + integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==, + } + engines: { node: '>=4.0.0' } + hasBin: true + + mimic-fn@2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + } + engines: { node: '>=6' } + + mimic-function@5.0.1: + resolution: + { + integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==, + } + engines: { node: '>=18' } + + mimic-response@1.0.1: + resolution: + { + integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==, + } + engines: { node: '>=4' } + + mimic-response@3.1.0: + resolution: + { + integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==, + } + engines: { node: '>=10' } + + minimatch@10.1.1: + resolution: + { + integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==, + } + engines: { node: 20 || >=22 } + + minimatch@3.1.2: + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } + + minimatch@5.1.6: + resolution: + { + integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==, + } + engines: { node: '>=10' } + + minimatch@9.0.5: + resolution: + { + integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, + } + engines: { node: '>=16 || 14 >=14.17' } + + minimist@1.2.8: + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } + + minipass-collect@1.0.2: + resolution: + { + integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==, + } + engines: { node: '>= 8' } + + minipass-fetch@2.1.2: + resolution: + { + integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + minipass-flush@1.0.5: + resolution: + { + integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==, + } + engines: { node: '>= 8' } + + minipass-pipeline@1.2.4: + resolution: + { + integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==, + } + engines: { node: '>=8' } + + minipass-sized@1.0.3: + resolution: + { + integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==, + } + engines: { node: '>=8' } + + minipass@3.3.6: + resolution: + { + integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==, + } + engines: { node: '>=8' } + + minipass@5.0.0: + resolution: + { + integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==, + } + engines: { node: '>=8' } + + minipass@7.1.2: + resolution: + { + integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, + } + engines: { node: '>=16 || 14 >=14.17' } + + minizlib@2.1.2: + resolution: + { + integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==, + } + engines: { node: '>= 8' } + + mkdirp@0.5.6: + resolution: + { + integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==, + } + hasBin: true + + mkdirp@1.0.4: + resolution: + { + integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, + } + engines: { node: '>=10' } + hasBin: true + + motion-dom@12.23.23: + resolution: + { + integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==, + } + + motion-utils@12.23.6: + resolution: + { + integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==, + } + + ms@2.1.3: + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } + + nano-spawn@2.0.0: + resolution: + { + integrity: sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==, + } + engines: { node: '>=20.17' } + + nanoid@3.3.11: + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + + natural-compare@1.4.0: + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } + + negotiator@0.6.4: + resolution: + { + integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==, + } + engines: { node: '>= 0.6' } + + no-case@3.0.4: + resolution: + { + integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==, + } + + node-abi@3.80.0: + resolution: + { + integrity: sha512-LyPuZJcI9HVwzXK1GPxWNzrr+vr8Hp/3UqlmWxxh8p54U1ZbclOqbSog9lWHaCX+dBaiGi6n/hIX+mKu74GmPA==, + } + engines: { node: '>=10' } + + node-addon-api@1.7.2: + resolution: + { + integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==, + } + + node-api-version@0.2.1: + resolution: + { + integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==, + } + + node-releases@2.0.27: + resolution: + { + integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==, + } + + nopt@6.0.0: + resolution: + { + integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + hasBin: true + + normalize-range@0.1.2: + resolution: + { + integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==, + } + engines: { node: '>=0.10.0' } + + normalize-url@6.1.0: + resolution: + { + integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==, + } + engines: { node: '>=10' } + + object-assign@4.1.1: + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: '>=0.10.0' } + + object-inspect@1.13.4: + resolution: + { + integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==, + } + engines: { node: '>= 0.4' } + + object-keys@1.1.1: + resolution: + { + integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, + } + engines: { node: '>= 0.4' } + + object.assign@4.1.7: + resolution: + { + integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==, + } + engines: { node: '>= 0.4' } + + object.entries@1.1.9: + resolution: + { + integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==, + } + engines: { node: '>= 0.4' } + + object.fromentries@2.0.8: + resolution: + { + integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==, + } + engines: { node: '>= 0.4' } + + object.values@1.2.1: + resolution: + { + integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==, + } + engines: { node: '>= 0.4' } + + once@1.4.0: + resolution: + { + integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, + } + + onetime@5.1.2: + resolution: + { + integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, + } + engines: { node: '>=6' } + + onetime@7.0.0: + resolution: + { + integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==, + } + engines: { node: '>=18' } + + optionator@0.9.4: + resolution: + { + integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, + } + engines: { node: '>= 0.8.0' } + + ora@5.4.1: + resolution: + { + integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==, + } + engines: { node: '>=10' } + + own-keys@1.0.1: + resolution: + { + integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==, + } + engines: { node: '>= 0.4' } + + p-cancelable@2.1.1: + resolution: + { + integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==, + } + engines: { node: '>=8' } + + p-limit@3.1.0: + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: '>=10' } + + p-locate@5.0.0: + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: '>=10' } + + p-map@4.0.0: + resolution: + { + integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==, + } + engines: { node: '>=10' } + + package-json-from-dist@1.0.1: + resolution: + { + integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, + } + + pako@1.0.11: + resolution: + { + integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==, + } + + parent-module@1.0.1: + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: '>=6' } + + parse-json@5.2.0: + resolution: + { + integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, + } + engines: { node: '>=8' } + + path-browserify@1.0.1: + resolution: + { + integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==, + } + + path-exists@4.0.0: + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: '>=8' } + + path-is-absolute@1.0.1: + resolution: + { + integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, + } + engines: { node: '>=0.10.0' } + + path-key@3.1.1: + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: '>=8' } + + path-parse@1.0.7: + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } + + path-scurry@1.11.1: + resolution: + { + integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, + } + engines: { node: '>=16 || 14 >=14.18' } + + path-type@4.0.0: + resolution: + { + integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, + } + engines: { node: '>=8' } + + pe-library@0.4.1: + resolution: + { + integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==, + } + engines: { node: '>=12', npm: '>=6' } + + pend@1.2.0: + resolution: + { + integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==, + } + + picocolors@1.1.1: + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } + + picomatch@2.3.1: + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: '>=8.6' } + + picomatch@4.0.3: + resolution: + { + integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==, + } + engines: { node: '>=12' } + + pidtree@0.6.0: + resolution: + { + integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==, + } + engines: { node: '>=0.10' } + hasBin: true + + plist@3.1.0: + resolution: + { + integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==, + } + engines: { node: '>=10.4.0' } + + possible-typed-array-names@1.1.0: + resolution: + { + integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==, + } + engines: { node: '>= 0.4' } + + postcss-value-parser@4.2.0: + resolution: + { + integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, + } + + postcss@8.5.6: + resolution: + { + integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, + } + engines: { node: ^10 || ^12 || >=14 } + + postject@1.0.0-alpha.6: + resolution: + { + integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==, + } + engines: { node: '>=14.0.0' } + hasBin: true + + prelude-ls@1.2.1: + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: '>= 0.8.0' } + + prettier-linter-helpers@1.0.0: + resolution: + { + integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==, + } + engines: { node: '>=6.0.0' } + + prettier-plugin-tailwindcss@0.7.1: + resolution: + { + integrity: sha512-Bzv1LZcuiR1Sk02iJTS1QzlFNp/o5l2p3xkopwOrbPmtMeh3fK9rVW5M3neBQzHq+kGKj/4LGQMTNcTH4NGPtQ==, + } + engines: { node: '>=20.19' } + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-hermes': '*' + '@prettier/plugin-oxc': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-hermes': + optional: true + '@prettier/plugin-oxc': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-svelte: + optional: true + + prettier@3.6.2: + resolution: + { + integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==, + } + engines: { node: '>=14' } + hasBin: true + + proc-log@2.0.1: + resolution: + { + integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + process-nextick-args@2.0.1: + resolution: + { + integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, + } + + progress@2.0.3: + resolution: + { + integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==, + } + engines: { node: '>=0.4.0' } + + promise-inflight@1.0.1: + resolution: + { + integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==, + } + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + promise-retry@2.0.1: + resolution: + { + integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==, + } + engines: { node: '>=10' } + + prop-types@15.8.1: + resolution: + { + integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, + } + + proxy-from-env@1.1.0: + resolution: + { + integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, + } + + pump@3.0.3: + resolution: + { + integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==, + } + + punycode@2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: '>=6' } + + q@1.5.1: + resolution: + { + integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==, + } + engines: { node: '>=0.6.0', teleport: '>=0.2.0' } + deprecated: |- + You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) + + queue-microtask@1.2.3: + resolution: + { + integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, + } + + quick-lru@5.1.1: + resolution: + { + integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==, + } + engines: { node: '>=10' } + + react-dom@19.2.0: + resolution: + { + integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==, + } + peerDependencies: + react: ^19.2.0 + + react-hook-form@7.66.0: + resolution: + { + integrity: sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==, + } + engines: { node: '>=18.0.0' } + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: + { + integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, + } + + react-redux@9.2.0: + resolution: + { + integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==, + } + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + + react-refresh@0.18.0: + resolution: + { + integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==, + } + engines: { node: '>=0.10.0' } + + react-router-dom@7.9.5: + resolution: + { + integrity: sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==, + } + engines: { node: '>=20.0.0' } + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.9.5: + resolution: + { + integrity: sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==, + } + engines: { node: '>=20.0.0' } + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react-webcam@7.2.0: + resolution: + { + integrity: sha512-xkrzYPqa1ag2DP+2Q/kLKBmCIfEx49bVdgCCCcZf88oF+0NPEbkwYk3/s/C7Zy0mhM8k+hpdNkBLzxg8H0aWcg==, + } + peerDependencies: + react: '>=16.2.0' + react-dom: '>=16.2.0' + + react@19.2.0: + resolution: + { + integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==, + } + engines: { node: '>=0.10.0' } + + read-binary-file-arch@1.0.6: + resolution: + { + integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==, + } + hasBin: true + + readable-stream@2.3.8: + resolution: + { + integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, + } + + readable-stream@3.6.2: + resolution: + { + integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, + } + engines: { node: '>= 6' } + + recharts@3.3.0: + resolution: + { + integrity: sha512-Vi0qmTB0iz1+/Cz9o5B7irVyUjX2ynvEgImbgMt/3sKRREcUM07QiYjS1QpAVrkmVlXqy5gykq4nGWMz9AS4Rg==, + } + engines: { node: '>=18' } + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + redux-thunk@3.1.0: + resolution: + { + integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==, + } + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: + { + integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==, + } + + reflect.getprototypeof@1.0.10: + resolution: + { + integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==, + } + engines: { node: '>= 0.4' } + + regexp.prototype.flags@1.5.4: + resolution: + { + integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==, + } + engines: { node: '>= 0.4' } + + require-directory@2.1.1: + resolution: + { + integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==, + } + engines: { node: '>=0.10.0' } + + resedit@1.7.2: + resolution: + { + integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==, + } + engines: { node: '>=12', npm: '>=6' } + + reselect@5.1.1: + resolution: + { + integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==, + } + + resolve-alpn@1.2.1: + resolution: + { + integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==, + } + + resolve-from@4.0.0: + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: '>=4' } + + resolve@2.0.0-next.5: + resolution: + { + integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==, + } + hasBin: true + + responselike@2.0.1: + resolution: + { + integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==, + } + + restore-cursor@3.1.0: + resolution: + { + integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==, + } + engines: { node: '>=8' } + + restore-cursor@5.1.0: + resolution: + { + integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==, + } + engines: { node: '>=18' } + + retry@0.12.0: + resolution: + { + integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==, + } + engines: { node: '>= 4' } + + reusify@1.1.0: + resolution: + { + integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, + } + engines: { iojs: '>=1.0.0', node: '>=0.10.0' } + + rfdc@1.4.1: + resolution: + { + integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==, + } + + rimraf@2.6.3: + resolution: + { + integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==, + } + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@3.0.2: + resolution: + { + integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, + } + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + roarr@2.15.4: + resolution: + { + integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==, + } + engines: { node: '>=8.0' } + + rollup@4.52.5: + resolution: + { + integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==, + } + engines: { node: '>=18.0.0', npm: '>=8.0.0' } + hasBin: true + + run-parallel@1.2.0: + resolution: + { + integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, + } + + safe-array-concat@1.1.3: + resolution: + { + integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==, + } + engines: { node: '>=0.4' } + + safe-buffer@5.1.2: + resolution: + { + integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, + } + + safe-buffer@5.2.1: + resolution: + { + integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, + } + + safe-push-apply@1.0.0: + resolution: + { + integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==, + } + engines: { node: '>= 0.4' } + + safe-regex-test@1.1.0: + resolution: + { + integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==, + } + engines: { node: '>= 0.4' } + + safer-buffer@2.1.2: + resolution: + { + integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, + } + + sanitize-filename@1.6.3: + resolution: + { + integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==, + } + + sax@1.4.1: + resolution: + { + integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==, + } + + scheduler@0.27.0: + resolution: + { + integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==, + } + + semver-compare@1.0.0: + resolution: + { + integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==, + } + + semver@5.7.2: + resolution: + { + integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, + } + hasBin: true + + semver@6.3.1: + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } + hasBin: true + + semver@7.7.3: + resolution: + { + integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==, + } + engines: { node: '>=10' } + hasBin: true + + serialize-error@7.0.1: + resolution: + { + integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==, + } + engines: { node: '>=10' } + + set-cookie-parser@2.7.2: + resolution: + { + integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==, + } + + set-function-length@1.2.2: + resolution: + { + integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, + } + engines: { node: '>= 0.4' } + + set-function-name@2.0.2: + resolution: + { + integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, + } + engines: { node: '>= 0.4' } + + set-proto@1.0.0: + resolution: + { + integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==, + } + engines: { node: '>= 0.4' } + + setimmediate@1.0.5: + resolution: + { + integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==, + } + + shebang-command@2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: '>=8' } + + shebang-regex@3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: '>=8' } + + side-channel-list@1.0.0: + resolution: + { + integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==, + } + engines: { node: '>= 0.4' } + + side-channel-map@1.0.1: + resolution: + { + integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==, + } + engines: { node: '>= 0.4' } + + side-channel-weakmap@1.0.2: + resolution: + { + integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==, + } + engines: { node: '>= 0.4' } + + side-channel@1.1.0: + resolution: + { + integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, + } + engines: { node: '>= 0.4' } + + signal-exit@3.0.7: + resolution: + { + integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, + } + + signal-exit@4.1.0: + resolution: + { + integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, + } + engines: { node: '>=14' } + + simple-update-notifier@2.0.0: + resolution: + { + integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==, + } + engines: { node: '>=10' } + + slice-ansi@3.0.0: + resolution: + { + integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==, + } + engines: { node: '>=8' } + + slice-ansi@7.1.2: + resolution: + { + integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==, + } + engines: { node: '>=18' } + + smart-buffer@4.2.0: + resolution: + { + integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, + } + engines: { node: '>= 6.0.0', npm: '>= 3.0.0' } + + snake-case@3.0.4: + resolution: + { + integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==, + } + + socks-proxy-agent@7.0.0: + resolution: + { + integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==, + } + engines: { node: '>= 10' } + + socks@2.8.7: + resolution: + { + integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==, + } + engines: { node: '>= 10.0.0', npm: '>= 3.0.0' } + + source-map-js@1.2.1: + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: '>=0.10.0' } + + source-map-support@0.5.21: + resolution: + { + integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, + } + + source-map@0.6.1: + resolution: + { + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, + } + engines: { node: '>=0.10.0' } + + sprintf-js@1.1.3: + resolution: + { + integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==, + } + + ssri@9.0.1: + resolution: + { + integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + stat-mode@1.0.0: + resolution: + { + integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==, + } + engines: { node: '>= 6' } + + stop-iteration-iterator@1.1.0: + resolution: + { + integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==, + } + engines: { node: '>= 0.4' } + + string-argv@0.3.2: + resolution: + { + integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==, + } + engines: { node: '>=0.6.19' } + + string-width@4.2.3: + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: '>=8' } + + string-width@5.1.2: + resolution: + { + integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, + } + engines: { node: '>=12' } + + string-width@7.2.0: + resolution: + { + integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==, + } + engines: { node: '>=18' } + + string-width@8.1.0: + resolution: + { + integrity: sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==, + } + engines: { node: '>=20' } + + string.prototype.matchall@4.0.12: + resolution: + { + integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==, + } + engines: { node: '>= 0.4' } + + string.prototype.repeat@1.0.0: + resolution: + { + integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==, + } + + string.prototype.trim@1.2.10: + resolution: + { + integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==, + } + engines: { node: '>= 0.4' } + + string.prototype.trimend@1.0.9: + resolution: + { + integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==, + } + engines: { node: '>= 0.4' } + + string.prototype.trimstart@1.0.8: + resolution: + { + integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==, + } + engines: { node: '>= 0.4' } + + string_decoder@1.1.1: + resolution: + { + integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, + } + + string_decoder@1.3.0: + resolution: + { + integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, + } + + strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: '>=8' } + + strip-ansi@7.1.2: + resolution: + { + integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==, + } + engines: { node: '>=12' } + + strip-json-comments@3.1.1: + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: '>=8' } + + sumchecker@3.0.1: + resolution: + { + integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==, + } + engines: { node: '>= 8.0' } + + supports-color@5.5.0: + resolution: + { + integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, + } + engines: { node: '>=4' } + + supports-color@7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: '>=8' } + + supports-preserve-symlinks-flag@1.0.0: + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: '>= 0.4' } + + svg-parser@2.0.4: + resolution: + { + integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==, + } + + synckit@0.11.11: + resolution: + { + integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + + tailwind-merge@3.3.1: + resolution: + { + integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==, + } + + tailwindcss@4.1.16: + resolution: + { + integrity: sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==, + } + + tapable@2.3.0: + resolution: + { + integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==, + } + engines: { node: '>=6' } + + tar@6.2.1: + resolution: + { + integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==, + } + engines: { node: '>=10' } + + temp-file@3.4.0: + resolution: + { + integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==, + } + + temp@0.9.4: + resolution: + { + integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==, + } + engines: { node: '>=6.0.0' } + + tiny-async-pool@1.3.0: + resolution: + { + integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==, + } + + tiny-invariant@1.3.3: + resolution: + { + integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==, + } + + tiny-typed-emitter@2.1.0: + resolution: + { + integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==, + } + + tinyglobby@0.2.15: + resolution: + { + integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==, + } + engines: { node: '>=12.0.0' } + + tmp-promise@3.0.3: + resolution: + { + integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==, + } + + tmp@0.2.5: + resolution: + { + integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==, + } + engines: { node: '>=14.14' } + + to-regex-range@5.0.1: + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: '>=8.0' } + + truncate-utf8-bytes@1.0.2: + resolution: + { + integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==, + } + + ts-api-utils@2.1.0: + resolution: + { + integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==, + } + engines: { node: '>=18.12' } + peerDependencies: + typescript: '>=4.8.4' + + ts-morph@13.0.2: + resolution: + { + integrity: sha512-SjeeHaRf/mFsNeR3KTJnx39JyEOzT4e+DX28gQx5zjzEOuFs2eGrqeN2PLKs/+AibSxPmzV7RD8nJVKmFJqtLA==, + } + + tslib@2.8.1: + resolution: + { + integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==, + } + + type-check@0.4.0: + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: '>= 0.8.0' } + + type-fest@0.13.1: + resolution: + { + integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==, + } + engines: { node: '>=10' } + + typed-array-buffer@1.0.3: + resolution: + { + integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==, + } + engines: { node: '>= 0.4' } + + typed-array-byte-length@1.0.3: + resolution: + { + integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==, + } + engines: { node: '>= 0.4' } + + typed-array-byte-offset@1.0.4: + resolution: + { + integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==, + } + engines: { node: '>= 0.4' } + + typed-array-length@1.0.7: + resolution: + { + integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==, + } + engines: { node: '>= 0.4' } + + typescript@5.9.3: + resolution: + { + integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, + } + engines: { node: '>=14.17' } + hasBin: true + + unbox-primitive@1.1.0: + resolution: + { + integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==, + } + engines: { node: '>= 0.4' } + + undici-types@6.21.0: + resolution: + { + integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, + } + + undici-types@7.16.0: + resolution: + { + integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==, + } + + unique-filename@2.0.1: + resolution: + { + integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + unique-slug@3.0.0: + resolution: + { + integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==, + } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } + + universalify@0.1.2: + resolution: + { + integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==, + } + engines: { node: '>= 4.0.0' } + + universalify@2.0.1: + resolution: + { + integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==, + } + engines: { node: '>= 10.0.0' } + + unzip-crx-3@0.2.0: + resolution: + { + integrity: sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==, + } + + update-browserslist-db@1.1.4: + resolution: + { + integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==, + } + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + + use-sync-external-store@1.6.0: + resolution: + { + integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==, + } + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + utf8-byte-length@1.0.5: + resolution: + { + integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==, + } + + util-deprecate@1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } + + verror@1.10.1: + resolution: + { + integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==, + } + engines: { node: '>=0.6.0' } + + victory-vendor@37.3.6: + resolution: + { + integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==, + } + + vite-plugin-svgr@4.5.0: + resolution: + { + integrity: sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==, + } + peerDependencies: + vite: '>=2.6.0' + + vite@7.1.12: + resolution: + { + integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + wcwidth@1.0.1: + resolution: + { + integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==, + } + + which-boxed-primitive@1.1.1: + resolution: + { + integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==, + } + engines: { node: '>= 0.4' } + + which-builtin-type@1.2.1: + resolution: + { + integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==, + } + engines: { node: '>= 0.4' } + + which-collection@1.0.2: + resolution: + { + integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, + } + engines: { node: '>= 0.4' } + + which-typed-array@1.1.19: + resolution: + { + integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==, + } + engines: { node: '>= 0.4' } + + which@2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: '>= 8' } + hasBin: true + + word-wrap@1.2.5: + resolution: + { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: '>=0.10.0' } + + wrap-ansi@7.0.0: + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, + } + engines: { node: '>=10' } + + wrap-ansi@8.1.0: + resolution: + { + integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, + } + engines: { node: '>=12' } + + wrap-ansi@9.0.2: + resolution: + { + integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==, + } + engines: { node: '>=18' } + + wrappy@1.0.2: + resolution: + { + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } + + xmlbuilder@15.1.1: + resolution: + { + integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==, + } + engines: { node: '>=8.0' } + + y18n@5.0.8: + resolution: + { + integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, + } + engines: { node: '>=10' } + + yaku@0.16.7: + resolution: + { + integrity: sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw==, + } + + yallist@3.1.1: + resolution: + { + integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, + } + + yallist@4.0.0: + resolution: + { + integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, + } + + yaml@2.8.1: + resolution: + { + integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==, + } + engines: { node: '>= 14.6' } + hasBin: true + + yargs-parser@21.1.1: + resolution: + { + integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==, + } + engines: { node: '>=12' } + + yargs@17.7.2: + resolution: + { + integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==, + } + engines: { node: '>=12' } + + yauzl@2.10.0: + resolution: + { + integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==, + } + + yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: '>=10' } + + zod-validation-error@4.0.2: + resolution: + { + integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==, + } + engines: { node: '>=18.0.0' } + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.1.12: + resolution: + { + integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==, + } + + zustand@5.0.8: + resolution: + { + integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==, + } + engines: { node: '>=12.20.0' } + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + 7zip-bin@5.2.0: {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.27.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@develar/schema-utils@2.6.5': + dependencies: + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + '@electron/asar@3.2.18': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.2 + + '@electron/asar@3.4.1': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.2 + + '@electron/fuses@1.8.0': + dependencies: + chalk: 4.1.2 + fs-extra: 9.1.0 + minimist: 1.2.8 + + '@electron/get@2.0.3': + dependencies: + debug: 4.4.3 + env-paths: 2.2.1 + fs-extra: 8.1.0 + got: 11.8.6 + progress: 2.0.3 + semver: 6.3.1 + sumchecker: 3.0.1 + optionalDependencies: + global-agent: 3.0.0 + transitivePeerDependencies: + - supports-color + + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + glob: 8.1.0 + graceful-fs: 4.2.11 + make-fetch-happen: 10.2.1 + nopt: 6.0.0 + proc-log: 2.0.1 + semver: 7.7.3 + tar: 6.2.1 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + + '@electron/notarize@2.5.0': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + promise-retry: 2.0.1 + transitivePeerDependencies: + - supports-color + + '@electron/osx-sign@1.3.1': + dependencies: + compare-version: 0.1.2 + debug: 4.4.3 + fs-extra: 10.1.0 + isbinaryfile: 4.0.10 + minimist: 1.2.8 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/rebuild@3.7.0': + dependencies: + '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 + '@malept/cross-spawn-promise': 2.0.0 + chalk: 4.1.2 + debug: 4.4.3 + detect-libc: 2.1.2 + fs-extra: 10.1.0 + got: 11.8.6 + node-abi: 3.80.0 + node-api-version: 0.2.1 + ora: 5.4.1 + read-binary-file-arch: 1.0.6 + semver: 7.7.3 + tar: 6.2.1 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - supports-color + + '@electron/universal@2.0.1': + dependencies: + '@electron/asar': 3.2.18 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.3 + dir-compare: 4.2.0 + fs-extra: 11.3.2 + minimatch: 9.0.5 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/windows-sign@1.2.2': + dependencies: + cross-dirname: 0.1.0 + debug: 4.4.3 + fs-extra: 11.3.2 + minimist: 1.2.8 + postject: 1.0.0-alpha.6 + transitivePeerDependencies: + - supports-color + optional: true + + '@epic-web/invariant@1.0.0': {} + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.0(jiti@2.6.1))': + dependencies: + eslint: 9.39.0(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.0': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@gar/promisify@1.1.3': {} + + '@hookform/resolvers@5.2.2(react-hook-form@7.66.0(react@19.2.0))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.66.0(react@19.2.0) + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@malept/cross-spawn-promise@2.0.0': + dependencies: + cross-spawn: 7.0.6 + + '@malept/flatpak-bundler@0.4.0': + dependencies: + debug: 4.4.3 + fs-extra: 9.1.0 + lodash: 4.17.21 + tmp-promise: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@mediapipe/tasks-vision@0.10.22-rc.20250304': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@npmcli/fs@2.1.2': + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.7.3 + + '@npmcli/move-file@2.0.1': + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.2.9': {} + + '@reduxjs/toolkit@2.10.1(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': + dependencies: + '@standard-schema/spec': 1.0.0 + '@standard-schema/utils': 0.3.0 + immer: 10.2.0 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.2.0 + react-redux: 9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1) + + '@rolldown/pluginutils@1.0.0-beta.43': {} + + '@rollup/pluginutils@5.3.0(rollup@4.52.5)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.52.5 + + '@rollup/rollup-android-arm-eabi@4.52.5': + optional: true + + '@rollup/rollup-android-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-arm64@4.52.5': + optional: true + + '@rollup/rollup-darwin-x64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-arm64@4.52.5': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-linux-x64-musl@4.52.5': + optional: true + + '@rollup/rollup-openharmony-arm64@4.52.5': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.52.5': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.52.5': + optional: true + + '@sindresorhus/is@4.6.0': {} + + '@standard-schema/spec@1.0.0': {} + + '@standard-schema/utils@0.3.0': {} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-preset@8.1.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) + + '@svgr/core@8.1.0(typescript@5.9.3)': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.9.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@svgr/hast-util-to-babel-ast@8.0.0': + dependencies: + '@babel/types': 7.28.5 + entities: 4.5.0 + + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@tailwindcss/node@4.1.16': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.16 + + '@tailwindcss/oxide-android-arm64@4.1.16': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.16': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.16': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.16': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.16': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.16': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.16': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.16': + optional: true + + '@tailwindcss/oxide@4.1.16': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.16 + '@tailwindcss/oxide-darwin-arm64': 4.1.16 + '@tailwindcss/oxide-darwin-x64': 4.1.16 + '@tailwindcss/oxide-freebsd-x64': 4.1.16 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.16 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.16 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.16 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.16 + '@tailwindcss/oxide-linux-x64-musl': 4.1.16 + '@tailwindcss/oxide-wasm32-wasi': 4.1.16 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.16 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.16 + + '@tailwindcss/vite@4.1.16(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + dependencies: + '@tailwindcss/node': 4.1.16 + '@tailwindcss/oxide': 4.1.16 + tailwindcss: 4.1.16 + vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + + '@tanstack/query-core@5.90.6': {} + + '@tanstack/react-query@5.90.6(react@19.2.0)': + dependencies: + '@tanstack/query-core': 5.90.6 + react: 19.2.0 + + '@tootallnate/once@2.0.0': {} + + '@ts-morph/common@0.12.3': + dependencies: + fast-glob: 3.3.3 + minimatch: 3.1.2 + mkdirp: 1.0.4 + path-browserify: 1.0.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 22.19.0 + '@types/responselike': 1.0.3 + + '@types/d3-array@3.2.2': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree@1.0.8': {} + + '@types/fs-extra@9.0.13': + dependencies: + '@types/node': 24.10.0 + + '@types/history@4.7.11': {} + + '@types/http-cache-semantics@4.0.4': {} + + '@types/json-schema@7.0.15': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 22.19.0 + + '@types/ms@2.1.0': {} + + '@types/node@22.19.0': + dependencies: + undici-types: 6.21.0 + + '@types/node@24.10.0': + dependencies: + undici-types: 7.16.0 + + '@types/plist@3.0.5': + dependencies: + '@types/node': 24.10.0 + xmlbuilder: 15.1.1 + optional: true + + '@types/q@1.5.8': {} + + '@types/react-dom@19.2.2(@types/react@19.2.2)': + dependencies: + '@types/react': 19.2.2 + + '@types/react-router-dom@5.3.3': + dependencies: + '@types/history': 4.7.11 + '@types/react': 19.2.2 + '@types/react-router': 5.1.20 + + '@types/react-router@5.1.20': + dependencies: + '@types/history': 4.7.11 + '@types/react': 19.2.2 + + '@types/react@19.2.2': + dependencies: + csstype: 3.1.3 + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 22.19.0 + + '@types/use-sync-external-store@0.0.6': {} + + '@types/verror@1.10.11': + optional: true + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 22.19.0 + optional: true + + '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/type-utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.2 + eslint: 9.39.0(jiti@2.6.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.2 + debug: 4.4.3 + eslint: 9.39.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.46.2(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) + '@typescript-eslint/types': 8.46.2 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.46.2': + dependencies: + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + + '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.0(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.46.2': {} + + '@typescript-eslint/typescript-estree@8.46.2(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.46.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + eslint: 9.39.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.46.2': + dependencies: + '@typescript-eslint/types': 8.46.2 + eslint-visitor-keys: 4.2.1 + + '@vitejs/plugin-react@5.1.0(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.43 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + + '@xmldom/xmldom@0.8.11': {} + + abbrev@1.1.1: {} + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + agent-base@7.1.4: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ajv-keywords@3.5.2(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-escapes@7.1.1: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + app-builder-bin@5.0.0-alpha.12: {} + + app-builder-lib@26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)): + dependencies: + '@develar/schema-utils': 2.6.5 + '@electron/asar': 3.2.18 + '@electron/fuses': 1.8.0 + '@electron/notarize': 2.5.0 + '@electron/osx-sign': 1.3.1 + '@electron/rebuild': 3.7.0 + '@electron/universal': 2.0.1 + '@malept/flatpak-bundler': 0.4.0 + '@types/fs-extra': 9.0.13 + async-exit-hook: 2.0.1 + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chromium-pickle-js: 0.2.0 + config-file-ts: 0.2.8-rc1 + debug: 4.4.3 + dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)) + dotenv: 16.6.1 + dotenv-expand: 11.0.7 + ejs: 3.1.10 + electron-builder-squirrel-windows: 26.0.12(dmg-builder@26.0.12) + electron-publish: 26.0.11 + fs-extra: 10.1.0 + hosted-git-info: 4.1.0 + is-ci: 3.0.1 + isbinaryfile: 5.0.6 + js-yaml: 4.1.0 + json5: 2.2.3 + lazy-val: 1.0.5 + minimatch: 10.1.1 + plist: 3.1.0 + resedit: 1.7.2 + semver: 7.7.3 + tar: 6.2.1 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + transitivePeerDependencies: + - bluebird + - supports-color + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + assert-plus@1.0.0: + optional: true + + astral-regex@2.0.0: + optional: true + + async-exit-hook@2.0.1: {} + + async-function@1.0.0: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + autoprefixer@10.4.21(postcss@8.5.6): + dependencies: + browserslist: 4.27.0 + caniuse-lite: 1.0.30001753 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axios@1.13.1: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.8.23: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + boolean@3.2.0: + optional: true + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.27.0: + dependencies: + baseline-browser-mapping: 2.8.23 + caniuse-lite: 1.0.30001753 + electron-to-chromium: 1.5.244 + node-releases: 2.0.27 + update-browserslist-db: 1.1.4(browserslist@4.27.0) + + buffer-crc32@0.2.13: {} + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + builder-util-runtime@9.3.1: + dependencies: + debug: 4.4.3 + sax: 1.4.1 + transitivePeerDependencies: + - supports-color + + builder-util@26.0.11: + dependencies: + 7zip-bin: 5.2.0 + '@types/debug': 4.1.12 + app-builder-bin: 5.0.0-alpha.12 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + fs-extra: 10.1.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-ci: 3.0.1 + js-yaml: 4.1.0 + sanitize-filename: 1.6.3 + source-map-support: 0.5.21 + stat-mode: 1.0.0 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + transitivePeerDependencies: + - supports-color + + cacache@16.1.3: + dependencies: + '@npmcli/fs': 2.1.2 + '@npmcli/move-file': 2.0.1 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 8.1.0 + infer-owner: 1.0.4 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 9.0.1 + tar: 6.2.1 + unique-filename: 2.0.1 + transitivePeerDependencies: + - bluebird + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001753: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chownr@2.0.0: {} + + chromium-pickle-js@0.2.0: {} + + ci-info@3.9.0: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-spinners@2.9.2: {} + + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + optional: true + + cli-truncate@5.1.1: + dependencies: + slice-ansi: 7.1.2 + string-width: 8.1.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + clone@1.0.4: {} + + clsx@2.1.1: {} + + coa@2.0.2: + dependencies: + '@types/q': 1.5.8 + chalk: 2.4.2 + q: 1.5.1 + + code-block-writer@11.0.3: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@14.0.2: {} + + commander@5.1.0: {} + + commander@9.5.0: + optional: true + + compare-version@0.1.2: {} + + concat-map@0.0.1: {} + + config-file-ts@0.2.8-rc1: + dependencies: + glob: 10.4.5 + typescript: 5.9.3 + + convert-source-map@2.0.0: {} + + cookie@1.0.2: {} + + core-util-is@1.0.2: + optional: true + + core-util-is@1.0.3: {} + + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + + crc@3.8.0: + dependencies: + buffer: 5.7.1 + optional: true + + cross-dirname@0.1.0: + optional: true + + cross-env@10.1.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-ease@3.0.1: {} + + d3-format@3.1.0: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js-light@2.5.1: {} + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-is@0.1.4: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + detect-node@2.1.0: + optional: true + + dir-compare@4.2.0: + dependencies: + minimatch: 3.1.2 + p-limit: 3.1.0 + + dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)): + dependencies: + app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)) + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + fs-extra: 10.1.0 + iconv-lite: 0.6.3 + js-yaml: 4.1.0 + optionalDependencies: + dmg-license: 1.0.11 + transitivePeerDependencies: + - bluebird + - electron-builder-squirrel-windows + - supports-color + + dmg-license@1.0.11: + dependencies: + '@types/plist': 3.0.5 + '@types/verror': 1.10.11 + ajv: 6.12.6 + crc: 3.8.0 + iconv-corefoundation: 1.1.7 + plist: 3.1.0 + smart-buffer: 4.2.0 + verror: 1.10.1 + optional: true + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dotenv-expand@11.0.7: + dependencies: + dotenv: 16.6.1 + + dotenv@16.6.1: {} + + dotenv@17.2.3: {} + + dts-for-context-bridge@0.7.1: + dependencies: + coa: 2.0.2 + ts-morph: 13.0.2 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12): + dependencies: + app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)) + builder-util: 26.0.11 + electron-winstaller: 5.4.0 + transitivePeerDependencies: + - bluebird + - dmg-builder + - supports-color + + electron-builder@26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)): + dependencies: + app-builder-lib: 26.0.12(dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)))(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)) + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12)) + fs-extra: 10.1.0 + is-ci: 3.0.1 + lazy-val: 1.0.5 + simple-update-notifier: 2.0.0 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - electron-builder-squirrel-windows + - supports-color + + electron-devtools-installer@4.0.0: + dependencies: + unzip-crx-3: 0.2.0 + + electron-publish@26.0.11: + dependencies: + '@types/fs-extra': 9.0.13 + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + form-data: 4.0.4 + fs-extra: 10.1.0 + lazy-val: 1.0.5 + mime: 2.6.0 + transitivePeerDependencies: + - supports-color + + electron-to-chromium@1.5.244: {} + + electron-updater@6.6.2: + dependencies: + builder-util-runtime: 9.3.1 + fs-extra: 10.1.0 + js-yaml: 4.1.0 + lazy-val: 1.0.5 + lodash.escaperegexp: 4.1.2 + lodash.isequal: 4.5.0 + semver: 7.7.3 + tiny-typed-emitter: 2.1.0 + transitivePeerDependencies: + - supports-color + + electron-winstaller@5.4.0: + dependencies: + '@electron/asar': 3.4.1 + debug: 4.4.3 + fs-extra: 7.0.1 + lodash: 4.17.21 + temp: 0.9.4 + optionalDependencies: + '@electron/windows-sign': 1.2.2 + transitivePeerDependencies: + - supports-color + + electron@39.0.0: + dependencies: + '@electron/get': 2.0.3 + '@types/node': 22.19.0 + extract-zip: 2.0.1 + transitivePeerDependencies: + - supports-color + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encoding@0.1.13: + dependencies: + iconv-lite: 0.6.3 + optional: true + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@4.5.0: {} + + env-paths@2.2.1: {} + + environment@1.1.0: {} + + err-code@2.0.3: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + es-toolkit@1.41.0: {} + + es6-error@4.1.1: + optional: true + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@2.6.1)): + dependencies: + eslint: 9.39.0(jiti@2.6.1) + + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@2.6.1)))(eslint@9.39.0(jiti@2.6.1))(prettier@3.6.2): + dependencies: + eslint: 9.39.0(jiti@2.6.1) + prettier: 3.6.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.11 + optionalDependencies: + eslint-config-prettier: 10.1.8(eslint@9.39.0(jiti@2.6.1)) + + eslint-plugin-react-hooks@7.0.1(eslint@9.39.0(jiti@2.6.1)): + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 + eslint: 9.39.0(jiti@2.6.1) + hermes-parser: 0.25.1 + zod: 4.1.12 + zod-validation-error: 4.0.2(zod@4.1.12) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-refresh@0.4.24(eslint@9.39.0(jiti@2.6.1)): + dependencies: + eslint: 9.39.0(jiti@2.6.1) + + eslint-plugin-react@7.37.5(eslint@9.39.0(jiti@2.6.1)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.39.0(jiti@2.6.1) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.0(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@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.0 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + 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.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + eventemitter3@5.0.1: {} + + exponential-backoff@3.1.3: {} + + extract-zip@2.0.1: + dependencies: + debug: 4.4.3 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + extsprintf@1.4.1: + optional: true + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + follow-redirects@1.15.11: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fraction.js@4.3.7: {} + + framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + motion-dom: 12.23.23 + motion-utils: 12.23.6 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.4.0: {} + + get-intrinsic@1.3.0: + 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 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@5.2.0: + dependencies: + pump: 3.0.3 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + global-agent@3.0.0: + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.7.3 + serialize-error: 7.0.1 + optional: true + + globals@14.0.0: {} + + globals@16.5.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.1.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + http-cache-semantics@4.2.0: {} + + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + husky@9.1.7: {} + + iconv-corefoundation@1.1.7: + dependencies: + cli-truncate: 2.1.0 + node-addon-api: 1.7.2 + optional: true + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + immediate@3.0.6: {} + + immer@10.2.0: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + infer-owner@1.0.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + internmap@2.0.3: {} + + ip-address@10.0.1: {} + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-ci@3.0.1: + dependencies: + ci-info: 3.9.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.4.0 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-interactive@1.0.0: {} + + is-lambda@1.0.1: {} + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-unicode-supported@0.1.0: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isbinaryfile@4.0.10: {} + + isbinaryfile@5.0.6: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.4 + picocolors: 1.1.1 + + jiti@2.6.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: + optional: true + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + lazy-val@1.0.5: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + 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 + + lines-and-columns@1.2.4: {} + + lint-staged@16.2.6: + dependencies: + commander: 14.0.2 + listr2: 9.0.5 + micromatch: 4.0.8 + nano-spawn: 2.0.0 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.8.1 + + listr2@9.0.5: + dependencies: + cli-truncate: 5.1.1 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.2 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.escaperegexp@4.1.2: {} + + lodash.isequal@4.5.0: {} + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.1.1 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lowercase-keys@2.0.0: {} + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lru-cache@7.18.3: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-fetch-happen@10.2.1: + dependencies: + agentkeepalive: 4.6.0 + cacache: 16.1.3 + http-cache-semantics: 4.2.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 2.1.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.4 + promise-retry: 2.0.1 + socks-proxy-agent: 7.0.0 + ssri: 9.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + + matcher@3.0.0: + dependencies: + escape-string-regexp: 4.0.0 + optional: true + + math-intrinsics@1.1.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@2.6.0: {} + + mimic-fn@2.1.0: {} + + mimic-function@5.0.1: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass-collect@1.0.2: + dependencies: + minipass: 3.3.6 + + minipass-fetch@2.1.2: + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + + minipass-flush@1.0.5: + dependencies: + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass-sized@1.0.3: + dependencies: + minipass: 3.3.6 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.2: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@1.0.4: {} + + motion-dom@12.23.23: + dependencies: + motion-utils: 12.23.6 + + motion-utils@12.23.6: {} + + ms@2.1.3: {} + + nano-spawn@2.0.0: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + negotiator@0.6.4: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + node-abi@3.80.0: + dependencies: + semver: 7.7.3 + + node-addon-api@1.7.2: + optional: true + + node-api-version@0.2.1: + dependencies: + semver: 7.7.3 + + node-releases@2.0.27: {} + + nopt@6.0.0: + dependencies: + abbrev: 1.1.1 + + normalize-range@0.1.2: {} + + normalize-url@6.1.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-cancelable@2.1.1: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + package-json-from-dist@1.0.1: {} + + pako@1.0.11: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-type@4.0.0: {} + + pe-library@0.4.1: {} + + pend@1.2.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pidtree@0.6.0: {} + + plist@3.1.0: + dependencies: + '@xmldom/xmldom': 0.8.11 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + + possible-typed-array-names@1.1.0: {} + + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postject@1.0.0-alpha.6: + dependencies: + commander: 9.5.0 + optional: true + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier-plugin-tailwindcss@0.7.1(prettier@3.6.2): + dependencies: + prettier: 3.6.2 + + prettier@3.6.2: {} + + proc-log@2.0.1: {} + + process-nextick-args@2.0.1: {} + + progress@2.0.3: {} + + promise-inflight@1.0.1: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + proxy-from-env@1.1.0: {} + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + q@1.5.1: {} + + queue-microtask@1.2.3: {} + + quick-lru@5.1.1: {} + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + + react-hook-form@7.66.0(react@19.2.0): + dependencies: + react: 19.2.0 + + react-is@16.13.1: {} + + react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.2 + redux: 5.0.1 + + react-refresh@0.18.0: {} + + react-router-dom@7.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-router: 7.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + + react-router@7.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + cookie: 1.0.2 + react: 19.2.0 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.0(react@19.2.0) + + react-webcam@7.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + react@19.2.0: {} + + read-binary-file-arch@1.0.6: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + recharts@3.3.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@16.13.1)(react@19.2.0)(redux@5.0.1): + dependencies: + '@reduxjs/toolkit': 2.10.1(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0) + clsx: 2.1.1 + decimal.js-light: 2.5.1 + es-toolkit: 1.41.0 + eventemitter3: 5.0.1 + immer: 10.2.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-is: 16.13.1 + react-redux: 9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1) + reselect: 5.1.1 + tiny-invariant: 1.3.3 + use-sync-external-store: 1.6.0(react@19.2.0) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux + + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-directory@2.1.1: {} + + resedit@1.7.2: + dependencies: + pe-library: 0.4.1 + + reselect@5.1.1: {} + + resolve-alpn@1.2.1: {} + + resolve-from@4.0.0: {} + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + retry@0.12.0: {} + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rimraf@2.6.3: + dependencies: + glob: 7.2.3 + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + roarr@2.15.4: + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.4 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.3 + optional: true + + rollup@4.52.5: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + sanitize-filename@1.6.3: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sax@1.4.1: {} + + scheduler@0.27.0: {} + + semver-compare@1.0.0: + optional: true + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + optional: true + + set-cookie-parser@2.7.2: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + setimmediate@1.0.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + simple-update-notifier@2.0.0: + dependencies: + semver: 7.7.3 + + slice-ansi@3.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + optional: true + + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + smart-buffer@4.2.0: {} + + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + socks-proxy-agent@7.0.0: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.0.1 + smart-buffer: 4.2.0 + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.1.3: + optional: true + + ssri@9.0.1: + dependencies: + minipass: 3.3.6 + + stat-mode@1.0.0: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + + string-width@8.1.0: + dependencies: + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + strip-json-comments@3.1.1: {} + + sumchecker@3.0.1: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + svg-parser@2.0.4: {} + + synckit@0.11.11: + dependencies: + '@pkgr/core': 0.2.9 + + tailwind-merge@3.3.1: {} + + tailwindcss@4.1.16: {} + + tapable@2.3.0: {} + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + temp-file@3.4.0: + dependencies: + async-exit-hook: 2.0.1 + fs-extra: 10.1.0 + + temp@0.9.4: + dependencies: + mkdirp: 0.5.6 + rimraf: 2.6.3 + + tiny-async-pool@1.3.0: + dependencies: + semver: 5.7.2 + + tiny-invariant@1.3.3: {} + + tiny-typed-emitter@2.1.0: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tmp-promise@3.0.3: + dependencies: + tmp: 0.2.5 + + tmp@0.2.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-morph@13.0.2: + dependencies: + '@ts-morph/common': 0.12.3 + code-block-writer: 11.0.3 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.13.1: + optional: true + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + undici-types@7.16.0: {} + + unique-filename@2.0.1: + dependencies: + unique-slug: 3.0.0 + + unique-slug@3.0.0: + dependencies: + imurmurhash: 0.1.4 + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unzip-crx-3@0.2.0: + dependencies: + jszip: 3.10.1 + mkdirp: 0.5.6 + yaku: 0.16.7 + + update-browserslist-db@1.1.4(browserslist@4.27.0): + dependencies: + browserslist: 4.27.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-sync-external-store@1.6.0(react@19.2.0): + dependencies: + react: 19.2.0 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + verror@1.10.1: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.4.1 + optional: true + + victory-vendor@37.3.6: + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + + vite-plugin-svgr@4.5.0(rollup@4.52.5)(typescript@5.9.3)(vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)): + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.52.5) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + vite: 7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + transitivePeerDependencies: + - rollup + - supports-color + - typescript + + vite@7.1.12(@types/node@24.10.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.52.5 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.10.0 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + yaml: 2.8.1 + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + + wrappy@1.0.2: {} + + xmlbuilder@15.1.1: {} + + y18n@5.0.8: {} + + yaku@0.16.7: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@2.8.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yocto-queue@0.1.0: {} + + zod-validation-error@4.0.2(zod@4.1.12): + dependencies: + zod: 4.1.12 + + zod@4.1.12: {} + + zustand@5.0.8(@types/react@19.2.2)(immer@10.2.0)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): + optionalDependencies: + '@types/react': 19.2.2 + immer: 10.2.0 + react: 19.2.0 + use-sync-external-store: 1.6.0(react@19.2.0) diff --git a/src/main/assets/Symbol_Logo.png b/src/main/assets/Symbol_Logo.png new file mode 100644 index 0000000..7c6b6ac Binary files /dev/null and b/src/main/assets/Symbol_Logo.png differ diff --git a/src/main/src/index.ts b/src/main/src/index.ts index 86c9430..08a8067 100644 --- a/src/main/src/index.ts +++ b/src/main/src/index.ts @@ -1,8 +1,14 @@ -import { app, ipcMain } from 'electron'; +import { app, ipcMain, nativeTheme } from 'electron'; import { appendFile, mkdir } from 'fs/promises'; import { join } from 'path'; import './security-restrictions'; import { restoreOrCreateWindow } from '/@/mainWindow'; +import { + openWidgetWindow, + closeWidgetWindow, + isWidgetWindowOpen, +} from '/@/widgetWindow'; +import { setupNotificationHandlers } from '/@/notificationHandlers'; /** * Setup IPC handlers for Electron-specific features @@ -37,6 +43,49 @@ function setupAPIHandlers() { } }, ); + + /* 리액트에서 Main Process로 오는 요청을 처리하는 함수*/ + + /* 위젯 오픈 요청 핸들러 */ + ipcMain.handle('widget:open', async () => { + try { + await openWidgetWindow(); + return { success: true }; + } catch (error) { + console.error('Failed to open widget window:', error); + throw error; + } + }); + + /* 위젯 닫기 요청 핸들러 */ + ipcMain.handle('widget:close', () => { + try { + closeWidgetWindow(); + return { success: true }; + } catch (error) { + console.error('Failed to close widget window:', error); + throw error; + } + }); + + /* 시스템 테마 조회 핸들러 */ + ipcMain.handle('theme:getSystemTheme', () => { + return nativeTheme.shouldUseDarkColors ? 'dark' : 'light'; + }); + /* Notification 핸들러 설정 */ + setupNotificationHandlers(); +} +/* 위젯 상태 확인 요청 핸들러 */ +ipcMain.handle('widget:isOpen', () => { + return isWidgetWindowOpen(); +}); + +/** + * Set App User Model ID for Windows notifications + * mac은 필요 x + */ +if (process.platform === 'win32') { + app.setAppUserModelId('거부기린'); } /** diff --git a/src/main/src/mainWindow.ts b/src/main/src/mainWindow.ts index 419b709..5c7e416 100644 --- a/src/main/src/mainWindow.ts +++ b/src/main/src/mainWindow.ts @@ -1,61 +1,45 @@ +// main/src/mainWindow.ts import { BrowserWindow } from 'electron'; import { join } from 'path'; -import { URL } from 'url'; + +const MIN_W = 1280; +const MIN_H = 800; async function createWindow() { - const browserWindow = new BrowserWindow({ - show: false, // Use 'ready-to-show' event to show window + const win = new BrowserWindow({ + show: false, + useContentSize: true, // 프레임 제외한 콘텐츠 영역 기준 + width: MIN_W, + height: MIN_H, + minWidth: MIN_W, + minHeight: MIN_H, + fullscreenable: false, // 전체 화면 금지(원하면 true) + // maximizable: false, // 최대화 버튼 자체를 막고 싶으면 주석 해제 webPreferences: { - webviewTag: false, // The webview tag is not recommended. Consider alternatives like iframe or Electron's BrowserView. https://www.electronjs.org/docs/latest/api/webview-tag#warning preload: join(__dirname, '../preload/index.cjs'), nodeIntegration: false, contextIsolation: true, allowRunningInsecureContent: false, - // GPU 가속은 app.commandLine.appendSwitch로 활성화됨 }, }); - /** - * If you install `show: true` then it can cause issues when trying to close the window. - * Use `show: false` and listener events `ready-to-show` to fix these issues. - * - * @see https://github.com/electron/electron/issues/25012 - */ - browserWindow.on('ready-to-show', () => { - browserWindow?.maximize(); - browserWindow?.show(); - - if (import.meta.env.DEV) { - // browserWindow?.webContents.openDevTools(); - } + win.on('ready-to-show', () => { + win.center(); + win.show(); }); const pageUrl = - import.meta.env.DEV && process.env.VITE_DEV_SERVER_URL !== undefined + import.meta.env.DEV && process.env.VITE_DEV_SERVER_URL ? process.env.VITE_DEV_SERVER_URL - : new URL( - join(__dirname, '..', 'renderer', 'index.html'), - 'file:', - ).toString(); - - await browserWindow.loadURL(pageUrl); + : 'https://www.bugi.co.kr/'; - return browserWindow; + await win.loadURL(pageUrl); + return win; } -/** - * Restore existing BrowserWindow or Create new BrowserWindow - */ export async function restoreOrCreateWindow() { - let window = BrowserWindow.getAllWindows().find((w) => !w.isDestroyed()); - - if (window === undefined) { - window = await createWindow(); - } - - if (window.isMinimized()) { - window.restore(); - } - - window.focus(); + let w = BrowserWindow.getAllWindows().find((x) => !x.isDestroyed()); + if (!w) w = await createWindow(); + if (w.isMinimized()) w.restore(); + w.focus(); } diff --git a/src/main/src/notificationHandlers.ts b/src/main/src/notificationHandlers.ts new file mode 100644 index 0000000..a9adad5 --- /dev/null +++ b/src/main/src/notificationHandlers.ts @@ -0,0 +1,70 @@ +import { app, ipcMain, Notification } from 'electron'; +import { join } from 'path'; + +/** + * Setup notification IPC handlers + */ +export function setupNotificationHandlers() { + /* 시스템 알림 표시 핸들러 (실제로 알림 띄우는 역할)*/ + ipcMain.handle( + 'notification:show', + async (_event, title: string, body: string) => { + try { + console.log('🔔 [Notification] 알림 요청 받음:', { title, body }); + + /* Notification 권한 확인 */ + if (!Notification.isSupported()) { + console.warn('❌ [Notification] 시스템 알림이 지원되지 않습니다'); + return { success: false, error: 'Not supported' }; + } + + console.log('✅ [Notification] 시스템 알림 지원됨'); + + /* 아이콘 경로 설정 (개발/프로덕션 환경 구분) */ + const iconPath = import.meta.env.DEV + ? join(app.getAppPath(), 'src', 'main', 'assets', 'Symbol_Logo.png') + : join(process.resourcesPath, 'Symbol_Logo.png'); + + /* 알림 생성 및 표시 */ + const notification = new Notification({ + title, + body, + icon: iconPath, + }); + + /* 알림 이벤트 리스너 추가 */ + notification.on('show', () => { + console.log('✅ [Notification] 알림이 표시되었습니다'); + }); + + notification.show(); + + return { success: true }; + } catch (error) { + console.error('❌ [Notification] 알림 표시 실패:', error); + return { success: false, error: String(error) }; + } + }, + ); + + /* 알림 권한 요청 핸들러(시스템이 알림 기능 사용할 수 있는지 확인) */ + ipcMain.handle('notification:requestPermission', async () => { + try { + /* Electron에서는 별도의 권한 요청이 필요하지 않지만, + 시스템 알림이 지원되는지 확인 */ + const isSupported = Notification.isSupported(); + + if (import.meta.env.DEV) { + console.log(`🔔 Notification support: ${isSupported}`); + } + + return { + success: true, + supported: isSupported, + }; + } catch (error) { + console.error('Failed to check notification permission:', error); + return { success: false, error: String(error) }; + } + }); +} diff --git a/src/main/src/security-restrictions.ts b/src/main/src/security-restrictions.ts index 9b89a0f..eebfe6d 100644 --- a/src/main/src/security-restrictions.ts +++ b/src/main/src/security-restrictions.ts @@ -159,4 +159,35 @@ app.on('web-contents-created', (_, contents) => { // Disable Node.js integration webPreferences.nodeIntegration = false; }); + + /** + * Prevent page reload (F5, Ctrl+R, Cmd+R) + * 개발 모드에서는 허용하고 프로덕션에서만 막기 + */ + contents.on('before-input-event', (event, input) => { + // 개발 모드에서는 새로고침 허용 + if (import.meta.env.DEV) { + return; + } + + // F5 또는 새로고침 단축키 (Ctrl+R, Cmd+R) 막기 + if ( + input.key === 'F5' || + (input.key === 'r' && (input.control || input.meta)) + ) { + event.preventDefault(); + } + }); + + /** + * Prevent programmatic reload + * 개발 모드에서는 허용하고 프로덕션에서만 막기 + */ + if (import.meta.env.PROD) { + const originalReload = contents.reload.bind(contents); + contents.reload = () => { + console.warn('Page reload is disabled in production mode'); + // 새로고침 실행하지 않음 + }; + } }); diff --git a/src/main/src/widgetConfig.ts b/src/main/src/widgetConfig.ts new file mode 100644 index 0000000..de9ed20 --- /dev/null +++ b/src/main/src/widgetConfig.ts @@ -0,0 +1,33 @@ +// 위젯 크기 타입 정의 +export type WidgetSize = 'mini' | 'medium'; + +// 위젯 기본 설정 +export const WIDGET_CONFIG = { + // 기본 시작 크기 + defaultWidth: 200, + defaultHeight: 320, + + // 최소 / 최대 크기 (사용자가 조절 가능한 범위) + minWidth: 150, + minHeight: 32, + maxWidth: 260, + maxHeight: 348, + + /* 레이아웃 전환 기준점 */ + breakpoint: { + height: 62, + }, + + /* 미니 모드 크기 설정 */ + mini: { + defaultWidth: 244, + defaultHeight: 42, + maxHeight: 50, + }, + + /* 미디엄 모드 크기 및 전환 임계값 */ + medium: { + minWidth: 192, + minHeight: 268, + }, +} as const; diff --git a/src/main/src/widgetWindow.ts b/src/main/src/widgetWindow.ts new file mode 100644 index 0000000..f91bade --- /dev/null +++ b/src/main/src/widgetWindow.ts @@ -0,0 +1,88 @@ +import { BrowserWindow } from 'electron'; +import { join } from 'path'; +import { WIDGET_CONFIG } from './widgetConfig'; + +/*위젯 관리 변수*/ +let widgetWindow: BrowserWindow | null = null; + +/* Create a widget window (위젯 창 생성)*/ +async function createWidgetWindow() { + // 이미 위젯 창이 있으면 포커스만 주고 반환(중복 방지) + if (widgetWindow && !widgetWindow.isDestroyed()) { + widgetWindow.focus(); + return widgetWindow; + } + + /* 위젯 속성 - 반응형 크기 조절 가능 */ + widgetWindow = new BrowserWindow({ + width: WIDGET_CONFIG.defaultWidth, + height: WIDGET_CONFIG.defaultHeight, + minWidth: WIDGET_CONFIG.minWidth, + minHeight: WIDGET_CONFIG.minHeight, + maxWidth: WIDGET_CONFIG.maxWidth, + maxHeight: WIDGET_CONFIG.maxHeight, + show: false, //깜빡임 방지 + frame: false, // 커스텀 타이틀바 사용을 위해 기본 프레임 제거 + + transparent: false, // 투명 배경 비활성화 (크기 조절을 위해) + + backgroundColor: '#00000000', // 투명 배경색 + alwaysOnTop: true, // 항상 위에 표시 + resizable: true, // 크기 조절 가능 (사용자가 드래그로 크기 조절 가능) + skipTaskbar: false, // 작업표시줄에 표시 여부 + hasShadow: true, // 그림자 추가 + webPreferences: { + webviewTag: false, + preload: join(__dirname, '../preload/index.cjs'), //preload 스크립트 + nodeIntegration: false, // Node.js API 직접 접근 차단 + contextIsolation: true, // Renderer와 Main 프로세스 격리 + allowRunningInsecureContent: false, + }, + }); + + /* 창이 완전히 로드되면 표시 */ + widgetWindow.on('ready-to-show', () => { + widgetWindow?.show(); + + if (import.meta.env.DEV) { + // widgetWindow?.webContents.openDevTools(); + } + }); + + // 위젯 창이 닫힐 때 참조 제거 + widgetWindow.on('closed', () => { + widgetWindow = null; + }); + + // 위젯 전용 URL + const baseUrl = + import.meta.env.DEV && process.env.VITE_DEV_SERVER_URL !== undefined + ? `${process.env.VITE_DEV_SERVER_URL}widget` + : 'https://www.bugi.co.kr/widget'; + + await widgetWindow.loadURL(baseUrl); +} + +export async function openWidgetWindow() { + if (widgetWindow && !widgetWindow.isDestroyed()) { + widgetWindow.focus(); + return widgetWindow; + } + + return await createWidgetWindow(); +} + +export function closeWidgetWindow() { + if (widgetWindow && !widgetWindow.isDestroyed()) { + widgetWindow.close(); + } + widgetWindow = null; +} + +export function isWidgetWindowOpen() { + return widgetWindow !== null && !widgetWindow.isDestroyed(); +} + +export function getWidgetWindow() { + return widgetWindow; +} diff --git a/src/preload/exposedInMainWorld.d.ts b/src/preload/exposedInMainWorld.d.ts index 4dd844c..a23ce86 100644 --- a/src/preload/exposedInMainWorld.d.ts +++ b/src/preload/exposedInMainWorld.d.ts @@ -1,15 +1,5 @@ interface Window { - readonly bugi: { version: number; }; - /** - * Safe expose crypto API - * @example - * window.nodeCrypto.sha256sum('data') - */ - readonly nodeCrypto: { sha256sum: (data: string) => Promise; }; - /** - * Expose API functionality to renderer - * @example - * window.electronAPI.getHealth() - */ - readonly electronAPI: { getHealth: () => Promise; getVersion: () => Promise; generateHash: (data: string) => Promise; generateBatchHash: (dataList: string[]) => Promise; getPlatform: () => Promise; writeLog: (data: string, filename?: string) => Promise; }; + readonly bugi: BugiAPI; + readonly nodeCrypto: NodeCryptoAPI; + readonly electronAPI: ElectronAPI; } diff --git a/src/preload/src/index.ts b/src/preload/src/index.ts index b2cd112..8ffc4a8 100644 --- a/src/preload/src/index.ts +++ b/src/preload/src/index.ts @@ -4,8 +4,90 @@ import { contextBridge, ipcRenderer } from 'electron'; +// Health 응답 타입 (예시) +// TODO: 실제 메인 프로세스에서 보내는 데이터 구조에 맞게 수정 +type HealthResponse = { + status: 'ok'; + uptime: number; +}; + +// Version 응답 타입 (예시) +type VersionInfo = { + appVersion: string; + electron: string; + chrome: string; + node: string; +}; + +// 플랫폼 정보 (예시) +type PlatformInfo = { + // eslint-disable-next-line no-undef + os: NodeJS.Platform; + arch: string; +}; + +// 로그 작성 결과 (예시) +type WriteLogResult = { + success: boolean; + path?: string; + error?: string; +}; + +// 시스템 테마 타입 (예시) +type SystemTheme = 'light' | 'dark' | 'system'; + +// window.bugi 타입 +type BugiAPI = { + version: number; +}; + +// window.nodeCrypto 타입 +type NodeCryptoAPI = { + sha256sum: (data: string) => Promise; +}; + +// window.electronAPI 타입 +interface ElectronAPI { + // Health check + getHealth: () => Promise; + + // Version info + getVersion: () => Promise; + + // Hash generation + generateHash: (data: string) => Promise; + + // Batch hash generation + generateBatchHash: (dataList: string[]) => Promise; + + // Platform info + getPlatform: () => Promise; + + // Write log file + writeLog: (data: string, filename?: string) => Promise; + + widget: { + open: () => Promise; + close: () => Promise; + isOpen: () => Promise; + }; + + // 시스템 테마 조회 + getSystemTheme: () => Promise; + + // 알림 API + notification: { + show: ( + title: string, + body: string, + ) => Promise<{ success: boolean; error?: string }>; + requestPermission: () => Promise<{ success: boolean; supported: boolean }>; + }; +} + // Expose version number to renderer -contextBridge.exposeInMainWorld('bugi', { version: 0.1 }); +const bugiAPI: BugiAPI = { version: 0.1 }; +contextBridge.exposeInMainWorld('bugi', bugiAPI); /** * The "Main World" is the JavaScript context that your main renderer code runs in. @@ -28,7 +110,7 @@ contextBridge.exposeInMainWorld('bugi', { version: 0.1 }); * @example * window.nodeCrypto.sha256sum('data') */ -contextBridge.exposeInMainWorld('nodeCrypto', { +const nodeCryptoAPI: NodeCryptoAPI = { sha256sum: async (data: string) => { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); @@ -36,31 +118,79 @@ contextBridge.exposeInMainWorld('nodeCrypto', { const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); }, -}); +}; +contextBridge.exposeInMainWorld('nodeCrypto', nodeCryptoAPI); /** * Expose API functionality to renderer * @example * window.electronAPI.getHealth() */ -contextBridge.exposeInMainWorld('electronAPI', { +const electronAPI: ElectronAPI = { // Health check - getHealth: () => ipcRenderer.invoke('api:health'), + getHealth: () => + ipcRenderer.invoke('api:health') as ReturnType, // Version info - getVersion: () => ipcRenderer.invoke('api:version'), + getVersion: () => + ipcRenderer.invoke('api:version') as ReturnType, // Hash generation - generateHash: (data: string) => ipcRenderer.invoke('api:hash', data), + generateHash: (data: string) => + ipcRenderer.invoke('api:hash', data) as ReturnType< + ElectronAPI['generateHash'] + >, // Batch hash generation generateBatchHash: (dataList: string[]) => - ipcRenderer.invoke('api:hash:batch', dataList), + ipcRenderer.invoke('api:hash:batch', dataList) as ReturnType< + ElectronAPI['generateBatchHash'] + >, // Platform info - getPlatform: () => ipcRenderer.invoke('api:platform'), + getPlatform: () => + ipcRenderer.invoke('api:platform') as ReturnType< + ElectronAPI['getPlatform'] + >, // Write log file writeLog: (data: string, filename?: string) => - ipcRenderer.invoke('api:writeLog', data, filename), -}); + ipcRenderer.invoke('api:writeLog', data, filename) as ReturnType< + ElectronAPI['writeLog'] + >, + + /*electronAPI 객체에 widget 추가해서 리액트에서 접근 가능하도록 설정(리액트와 main process의 다리 역할) */ + widget: { + open: () => + ipcRenderer.invoke('widget:open') as ReturnType< + ElectronAPI['widget']['open'] + >, + close: () => + ipcRenderer.invoke('widget:close') as ReturnType< + ElectronAPI['widget']['close'] + >, + isOpen: () => + ipcRenderer.invoke('widget:isOpen') as ReturnType< + ElectronAPI['widget']['isOpen'] + >, + }, + + // 시스템 테마 조회 + getSystemTheme: () => + ipcRenderer.invoke('theme:getSystemTheme') as ReturnType< + ElectronAPI['getSystemTheme'] + >, + + // 알림 API + notification: { + show: (title: string, body: string) => + ipcRenderer.invoke('notification:show', title, body) as ReturnType< + ElectronAPI['notification']['show'] + >, + requestPermission: () => + ipcRenderer.invoke('notification:requestPermission') as ReturnType< + ElectronAPI['notification']['requestPermission'] + >, + }, +}; +contextBridge.exposeInMainWorld('electronAPI', electronAPI); diff --git a/src/renderer/index.html b/src/renderer/index.html index 45ef696..e94ab21 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -2,12 +2,13 @@ - + 거부기린
+ diff --git a/src/renderer/public/favicon.ico b/src/renderer/public/favicon.ico new file mode 100644 index 0000000..77f6911 Binary files /dev/null and b/src/renderer/public/favicon.ico differ diff --git a/assets/fonts/PretendardVariable.woff2 b/src/renderer/public/fonts/PretendardVariable.woff2 similarity index 100% rename from assets/fonts/PretendardVariable.woff2 rename to src/renderer/public/fonts/PretendardVariable.woff2 diff --git a/src/renderer/src/api/api.ts b/src/renderer/src/api/api.ts index 9bc9c9d..84d4a4b 100644 --- a/src/renderer/src/api/api.ts +++ b/src/renderer/src/api/api.ts @@ -1,4 +1,16 @@ import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'; +import { Ref } from 'react'; + +interface RefreshResponse { + timestamp: string; + success: boolean; + data: { + accessToken: string; + refreshToken: string; + }; + code: string; + message: string | null; +} const api: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_BASE_URL as string, @@ -28,28 +40,37 @@ api.interceptors.response.use( _retry?: boolean; }; // 무한 요청 방지 - if (error.response?.status === 401 && !originalRequest._retry) { + /* 에러가 401,403일 때 토큰 갱신 */ + if ( + (error.response?.status === 401 || error.response?.status === 403) && + !originalRequest._retry + ) { originalRequest._retry = true; try { const refreshToken = localStorage.getItem('refreshToken'); - const { data: newToken } = await axios.post<{ - accessToken: string; - refreshToken: string; - }>( + const { data: newToken } = await axios.post( `${import.meta.env.VITE_BASE_URL}/auth/refresh`, { refreshToken }, { withCredentials: true }, ); - localStorage.setItem('accessToken', newToken.accessToken); - localStorage.setItem('refreshToken', newToken.refreshToken); + /* success가 false이거나 응답으로 온 데이터가 비었을 때 */ + if (!newToken.success || !newToken.data) { + throw new Error('Refresh token expired'); + } + + /* 새로 발급 받은 토큰 저장 */ + const newAccessToken = newToken.data.accessToken; + const newRefreshToken = newToken.data.refreshToken; + + localStorage.setItem('accessToken', newAccessToken); + localStorage.setItem('refreshToken', newRefreshToken); api.defaults.headers.common['Authorization'] = - `Bearer ${newToken.accessToken}`; + `Bearer ${newAccessToken}`; if (originalRequest.headers) { - originalRequest.headers['Authorization'] = - `Bearer ${newToken.accessToken}`; + originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; } return api(originalRequest); diff --git a/src/renderer/src/api/dashboard/useAverageScoreQuery.ts b/src/renderer/src/api/dashboard/useAverageScoreQuery.ts new file mode 100644 index 0000000..d86f643 --- /dev/null +++ b/src/renderer/src/api/dashboard/useAverageScoreQuery.ts @@ -0,0 +1,33 @@ +import { useQuery } from '@tanstack/react-query'; +import api from '../api'; +import { AverageScoreResponse } from '../../types/dashboard/averageScore'; + +/** + * 평균 자세 점수 조회 API + * GET /dashboard/average-score + */ +const getAverageScore = async (): Promise => { + const response = await api.get( + '/dashboard/average-score', + ); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '평균 점수 조회 실패'); + } + + return result; +}; + +/** + * 평균 자세 점수 조회 query 훅 + * @example + * const { data, isLoading, error } = useAverageScoreQuery(); + * const score = data?.data.score; + */ +export const useAverageScoreQuery = () => { + return useQuery({ + queryKey: ['averageScore'], + queryFn: getAverageScore, + }); +}; diff --git a/src/renderer/src/api/dashboard/useLevelQuery.ts b/src/renderer/src/api/dashboard/useLevelQuery.ts new file mode 100644 index 0000000..333b15a --- /dev/null +++ b/src/renderer/src/api/dashboard/useLevelQuery.ts @@ -0,0 +1,33 @@ +import { useQuery } from '@tanstack/react-query'; +import api from '../api'; +import { LevelResponse } from '../../types/dashboard/level'; + +/** + * 레벨 도달 현황 조회 API + * GET /dashboard/level + */ +const getLevel = async (): Promise => { + const response = await api.get('/dashboard/level'); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '레벨 조회 실패'); + } + + return result; +}; + +/** + * 레벨 도달 현황 조회 query 훅 + * @example + * const { data, isLoading, error } = useLevelQuery(); + * const level = data?.data.level; + * const current = data?.data.current; + * const required = data?.data.required; + */ +export const useLevelQuery = () => { + return useQuery({ + queryKey: ['level'], + queryFn: getLevel, + }); +}; diff --git a/src/renderer/src/api/dashboard/usePostureGraphQuery.ts b/src/renderer/src/api/dashboard/usePostureGraphQuery.ts new file mode 100644 index 0000000..0949937 --- /dev/null +++ b/src/renderer/src/api/dashboard/usePostureGraphQuery.ts @@ -0,0 +1,34 @@ +import { useQuery } from '@tanstack/react-query'; +import api from '../api'; +import { PostureGraphResponse } from '../../types/dashboard/postureGraph'; + +/** + * 바른 자세 점수 그래프 조회 API (최근 31일) + * GET /dashboard/posture-graph + */ +const getPostureGraph = async (): Promise => { + const response = await api.get( + '/dashboard/posture-graph', + ); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '자세 그래프 조회 실패'); + } + + return result; +}; + +/** + * 바른 자세 점수 그래프 조회 query 훅 + * @example + * const { data, isLoading, error } = usePostureGraphQuery(); + * const points = data?.data.points; + * // points: { "2025-01-01": 85, "2025-01-02": 92, ... } + */ +export const usePostureGraphQuery = () => { + return useQuery({ + queryKey: ['postureGraph'], + queryFn: getPostureGraph, + }); +}; diff --git a/src/renderer/src/api/login/useLoginMutation.ts b/src/renderer/src/api/login/useLoginMutation.ts index c2a9572..7b1a498 100644 --- a/src/renderer/src/api/login/useLoginMutation.ts +++ b/src/renderer/src/api/login/useLoginMutation.ts @@ -27,7 +27,17 @@ export const useLoginMutation = () => { localStorage.setItem('accessToken', res.data.accessToken); localStorage.setItem('refreshToken', res.data.refreshToken); - navigate('/onboarding'); + /* 사용자 정보 조회 후 이름 저장 */ + try { + const userResponse = await api.get('/users/me'); + if (userResponse.data.success && userResponse.data.data.name) { + localStorage.setItem('userName', userResponse.data.data.name); + } + } catch (error) { + console.error('사용자 정보 조회 실패:', error); + } + + navigate('/onboarding/init'); }, onError: (error) => { console.error('로그인 오류:', error); diff --git a/src/renderer/src/api/session/useCreateSessionMutation.ts b/src/renderer/src/api/session/useCreateSessionMutation.ts new file mode 100644 index 0000000..16868c7 --- /dev/null +++ b/src/renderer/src/api/session/useCreateSessionMutation.ts @@ -0,0 +1,42 @@ +import { useMutation } from '@tanstack/react-query'; +import api from '../api'; +import { CreateSessionResponse } from '../../types/main/session'; + +/** + * 세션 생성 API + * POST /sessions + */ +const createSession = async (): Promise => { + const response = await api.post('/sessions'); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '세션 생성 실패'); + } + + return result; +}; + +/** + * 세션 생성 mutation 훅 + * @example + * const { mutate: createSession } = useCreateSessionMutation(); + * createSession(); + */ +export const useCreateSessionMutation = () => { + return useMutation({ + mutationFn: createSession, + onSuccess: (res) => { + console.log('세션 생성 성공:', res.data.sessionId); + + // sessionId를 localStorage에 저장 + localStorage.setItem('sessionId', res.data.sessionId); + + // 이전 세션의 lastSessionId 삭제 (중복 방지) + localStorage.removeItem('lastSessionId'); + }, + onError: (error) => { + console.error('세션 생성 오류:', error); + }, + }); +}; diff --git a/src/renderer/src/api/session/usePauseSessionMutation.ts b/src/renderer/src/api/session/usePauseSessionMutation.ts new file mode 100644 index 0000000..7ced5bf --- /dev/null +++ b/src/renderer/src/api/session/usePauseSessionMutation.ts @@ -0,0 +1,41 @@ +import { useMutation } from '@tanstack/react-query'; +import api from '../api'; +import { SessionActionResponse } from '../../types/main/session'; + +/** + * 세션 일시정지 API + * PATCH /sessions/{sessionId}/pause + */ +const pauseSession = async ( + sessionId: string, +): Promise => { + const response = await api.patch( + `/sessions/${sessionId}/pause`, + ); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '세션 일시정지 실패'); + } + + return result; +}; + +/** + * 세션 일시정지 mutation 훅 + * @example + * const { mutate: pauseSession } = usePauseSessionMutation(); + * const sessionId = localStorage.getItem('sessionId'); + * pauseSession(sessionId); + */ +export const usePauseSessionMutation = () => { + return useMutation({ + mutationFn: pauseSession, + onSuccess: () => { + console.log('세션 일시정지 성공'); + }, + onError: (error) => { + console.error('세션 일시정지 오류:', error); + }, + }); +}; diff --git a/src/renderer/src/api/session/useResumeSessionMutation.ts b/src/renderer/src/api/session/useResumeSessionMutation.ts new file mode 100644 index 0000000..638cea0 --- /dev/null +++ b/src/renderer/src/api/session/useResumeSessionMutation.ts @@ -0,0 +1,41 @@ +import { useMutation } from '@tanstack/react-query'; +import api from '../api'; +import { SessionActionResponse } from '../../types/main/session'; + +/** + * 세션 재개 API + * PATCH /sessions/{sessionId}/resume + */ +const resumeSession = async ( + sessionId: string, +): Promise => { + const response = await api.patch( + `/sessions/${sessionId}/resume`, + ); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '세션 재개 실패'); + } + + return result; +}; + +/** + * 세션 재개 mutation 훅 + * @example + * const { mutate: resumeSession } = useResumeSessionMutation(); + * const sessionId = localStorage.getItem('sessionId'); + * resumeSession(sessionId); + */ +export const useResumeSessionMutation = () => { + return useMutation({ + mutationFn: resumeSession, + onSuccess: () => { + console.log('세션 재개 성공'); + }, + onError: (error) => { + console.error('세션 재개 오류:', error); + }, + }); +}; diff --git a/src/renderer/src/api/session/useSaveMetricsMutation.ts b/src/renderer/src/api/session/useSaveMetricsMutation.ts new file mode 100644 index 0000000..953ceb5 --- /dev/null +++ b/src/renderer/src/api/session/useSaveMetricsMutation.ts @@ -0,0 +1,52 @@ +import { useMutation } from '@tanstack/react-query'; +import api from '../api'; +import { + SaveMetricsRequest, + SaveMetricsResponse, +} from '../../types/main/session'; + +/** + * 세션 메트릭 저장 API + * POST /sessions/{sessionId}/metrics + */ +const saveMetrics = async ( + data: SaveMetricsRequest, +): Promise => { + const { sessionId, metrics } = data; + const response = await api.post( + `/sessions/${sessionId}/metrics`, + { sessionId, metrics }, + ); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '세션 메트릭 저장 실패'); + } + + return result; +}; + +/** + * 세션 메트릭 저장 mutation 훅 + * @example + * const { mutate: saveMetrics } = useSaveMetricsMutation(); + * const sessionId = localStorage.getItem('sessionId'); + * saveMetrics({ + * sessionId, + * metrics: [ + * { score: 0.85, timestamp: new Date().toISOString() }, + * { score: 0.92, timestamp: new Date().toISOString() } + * ] + * }); + */ +export const useSaveMetricsMutation = () => { + return useMutation({ + mutationFn: saveMetrics, + onSuccess: (res) => { + console.log('세션 메트릭 저장 성공:', res); + }, + onError: (error) => { + console.error('세션 메트릭 저장 오류:', error); + }, + }); +}; diff --git a/src/renderer/src/api/session/useSessionReportQuery.ts b/src/renderer/src/api/session/useSessionReportQuery.ts new file mode 100644 index 0000000..46d2d36 --- /dev/null +++ b/src/renderer/src/api/session/useSessionReportQuery.ts @@ -0,0 +1,45 @@ +import { useQuery } from '@tanstack/react-query'; +import api from '../api'; +import { SessionReportResponse } from '../../types/main/session'; + +/** + * 세션 리포트 조회 API + * GET /sessions/{sessionId}/report + */ +const fetchSessionReport = async ( + sessionId: string, +): Promise => { + const response = await api.get( + `/sessions/${sessionId}/report`, + ); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '세션 리포트 조회 실패'); + } + + return result; +}; + +/** + * 세션 리포트 조회 query 훅 + * @param sessionId - 조회할 세션 ID + * @param enabled - 쿼리 실행 여부 (기본값: true) + * @example + * const { data, isLoading, error } = useSessionReportQuery(sessionId); + * console.log(data?.data.totalSeconds); // 전체 시간 + * console.log(data?.data.goodSeconds); // 좋은 자세 시간 + * console.log(data?.data.score); // 점수 + */ +export const useSessionReportQuery = ( + sessionId: string | null, + enabled: boolean = true, +) => { + return useQuery({ + queryKey: ['sessionReport', sessionId], + queryFn: () => fetchSessionReport(sessionId!), + enabled: enabled && !!sessionId, // sessionId가 있을 때만 실행 + staleTime: 1000 * 60 * 5, // 5분간 데이터 신선하게 유지 + retry: 1, // 실패 시 1번만 재시도 + }); +}; diff --git a/src/renderer/src/api/session/useStopSessionMutation.ts b/src/renderer/src/api/session/useStopSessionMutation.ts new file mode 100644 index 0000000..7b3819b --- /dev/null +++ b/src/renderer/src/api/session/useStopSessionMutation.ts @@ -0,0 +1,61 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import api from '../api'; +import { SessionActionResponse } from '../../types/main/session'; + +/** + * 세션 중단 API + * PATCH /sessions/{sessionId}/stop + */ +const stopSession = async ( + sessionId: string, +): Promise => { + const response = await api.patch( + `/sessions/${sessionId}/stop`, + ); + const result = response.data; + + if (!result.success) { + throw new Error(result.message || '세션 중단 실패'); + } + + return result; +}; + +/** + * 세션 중단 mutation 훅 + * @example + * const { mutate: stopSession } = useStopSessionMutation(); + * const sessionId = localStorage.getItem('sessionId'); + * stopSession(sessionId); + */ +export const useStopSessionMutation = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: stopSession, + onSuccess: () => { + console.log('세션 중단 성공'); + + // sessionId를 lastSessionId로 백업 (ExitPanel에서 리포트 조회용) + const sessionId = localStorage.getItem('sessionId'); + if (sessionId) { + localStorage.setItem('lastSessionId', sessionId); + } + + // sessionId를 localStorage에서 제거 + localStorage.removeItem('sessionId'); + + // 평균 자세 점수 쿼리 갱신 + queryClient.invalidateQueries({ queryKey: ['averageScore'] }); + + // 레벨 쿼리 갱신 + queryClient.invalidateQueries({ queryKey: ['level'] }); + + // 자세 그래프 쿼리 갱신 + queryClient.invalidateQueries({ queryKey: ['postureGraph'] }); + }, + onError: (error) => { + console.error('세션 중단 오류:', error); + }, + }); +}; diff --git a/src/renderer/src/api/signup/signup.ts b/src/renderer/src/api/signup/signup.ts index 34b43d1..ea3b2db 100644 --- a/src/renderer/src/api/signup/signup.ts +++ b/src/renderer/src/api/signup/signup.ts @@ -1,6 +1,6 @@ import { useMutation } from '@tanstack/react-query'; -import api from '../api'; import { useNavigate } from 'react-router-dom'; +import api from '../api'; export interface SignupRequest { email: string; @@ -20,7 +20,7 @@ const duplicatedEmail = async (email: string) => { const signupUser = async (data: SignupRequest) => { const response = await api.post(`/auth/sign-up`, { ...data, - callbackUrl: `${window.location.origin}/auth/verify`, + callbackUrl: `${window.location.origin}/auth/verify-callback`, }); const result = response.data; diff --git a/src/renderer/src/api/signup/verifyEmail.ts b/src/renderer/src/api/signup/verifyEmail.ts index f988b07..d3a50be 100644 --- a/src/renderer/src/api/signup/verifyEmail.ts +++ b/src/renderer/src/api/signup/verifyEmail.ts @@ -1,6 +1,6 @@ import { useMutation } from '@tanstack/react-query'; -import api from '../api'; import { useNavigate } from 'react-router-dom'; +import api from '../api'; export interface ResendVerifyEmailRequest { email: string; diff --git a/src/renderer/src/assets/arrow-narrow-down.svg b/src/renderer/src/assets/arrow-narrow-down.svg new file mode 100644 index 0000000..8e9d0c6 --- /dev/null +++ b/src/renderer/src/assets/arrow-narrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/renderer/src/assets/arrow-narrow-up.svg b/src/renderer/src/assets/arrow-narrow-up.svg new file mode 100644 index 0000000..028e2d5 --- /dev/null +++ b/src/renderer/src/assets/arrow-narrow-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/renderer/src/assets/auth/error_icon.svg b/src/renderer/src/assets/auth/error_icon.svg index dfc21ac..f18267e 100644 --- a/src/renderer/src/assets/auth/error_icon.svg +++ b/src/renderer/src/assets/auth/error_icon.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/src/renderer/src/assets/auth/invisible_icon.svg b/src/renderer/src/assets/auth/invisible_icon.svg index 4b0ff83..fb9add6 100644 --- a/src/renderer/src/assets/auth/invisible_icon.svg +++ b/src/renderer/src/assets/auth/invisible_icon.svg @@ -1,7 +1,7 @@ - - + + diff --git a/src/renderer/src/assets/auth/saveid_icon.svg b/src/renderer/src/assets/auth/saveid_icon.svg index 79a8eb3..0466c24 100644 --- a/src/renderer/src/assets/auth/saveid_icon.svg +++ b/src/renderer/src/assets/auth/saveid_icon.svg @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/src/renderer/src/assets/auth/success_icon.svg b/src/renderer/src/assets/auth/success_icon.svg index b196113..1d4c217 100644 --- a/src/renderer/src/assets/auth/success_icon.svg +++ b/src/renderer/src/assets/auth/success_icon.svg @@ -1,10 +1,3 @@ - - - - - - - - + \ No newline at end of file diff --git a/src/renderer/src/assets/auth/visible_icon.svg b/src/renderer/src/assets/auth/visible_icon.svg index 7f6596f..2b00237 100644 --- a/src/renderer/src/assets/auth/visible_icon.svg +++ b/src/renderer/src/assets/auth/visible_icon.svg @@ -1,4 +1,4 @@ - - + + \ No newline at end of file diff --git a/src/renderer/src/assets/calendar.svg b/src/renderer/src/assets/calendar.svg new file mode 100644 index 0000000..4492bce --- /dev/null +++ b/src/renderer/src/assets/calendar.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/renderer/src/assets/calibration_guide.svg b/src/renderer/src/assets/calibration_guide.svg new file mode 100644 index 0000000..901c363 --- /dev/null +++ b/src/renderer/src/assets/calibration_guide.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/renderer/src/assets/chevron-right.svg b/src/renderer/src/assets/chevron-right.svg new file mode 100644 index 0000000..4379b60 --- /dev/null +++ b/src/renderer/src/assets/chevron-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/renderer/src/assets/clock.svg b/src/renderer/src/assets/clock.svg new file mode 100644 index 0000000..fdcbe7a --- /dev/null +++ b/src/renderer/src/assets/clock.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/renderer/src/assets/dashboard.svg b/src/renderer/src/assets/dashboard.svg new file mode 100644 index 0000000..ae20c05 --- /dev/null +++ b/src/renderer/src/assets/dashboard.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/renderer/src/assets/hide.svg b/src/renderer/src/assets/hide.svg new file mode 100644 index 0000000..52f88bb --- /dev/null +++ b/src/renderer/src/assets/hide.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/renderer/src/assets/hourglass.svg b/src/renderer/src/assets/hourglass.svg new file mode 100644 index 0000000..e75f8c4 --- /dev/null +++ b/src/renderer/src/assets/hourglass.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/renderer/src/assets/info-circle.svg b/src/renderer/src/assets/info-circle.svg new file mode 100644 index 0000000..e8593a2 --- /dev/null +++ b/src/renderer/src/assets/info-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/renderer/src/assets/logo.svg b/src/renderer/src/assets/logo.svg index fc6d48c..d5e8c09 100644 --- a/src/renderer/src/assets/logo.svg +++ b/src/renderer/src/assets/logo.svg @@ -1,6 +1,6 @@ - - - - + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/main/achivement_meadl.svg b/src/renderer/src/assets/main/achivement_meadl.svg new file mode 100644 index 0000000..6e086d5 --- /dev/null +++ b/src/renderer/src/assets/main/achivement_meadl.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/main/averagePosture/step_five_character.png b/src/renderer/src/assets/main/averagePosture/step_five_character.png new file mode 100644 index 0000000..4727a51 Binary files /dev/null and b/src/renderer/src/assets/main/averagePosture/step_five_character.png differ diff --git a/src/renderer/src/assets/main/averagePosture/step_four_character.png b/src/renderer/src/assets/main/averagePosture/step_four_character.png new file mode 100644 index 0000000..405d9c1 Binary files /dev/null and b/src/renderer/src/assets/main/averagePosture/step_four_character.png differ diff --git a/src/renderer/src/assets/main/averagePosture/step_one_character.png b/src/renderer/src/assets/main/averagePosture/step_one_character.png new file mode 100644 index 0000000..ff05a4d Binary files /dev/null and b/src/renderer/src/assets/main/averagePosture/step_one_character.png differ diff --git a/src/renderer/src/assets/main/averagePosture/step_three_character.png b/src/renderer/src/assets/main/averagePosture/step_three_character.png new file mode 100644 index 0000000..dbe38e8 Binary files /dev/null and b/src/renderer/src/assets/main/averagePosture/step_three_character.png differ diff --git a/src/renderer/src/assets/main/averagePosture/step_two_character.png b/src/renderer/src/assets/main/averagePosture/step_two_character.png new file mode 100644 index 0000000..33a1809 Binary files /dev/null and b/src/renderer/src/assets/main/averagePosture/step_two_character.png differ diff --git a/src/renderer/src/assets/main/bell_icon.svg b/src/renderer/src/assets/main/bell_icon.svg new file mode 100644 index 0000000..cc82487 --- /dev/null +++ b/src/renderer/src/assets/main/bell_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/main/downward_caret.svg b/src/renderer/src/assets/main/downward_caret.svg new file mode 100644 index 0000000..c6d2e4a --- /dev/null +++ b/src/renderer/src/assets/main/downward_caret.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/main/level1_character.svg b/src/renderer/src/assets/main/level1_character.svg new file mode 100644 index 0000000..5dc636c --- /dev/null +++ b/src/renderer/src/assets/main/level1_character.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/main/minus_icon.svg b/src/renderer/src/assets/main/minus_icon.svg new file mode 100644 index 0000000..ece2def --- /dev/null +++ b/src/renderer/src/assets/main/minus_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/main/plus_icon.svg b/src/renderer/src/assets/main/plus_icon.svg new file mode 100644 index 0000000..bc302f8 --- /dev/null +++ b/src/renderer/src/assets/main/plus_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/moon_icon.svg b/src/renderer/src/assets/moon_icon.svg new file mode 100644 index 0000000..91c78ce --- /dev/null +++ b/src/renderer/src/assets/moon_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/fifth_progress_icon.svg b/src/renderer/src/assets/onboarding/fifth_progress_icon.svg new file mode 100644 index 0000000..cf52bc5 --- /dev/null +++ b/src/renderer/src/assets/onboarding/fifth_progress_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/first_dark_image.png b/src/renderer/src/assets/onboarding/first_dark_image.png new file mode 100644 index 0000000..70b2cae Binary files /dev/null and b/src/renderer/src/assets/onboarding/first_dark_image.png differ diff --git a/src/renderer/src/assets/onboarding/first_image.png b/src/renderer/src/assets/onboarding/first_image.png new file mode 100644 index 0000000..a0e6952 Binary files /dev/null and b/src/renderer/src/assets/onboarding/first_image.png differ diff --git a/src/renderer/src/assets/onboarding/first_progress_icon.svg b/src/renderer/src/assets/onboarding/first_progress_icon.svg new file mode 100644 index 0000000..d362daf --- /dev/null +++ b/src/renderer/src/assets/onboarding/first_progress_icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/fourth_dark_image.png b/src/renderer/src/assets/onboarding/fourth_dark_image.png new file mode 100644 index 0000000..639b8e6 Binary files /dev/null and b/src/renderer/src/assets/onboarding/fourth_dark_image.png differ diff --git a/src/renderer/src/assets/onboarding/fourth_image.png b/src/renderer/src/assets/onboarding/fourth_image.png new file mode 100644 index 0000000..613e653 Binary files /dev/null and b/src/renderer/src/assets/onboarding/fourth_image.png differ diff --git a/src/renderer/src/assets/onboarding/fourth_progress_icon.svg b/src/renderer/src/assets/onboarding/fourth_progress_icon.svg new file mode 100644 index 0000000..b86556e --- /dev/null +++ b/src/renderer/src/assets/onboarding/fourth_progress_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/giraffe.svg b/src/renderer/src/assets/onboarding/giraffe.svg new file mode 100644 index 0000000..dc076dd --- /dev/null +++ b/src/renderer/src/assets/onboarding/giraffe.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/prev_icon.svg b/src/renderer/src/assets/onboarding/prev_icon.svg new file mode 100644 index 0000000..1a548ea --- /dev/null +++ b/src/renderer/src/assets/onboarding/prev_icon.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/rock_icon.svg b/src/renderer/src/assets/onboarding/rock_icon.svg new file mode 100644 index 0000000..57a7c89 --- /dev/null +++ b/src/renderer/src/assets/onboarding/rock_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/second_dark_image.png b/src/renderer/src/assets/onboarding/second_dark_image.png new file mode 100644 index 0000000..931f129 Binary files /dev/null and b/src/renderer/src/assets/onboarding/second_dark_image.png differ diff --git a/src/renderer/src/assets/onboarding/second_image.png b/src/renderer/src/assets/onboarding/second_image.png new file mode 100644 index 0000000..c7e8f2d Binary files /dev/null and b/src/renderer/src/assets/onboarding/second_image.png differ diff --git a/src/renderer/src/assets/onboarding/second_progress_icon.svg b/src/renderer/src/assets/onboarding/second_progress_icon.svg new file mode 100644 index 0000000..1c205b5 --- /dev/null +++ b/src/renderer/src/assets/onboarding/second_progress_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/third_dark_image.png b/src/renderer/src/assets/onboarding/third_dark_image.png new file mode 100644 index 0000000..7c6e1aa Binary files /dev/null and b/src/renderer/src/assets/onboarding/third_dark_image.png differ diff --git a/src/renderer/src/assets/onboarding/third_image.png b/src/renderer/src/assets/onboarding/third_image.png new file mode 100644 index 0000000..8d6b497 Binary files /dev/null and b/src/renderer/src/assets/onboarding/third_image.png differ diff --git a/src/renderer/src/assets/onboarding/third_progress_icon.svg b/src/renderer/src/assets/onboarding/third_progress_icon.svg new file mode 100644 index 0000000..07cdc24 --- /dev/null +++ b/src/renderer/src/assets/onboarding/third_progress_icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/assets/onboarding/turtle.svg b/src/renderer/src/assets/onboarding/turtle.svg new file mode 100644 index 0000000..ae574dd --- /dev/null +++ b/src/renderer/src/assets/onboarding/turtle.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/page-move-button.svg b/src/renderer/src/assets/page-move-button.svg new file mode 100644 index 0000000..c41b4da --- /dev/null +++ b/src/renderer/src/assets/page-move-button.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/renderer/src/assets/plan.svg b/src/renderer/src/assets/plan.svg new file mode 100644 index 0000000..fbefe95 --- /dev/null +++ b/src/renderer/src/assets/plan.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/renderer/src/assets/profile.svg b/src/renderer/src/assets/profile.svg new file mode 100644 index 0000000..12ae21d --- /dev/null +++ b/src/renderer/src/assets/profile.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/renderer/src/assets/setting.svg b/src/renderer/src/assets/setting.svg new file mode 100644 index 0000000..0886f41 --- /dev/null +++ b/src/renderer/src/assets/setting.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/renderer/src/assets/show.svg b/src/renderer/src/assets/show.svg new file mode 100644 index 0000000..ee6b650 --- /dev/null +++ b/src/renderer/src/assets/show.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/renderer/src/assets/sleep.svg b/src/renderer/src/assets/sleep.svg new file mode 100644 index 0000000..9997837 --- /dev/null +++ b/src/renderer/src/assets/sleep.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/renderer/src/assets/sun_icon.svg b/src/renderer/src/assets/sun_icon.svg new file mode 100644 index 0000000..ca4459f --- /dev/null +++ b/src/renderer/src/assets/sun_icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/symbol.svg b/src/renderer/src/assets/symbol.svg new file mode 100644 index 0000000..faa799f --- /dev/null +++ b/src/renderer/src/assets/symbol.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/renderer/src/assets/thumbup.svg b/src/renderer/src/assets/thumbup.svg new file mode 100644 index 0000000..643bbaf --- /dev/null +++ b/src/renderer/src/assets/thumbup.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/renderer/src/assets/video/angel-rini.webm b/src/renderer/src/assets/video/angel-rini.webm new file mode 100644 index 0000000..a06676c Binary files /dev/null and b/src/renderer/src/assets/video/angel-rini.webm differ diff --git a/src/renderer/src/assets/video/background.webm b/src/renderer/src/assets/video/background.webm new file mode 100644 index 0000000..30f2623 Binary files /dev/null and b/src/renderer/src/assets/video/background.webm differ diff --git a/src/renderer/src/assets/video/bugi.webm b/src/renderer/src/assets/video/bugi.webm new file mode 100644 index 0000000..4f9d9c2 Binary files /dev/null and b/src/renderer/src/assets/video/bugi.webm differ diff --git a/src/renderer/src/assets/video/pm-rini.webm b/src/renderer/src/assets/video/pm-rini.webm new file mode 100644 index 0000000..7214a08 Binary files /dev/null and b/src/renderer/src/assets/video/pm-rini.webm differ diff --git a/src/renderer/src/assets/video/rini.webm b/src/renderer/src/assets/video/rini.webm new file mode 100644 index 0000000..9b0f7d6 Binary files /dev/null and b/src/renderer/src/assets/video/rini.webm differ diff --git a/src/renderer/src/assets/video/stone-bugi.webm b/src/renderer/src/assets/video/stone-bugi.webm new file mode 100644 index 0000000..eaa6530 Binary files /dev/null and b/src/renderer/src/assets/video/stone-bugi.webm differ diff --git a/src/renderer/src/assets/video/tire-bugi.webm b/src/renderer/src/assets/video/tire-bugi.webm new file mode 100644 index 0000000..cbe8893 Binary files /dev/null and b/src/renderer/src/assets/video/tire-bugi.webm differ diff --git a/src/renderer/src/assets/widget.svg b/src/renderer/src/assets/widget.svg new file mode 100644 index 0000000..c88ea3b --- /dev/null +++ b/src/renderer/src/assets/widget.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/renderer/src/assets/widget/drag_icon.svg b/src/renderer/src/assets/widget/drag_icon.svg new file mode 100644 index 0000000..4a96574 --- /dev/null +++ b/src/renderer/src/assets/widget/drag_icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/widget/medium_giraffe.svg b/src/renderer/src/assets/widget/medium_giraffe.svg new file mode 100644 index 0000000..5a2da2d --- /dev/null +++ b/src/renderer/src/assets/widget/medium_giraffe.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/widget/medium_turtle.svg b/src/renderer/src/assets/widget/medium_turtle.svg new file mode 100644 index 0000000..63a823c --- /dev/null +++ b/src/renderer/src/assets/widget/medium_turtle.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/widget/mini_drag_icon.svg b/src/renderer/src/assets/widget/mini_drag_icon.svg new file mode 100644 index 0000000..98d36c7 --- /dev/null +++ b/src/renderer/src/assets/widget/mini_drag_icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/widget/mini_giraffe.svg b/src/renderer/src/assets/widget/mini_giraffe.svg new file mode 100644 index 0000000..fcce860 --- /dev/null +++ b/src/renderer/src/assets/widget/mini_giraffe.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/widget/mini_turtle.svg b/src/renderer/src/assets/widget/mini_turtle.svg new file mode 100644 index 0000000..5b06dc0 --- /dev/null +++ b/src/renderer/src/assets/widget/mini_turtle.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/renderer/src/assets/widget/widgetbutton.svg b/src/renderer/src/assets/widget/widgetbutton.svg new file mode 100644 index 0000000..f890b68 --- /dev/null +++ b/src/renderer/src/assets/widget/widgetbutton.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/renderer/src/components/Button/Button.tsx b/src/renderer/src/components/Button/Button.tsx index 0c00c43..2e1ea7a 100644 --- a/src/renderer/src/components/Button/Button.tsx +++ b/src/renderer/src/components/Button/Button.tsx @@ -4,13 +4,16 @@ import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '../../utils/cn'; const buttonVariants = cva( - 'inline-flex items-center justify-center rounded-full transition-colors focus-visible:outline-none disabled:cursor-not-allowed', + 'inline-flex items-center justify-center rounded-full transition-colors focus-visible:outline-none disabled:cursor-not-allowed active:scale-95', { variants: { variant: { primary: 'bg-yellow-400 text-grey-1000 hover:bg-yellow-500 active:bg-yellow-600 disabled:bg-yellow-100 disabled:text-grey-0 cursor-pointer', + sub: 'bg-yellow-50 text-yellow-500 hover:bg-yellow-100 active:bg-yellow-200 active:text-yellow-600 cursor-pointer', + grey: 'bg-grey-25 text-grey-500 hover:bg-grey-50 active:bg-grey-100 active:text-grey-300 cursor-pointer disabled:bg-grey-25 disabled:text-grey-100', }, + size: { xs: 'h-[33px] px-3 text-caption-sm-medium', sm: 'h-10 px-4 text-body-md-medium', @@ -29,7 +32,7 @@ const buttonVariants = cva( export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { - text?: string; + text?: React.ReactNode; } const Button = React.forwardRef( diff --git a/src/renderer/src/components/DevNavbar/DevNavbar.tsx b/src/renderer/src/components/DevNavbar/DevNavbar.tsx index 53bfada..6fc65f1 100644 --- a/src/renderer/src/components/DevNavbar/DevNavbar.tsx +++ b/src/renderer/src/components/DevNavbar/DevNavbar.tsx @@ -1,9 +1,11 @@ +import { useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; const DevNavbar = () => { const navigate = useNavigate(); const location = useLocation(); const isDev = import.meta.env.DEV; + const [isWidgetOpen, setIsWidgetOpen] = useState(false); // 개발 모드가 아니면 렌더링하지 않음 if (!isDev) return null; @@ -16,8 +18,25 @@ const DevNavbar = () => { { path: '/onboarding/calibration', label: '캘리브레이션' }, ]; + // 위젯 토글 + const handleToggleWidget = async () => { + try { + if (window.electronAPI?.widget) { + if (isWidgetOpen) { + await window.electronAPI.widget.close(); + setIsWidgetOpen(false); + } else { + await window.electronAPI.widget.open(); + setIsWidgetOpen(true); + } + } + } catch (error) { + console.error('위젯 토글 실패:', error); + } + }; + return ( -
+
@@ -37,6 +56,18 @@ const DevNavbar = () => { {item.label} ))} + + {/* 위젯 토글 버튼 */} +
diff --git a/src/renderer/src/components/Header/Header.tsx b/src/renderer/src/components/Header/Header.tsx deleted file mode 100644 index c4b3105..0000000 --- a/src/renderer/src/components/Header/Header.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { Button } from '../Button/Button'; -import './header.css'; - -type User = { - name: string; -}; - -export interface HeaderProps { - user?: User; - onLogin?: () => void; - onLogout?: () => void; - onCreateAccount?: () => void; -} - -export const Header = ({ - user, - onLogin, - onLogout, - onCreateAccount, -}: HeaderProps) => ( -
-
-
- - - - - - - -

Acme

-
-
- {user ? ( - <> - - Welcome, {user.name}! - - - - ) : ( - <> - - - - )} -
-
-
-); diff --git a/src/renderer/src/components/Header/header.css b/src/renderer/src/components/Header/header.css deleted file mode 100644 index 5efd46c..0000000 --- a/src/renderer/src/components/Header/header.css +++ /dev/null @@ -1,32 +0,0 @@ -.storybook-header { - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - padding: 15px 20px; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-header svg { - display: inline-block; - vertical-align: top; -} - -.storybook-header h1 { - display: inline-block; - vertical-align: top; - margin: 6px 0 6px 10px; - font-weight: 700; - font-size: 20px; - line-height: 1; -} - -.storybook-header button + button { - margin-left: 10px; -} - -.storybook-header .welcome { - margin-right: 10px; - color: #333; - font-size: 14px; -} diff --git a/src/renderer/src/components/InputField/TextField.tsx b/src/renderer/src/components/InputField/TextField.tsx index 613b213..672762d 100644 --- a/src/renderer/src/components/InputField/TextField.tsx +++ b/src/renderer/src/components/InputField/TextField.tsx @@ -1,4 +1,4 @@ -import { forwardRef } from 'react'; +import { forwardRef, type ChangeEvent, type FocusEvent } from 'react'; interface TextFieldProps { id?: string; @@ -7,9 +7,9 @@ interface TextFieldProps { value?: string; disabled?: boolean; maxLength?: number; - onChange?: (e: React.ChangeEvent) => void; - onFocus?: (e: React.FocusEvent) => void; - onBlur?: (e: React.FocusEvent) => void; + onChange?: (e: ChangeEvent) => void; + onFocus?: (e: FocusEvent) => void; + onBlur?: (e: FocusEvent) => void; className?: string; name?: string; } @@ -44,7 +44,7 @@ const TextField = forwardRef( onChange={onChange} onFocus={onFocus} onBlur={onBlur} - className={`flex aspect-[44/6] w-full cursor-pointer flex-row rounded-full border border-[#E3E1DF] bg-[#ffffff] px-6 outline-none focus:border-yellow-500 ${className}`} + className={`border-grey-100 bg-grey-0 text-grey-700 flex aspect-[44/6] w-full cursor-pointer flex-row rounded-full border px-6 outline-none focus:border-yellow-500 ${className}`} /> ); }, diff --git a/src/renderer/src/components/IntensitySlider/IntensitySlider.tsx b/src/renderer/src/components/IntensitySlider/IntensitySlider.tsx new file mode 100644 index 0000000..034286f --- /dev/null +++ b/src/renderer/src/components/IntensitySlider/IntensitySlider.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; +import { cn } from '../../utils/cn'; + +interface IntensitySliderProps { + leftLabel?: string; + rightLabel?: string; +} + +const LEVEL_COLORS = [ + 'bg-yellow-50', // 가장 옅은 크림색 + 'bg-yellow-100', // 옅은 노란색 + 'bg-yellow-200', // 중간 노란색 + 'bg-yellow-400', // 밝은 노란색/주황빛 + 'bg-yellow-500', // 가장 진한 주황색/노란색 +] as const; + +const IntensitySlider = React.forwardRef( + ({ leftLabel = 'Less', rightLabel = 'More' }, ref) => { + return ( +
+ + {leftLabel} + + +
+ {LEVEL_COLORS.map((color, index) => ( +
+ ))} +
+ + + {rightLabel} + +
+ ); + }, +); + +IntensitySlider.displayName = 'IntensitySlider'; +export { IntensitySlider }; diff --git a/src/renderer/src/components/Modal/ModalPortal.ts b/src/renderer/src/components/Modal/ModalPortal.ts new file mode 100644 index 0000000..71a2858 --- /dev/null +++ b/src/renderer/src/components/Modal/ModalPortal.ts @@ -0,0 +1,15 @@ +//ModalPortal를 생성한다. +import { ReactNode } from 'react'; +import ReactDOM from 'react-dom'; +interface ModalPortalProps { + children: ReactNode; +} + +export const ModalPortal = ({ children }: ModalPortalProps) => { + const el = document.getElementById('modal'); + if (!el) { + console.error("Modal container with id 'modal' not found!"); + return null; + } + return ReactDOM.createPortal(children, el); +}; diff --git a/src/renderer/src/components/Modal/NotificationModal.tsx b/src/renderer/src/components/Modal/NotificationModal.tsx new file mode 100644 index 0000000..f024c14 --- /dev/null +++ b/src/renderer/src/components/Modal/NotificationModal.tsx @@ -0,0 +1,116 @@ +import { NotificationToggleSwitch } from '@ui/ToggleSwitch/NotificationToggleSwitch'; +import { useState } from 'react'; +import { useTimeEditor } from './hooks/useTimeEditor'; +import { TimeControlSection } from './components/TimeControlSection'; +import { Button } from '@ui/Button/Button'; +import { useNotificationStore } from '../../store/useNotificationStore'; + +interface NotificationModalProps { + onClose: () => void; +} + +const NotificationModal = ({ onClose }: NotificationModalProps) => { + const store = useNotificationStore(); + + /* 알림 허용 */ + const [isAllow, setIsAllow] = useState(store.isAllow); + + /* 스트레칭 주기 */ + const [isStretchingEnabled, setIsStretchingEnabled] = useState( + store.stretching.isEnabled, + ); + const stretching = useTimeEditor({ + initialTime: store.stretching.interval, + isEnabled: isAllow && isStretchingEnabled, + }); + + /* 거북목 경고 */ + const [isTurtleNeckEnabled, setIsTurtleNeckEnabled] = useState( + store.turtleNeck.isEnabled, + ); + const turtleNeck = useTimeEditor({ + initialTime: store.turtleNeck.interval, + isEnabled: isAllow && isTurtleNeckEnabled, + }); + + /* 저장하기 핸들러 - 알림 허용, 스트레칭, 거북목 시간 간격 전역 저장 */ + const handleSave = async () => { + store.setSettings({ + isAllow, + stretching: { + isEnabled: isStretchingEnabled, + interval: stretching.time, + }, + turtleNeck: { + isEnabled: isTurtleNeckEnabled, + interval: turtleNeck.time, + }, + }); + + /* 알림 권한 요청 (처음 활성화하는 경우) */ + if (isAllow) { + try { + await window.electronAPI.notification.requestPermission(); + } catch (error) { + console.error('Failed to request notification permission:', error); + } + } + onClose(); + }; + + return ( + <> +
+
e.stopPropagation()} + > + {/* 알림 허용 */} +
+ + 알림 허용 + + setIsAllow(!isAllow)} + /> +
+ + {/* 맞춤 스트레칭 주기 */} + setIsStretchingEnabled(!isStretchingEnabled)} + isDisabled={!isAllow} + timeEditor={stretching} + /> + + {/* 거북목 경고 */} + setIsTurtleNeckEnabled(!isTurtleNeckEnabled)} + isDisabled={!isAllow} + timeEditor={turtleNeck} + /> + + {/* 저장하기 버튼 */} +
+
+ + ); +}; + +export default NotificationModal; diff --git a/src/renderer/src/components/Modal/components/TimeControlSection.tsx b/src/renderer/src/components/Modal/components/TimeControlSection.tsx new file mode 100644 index 0000000..94ddba3 --- /dev/null +++ b/src/renderer/src/components/Modal/components/TimeControlSection.tsx @@ -0,0 +1,91 @@ +import { NotificationToggleSwitch } from '@ui/ToggleSwitch/NotificationToggleSwitch'; +import { useTimeEditor } from '../hooks/useTimeEditor'; +import MinusIcon from '../../../assets/main/minus_icon.svg?react'; +import PlusIcon from '../../../assets/main/plus_icon.svg?react'; + +interface TimeControlSectionProps { + title: string; + description: string; + isEnabled: boolean; + onToggle: () => void; + isDisabled?: boolean; + timeEditor: ReturnType; +} + +export const TimeControlSection = ({ + title, + description, + isEnabled, + onToggle, + isDisabled = false, + timeEditor, +}: TimeControlSectionProps) => { + return ( +
+ {/* 헤더 */} +
+ {title} + +
+ + {/* 설명 */} + + {description} + + + {/* 시간 조절 UI */} +
+ {/* 감소 버튼 */} + + + {/* 시간 표시/입력 */} + {timeEditor.isEditing ? ( + + ) : ( +
+ {timeEditor.time}분 +
+ )} + + {/* 증가 버튼 */} + +
+
+ ); +}; diff --git a/src/renderer/src/components/Modal/hooks/useTimeEditor.ts b/src/renderer/src/components/Modal/hooks/useTimeEditor.ts new file mode 100644 index 0000000..6e9e382 --- /dev/null +++ b/src/renderer/src/components/Modal/hooks/useTimeEditor.ts @@ -0,0 +1,79 @@ +import { useState, useRef, useEffect } from 'react'; + +interface UseTimeEditorProps { + initialTime: number; + isEnabled: boolean; +} + +export const useTimeEditor = ({ + initialTime, + isEnabled, +}: UseTimeEditorProps) => { + const [time, setTime] = useState(initialTime); + const [isEditing, setIsEditing] = useState(false); + const [tempTime, setTempTime] = useState(initialTime.toString()); + const inputRef = useRef(null); + + /* 편집 시작 시 포커스 */ + useEffect(() => { + if (isEditing && inputRef.current) { + inputRef.current.focus(); + inputRef.current.select(); + } + }, [isEditing]); + + /* 시간 클릭 (편집 모드 진입) */ + const handleTimeClick = () => { + if (isEnabled) { + setTempTime(time.toString()); + setIsEditing(true); + } + }; + + /* 시간 입력 변경 */ + const handleTimeChange = (e: React.ChangeEvent) => { + const value = e.target.value.replace(/[^0-9]/g, ''); + setTempTime(value); + }; + + /* 시간 제출 */ + const handleTimeSubmit = () => { + const newTime = Math.min(300, Math.max(1, parseInt(tempTime) || 1)); + setTime(newTime); + setIsEditing(false); + }; + + /* 시간 키 입력 */ + const handleTimeKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + handleTimeSubmit(); + } else if (e.key === 'Escape') { + setIsEditing(false); + } + }; + + /* 시간 증가 (최대 300분) */ + const increaseTime = () => { + setTime((prev) => Math.min(300, prev + 1)); + }; + + /* 시간 감소 */ + const decreaseTime = () => { + setTime((prev) => Math.max(1, prev - 1)); + }; + + return { + time, + isEditing, + tempTime, + inputRef, + handlers: { + handleTimeClick, + handleTimeChange, + handleTimeSubmit, + handleTimeKeyDown, + increaseTime, + decreaseTime, + }, + }; +}; diff --git a/src/renderer/src/components/NotificateMessage/NotificateMessage.stories.tsx b/src/renderer/src/components/NotificateMessage/NotificateMessage.stories.tsx deleted file mode 100644 index 4e102e3..0000000 --- a/src/renderer/src/components/NotificateMessage/NotificateMessage.stories.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { NotificateMessage } from './NotificateMessage'; - -const meta: Meta = { - title: 'UI/NotificateMessage', - component: NotificateMessage, - parameters: { - layout: 'centered', - }, - tags: ['autodocs'], - argTypes: { - variant: { - control: { type: 'select' }, - options: ['default', 'fail', 'success'], - }, - }, -}; - -export default meta; -type Story = StoryObj; - -// 기본 메시지 (스텝 번호 포함) -export const Default: Story = { - args: { - step: 1, - message: '의자에 편안히 앉아 허리를 펴고 턱을 당겨주세요.', - }, -}; - -// 에러 단계 (기본 상태 + 에러 메시지) -export const ErrorStep: Story = { - args: { - variant: 'default', - step: 1, - message: '의자에 편안히 앉아 허리를 펴고 턱을 당겨주세요.', - errorMessage: '허리를 의자에 더 가까이 다가가주세요.', - }, -}; - -// 성공 메시지 -export const Success: Story = { - args: { - variant: 'success', - message: '의자에 편안히 앉아 허리를 펴고 턱을 당겨주세요.', - }, -}; - -// 긴 메시지 -export const LongMessage: Story = { - args: { - variant: 'default', - message: - '이것은 매우 긴 메시지입니다. 실제 사용 시에는 사용자에게 중요한 정보를 전달하는 메시지가 들어갈 것입니다. 알림 메시지는 사용자에게 명확하고 간결한 정보를 제공해야 합니다.', - }, -}; - -// 모든 변형을 보여주는 그리드 -export const AllVariants: Story = { - render: () => ( -
- - - -
- ), -}; diff --git a/src/renderer/src/components/PageMoveButton/PageMoveButton.tsx b/src/renderer/src/components/PageMoveButton/PageMoveButton.tsx new file mode 100644 index 0000000..0951a10 --- /dev/null +++ b/src/renderer/src/components/PageMoveButton/PageMoveButton.tsx @@ -0,0 +1,44 @@ +import PageMoveIcon from '@assets/page-move-button.svg?react'; +import * as React from 'react'; +import { cn } from '../../utils/cn'; + +interface PageMoveButtonProps { + direction?: 'prev' | 'next'; + onClick?: () => void; + disabled?: boolean; +} + +const PageMoveButton = React.forwardRef( + ({ direction = 'prev', onClick, disabled = false }, ref) => { + return ( + + ); + }, +); + +PageMoveButton.displayName = 'PageMoveButton'; +export { PageMoveButton }; diff --git a/src/renderer/src/components/PannelHeader/PannelHeader.tsx b/src/renderer/src/components/PannelHeader/PannelHeader.tsx new file mode 100644 index 0000000..84917bd --- /dev/null +++ b/src/renderer/src/components/PannelHeader/PannelHeader.tsx @@ -0,0 +1,23 @@ +import InfoIcon from '@assets/info-circle.svg?react'; +import * as React from 'react'; + +interface PannelHeaderProps { + children?: React.ReactNode; +} + +const PannelHeader = React.forwardRef( + ({ children }, ref) => { + return ( +
+ {children} + +
+ ); + }, +); + +PannelHeader.displayName = 'PannelHeader'; +export { PannelHeader }; diff --git a/src/renderer/src/components/ThemeToggleSwitch/ThemeToggleSwitch.tsx b/src/renderer/src/components/ThemeToggleSwitch/ThemeToggleSwitch.tsx new file mode 100644 index 0000000..9924445 --- /dev/null +++ b/src/renderer/src/components/ThemeToggleSwitch/ThemeToggleSwitch.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import MoonIcon from '../../assets/moon_icon.svg?react'; +import SunIcon from '../../assets/sun_icon.svg?react'; +import { cn } from '../../utils/cn'; + +interface ThemeToggleSwitchProps { + checked: boolean; + onChange: (checked: boolean) => void; +} + +const ThemeToggleSwitch = React.forwardRef< + HTMLButtonElement, + ThemeToggleSwitchProps +>(({ checked, onChange }, ref) => { + return ( + + ); +}); + +ThemeToggleSwitch.displayName = 'ThemeToggleSwitch'; +export { ThemeToggleSwitch }; diff --git a/src/renderer/src/components/Timer/Timer.stories.tsx b/src/renderer/src/components/Timer/Timer.stories.tsx deleted file mode 100644 index 9cd60a2..0000000 --- a/src/renderer/src/components/Timer/Timer.stories.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import Timer from './Timer'; - -const meta: Meta = { - title: 'UI/Timer', - component: Timer, - parameters: { layout: 'centered' }, - tags: ['autodocs'], - argTypes: { - value: { - control: { type: 'number', min: 0, max: 5 }, - description: '카운트다운 값 (5 -> 4 -> 3 -> 2 -> 1 -> 0)', - }, - size: { - control: { type: 'number' }, - description: '타이머 크기 (기본: 100)', - }, - on: { - control: { type: 'color' }, - description: '하이라이트 색상', - }, - off: { - control: { type: 'color' }, - description: '비활성 색상', - }, - }, - args: { - value: 5, - size: 100, - on: '#FFBF00', - off: 'white', - }, -}; - -export default meta; -type Story = StoryObj; - -export const Playground: Story = {}; - -export const Countdown: Story = { - render: () => ( -
-
- - 5 -
-
- - 4 -
-
- - 3 -
-
- - 2 -
-
- - 1 -
-
- - 0 -
-
- ), -}; - -export const Sizes: Story = { - render: () => ( -
-
- - Small (48px) -
-
- - Default (100px) -
-
- - Large (160px) -
-
- - XLarge (240px) -
-
- ), -}; - -export const CustomColors: Story = { - render: () => ( -
-
- - Green on Dark -
-
- - Blue on Light -
-
- - Magenta on Purple -
-
- ), -}; diff --git a/src/renderer/src/components/Timer/Timer.tsx b/src/renderer/src/components/Timer/Timer.tsx index 35178cd..0d18904 100644 --- a/src/renderer/src/components/Timer/Timer.tsx +++ b/src/renderer/src/components/Timer/Timer.tsx @@ -2,30 +2,23 @@ type CountdownValue = 0 | 1 | 2 | 3 | 4 | 5; type Props = { value: CountdownValue; // 5 -> 4 -> 3 -> 2 -> 1 -> 0 - size?: number; // 기본 100 - on?: string; // 하이라이트 색 (기본 #FFBF00) - off?: string; // 비활성 색 (기본 white) + size?: number; // 기본 64 + on?: string; // 하이라이트 색 (기본 yellow-500) + off?: string; // 비활성 색 (기본 grey-50) }; const SEG_KEYS = ['LT', 'TOP', 'LB', 'RT', 'RB'] as const; type SegmentKey = (typeof SEG_KEYS)[number]; -/** - * 각 숫자에서 노란색으로 켜질 세그먼트 매핑 - * - LT: 좌상(왼쪽 위 곡선) - * - TOP: 상단 곡선 - * - LB: 좌하(왼쪽 아래 곡선) - * - RT: 우상(오른쪽 위 곡선) - * - RB: 우하(오른쪽 아래 곡선) - * - * 원본 SVG들을 기준으로 매핑함: - * 5: 모두 흰색 - * 4: LB만 노랑 - * 3: LT, TOP, LB 노랑 - * 2: LT, LB 노랑 - * 1: LT, TOP, LB, RT 노랑 (RB만 흰색) - * 0: 전부 노랑 - */ +// Tailwind 기준 (CSS 변수 사용해 다크/라이트 테마 자동 대응) +const DEFAULT_ON = 'var(--color-yellow-500)'; +const DEFAULT_OFF = 'var(--color-grey-50)'; + +// 배경 대비 세그먼트+숫자 확대 비율 +const SEG_SCALE = 1.6; +// 세그먼트+숫자를 살짝 위로 올리기 위한 오프셋 (뷰박스 기준) +const SEG_Y_OFFSET = -4; // 값 더 줄이면 위로 더 올라감 + const activeMap: Record = { 5: [], 4: ['LB'], @@ -35,38 +28,24 @@ const activeMap: Record = { 0: ['LT', 'TOP', 'LB', 'RT', 'RB'], }; -// 각 숫자 중앙 글리프(path) — 원본 그대로 (축약/가공 없음) -const centerPathMap: Record = { - 5: { - d: 'M50.0215 62.2148C48.9974 62.2148 48.0736 62.0251 47.25 61.6455C46.4264 61.266 45.7747 60.7432 45.2949 60.0771C44.8223 59.404 44.5716 58.6413 44.543 57.7891H47.2715C47.3001 58.2044 47.4362 58.5768 47.6797 58.9062C47.9303 59.2357 48.2598 59.4935 48.668 59.6797C49.0833 59.8659 49.5345 59.959 50.0215 59.959C50.5944 59.959 51.1064 59.8301 51.5576 59.5723C52.016 59.3145 52.3704 58.96 52.6211 58.5088C52.8789 58.0505 53.0078 57.5384 53.0078 56.9727C53.0078 56.3854 52.8753 55.8626 52.6104 55.4043C52.3454 54.9388 51.9801 54.5771 51.5146 54.3193C51.0492 54.0544 50.5228 53.9219 49.9355 53.9219C48.7038 53.9004 47.8444 54.3444 47.3574 55.2539H44.7578L45.7031 46.4453H54.8984V48.7871H48.002L47.5293 52.9121H47.6797C47.9876 52.5612 48.4102 52.2783 48.9473 52.0635C49.4844 51.8415 50.0645 51.7305 50.6875 51.7305C51.64 51.7305 52.4993 51.9525 53.2656 52.3965C54.0319 52.8405 54.6299 53.4564 55.0596 54.2441C55.4964 55.0247 55.7148 55.9056 55.7148 56.8867C55.7148 57.9108 55.4714 58.8275 54.9844 59.6367C54.5046 60.446 53.8314 61.0798 52.9648 61.5381C52.1055 61.9893 51.1243 62.2148 50.0215 62.2148Z', - }, - 4: { - d: 'M43.3555 59.8359V57.3984L50.6914 46.0312H54.4883V57.3281H56.7148V59.8359H54.4883V63H51.582V59.8359H43.3555ZM46.4727 57.3281H51.6289V49.5H51.4414L46.4727 57.2109V57.3281Z', - }, - 3: { - d: 'M49.9219 63.2214C46.2891 63.2214 43.7109 61.2527 43.6406 58.3933H46.7109C46.8047 59.7527 48.1641 60.6433 49.9219 60.6433C51.7969 60.6433 53.1328 59.6121 53.1328 58.1121C53.1328 56.5886 51.8203 55.4871 49.6172 55.4871H48.0938V53.1433H49.6172C51.4219 53.1433 52.6875 52.1355 52.6641 50.6589C52.6875 49.2292 51.6094 48.2683 49.9453 48.2683C48.3516 48.2683 46.9688 49.1589 46.9219 50.5886H43.9922C44.0625 47.7292 46.6406 45.7839 49.9688 45.7839C53.4141 45.7839 55.6406 47.8933 55.6172 50.4949C55.6406 52.3933 54.375 53.7761 52.5234 54.1511V54.2917C54.9141 54.6199 56.2734 56.1433 56.25 58.2761C56.2734 61.1355 53.6016 63.2214 49.9219 63.2214Z', - }, - 2: { - d: 'M44.6758 63V60.7969L50.6758 55.0078C52.3867 53.2969 53.2773 52.2891 53.2773 50.8594C53.2773 49.2891 52.0352 48.2812 50.3711 48.2812C48.6133 48.2812 47.4883 49.3828 47.5117 51.0938H44.6055C44.582 47.8828 46.9961 45.7969 50.3945 45.7969C53.8633 45.7969 56.207 47.8594 56.207 50.7188C56.207 52.6406 55.2695 54.1875 51.9414 57.3281L48.918 60.3281V60.4453H56.4648V63H44.6758Z', - }, - 1: { - d: 'M52.7227 46.0184V62.9872H49.6523V48.995H49.5586L45.5977 51.5262V48.7372L49.793 46.0184H52.7227Z', - }, - 0: { - d: 'M50 62.2344C48.6406 62.2344 47.4727 61.8945 46.4961 61.2148C45.5273 60.5273 44.7812 59.5312 44.2578 58.2266C43.7422 56.9219 43.4844 55.3516 43.4844 53.5156C43.4844 51.6875 43.7422 50.1211 44.2578 48.8164C44.7812 47.5039 45.5312 46.5078 46.5078 45.8281C47.4844 45.1406 48.6484 44.7969 50 44.7969C51.3438 44.7969 52.5039 45.1406 53.4805 45.8281C54.4648 46.5078 55.2148 47.5039 55.7305 48.8164C56.2539 50.1211 56.5156 51.6875 56.5156 53.5156C56.5156 55.3516 56.2539 56.9219 55.7305 58.2266C55.2148 59.5312 54.4688 60.5273 53.4922 61.2148C52.5234 61.8945 51.3594 62.2344 50 62.2344ZM50 59.6797C50.7188 59.6797 51.332 59.4492 51.8398 58.9883C52.3555 58.5195 52.75 57.8281 53.0234 56.9141C53.3047 55.9922 53.4453 54.8594 53.4453 53.5156C53.4453 52.1875 53.3047 51.0625 53.0234 50.1406C52.75 49.2109 52.3555 48.5117 51.8398 48.043C51.3242 47.5664 50.7109 47.3281 50 47.3281C49.2891 47.3281 48.6758 47.5664 48.1602 48.043C47.6445 48.5117 47.2461 49.2109 46.9648 50.1406C46.6914 51.0625 46.5547 52.1875 46.5547 53.5156C46.5547 54.8594 46.6914 55.9922 46.9648 56.9141C47.2461 57.8281 47.6406 58.5195 48.1484 58.9883C48.6641 59.4492 49.2812 59.6797 50 59.6797Z', - fill: '#FFBF00', - }, +const centerPathMap: Record = { + 5: 'M50.0215 62.2148C48.9974 62.2148 48.0736 62.0251 47.25 61.6455C46.4264 61.266 45.7747 60.7432 45.2949 60.0771C44.8223 59.404 44.5716 58.6413 44.543 57.7891H47.2715C47.3001 58.2044 47.4362 58.5768 47.6797 58.9062C47.9303 59.2357 48.2598 59.4935 48.668 59.6797C49.0833 59.8659 49.5345 59.959 50.0215 59.959C50.5944 59.959 51.1064 59.8301 51.5576 59.5723C52.016 59.3145 52.3704 58.96 52.6211 58.5088C52.8789 58.0505 53.0078 57.5384 53.0078 56.9727C53.0078 56.3854 52.8753 55.8626 52.6104 55.4043C52.3454 54.9388 51.9801 54.5771 51.5146 54.3193C51.0492 54.0544 50.5228 53.9219 49.9355 53.9219C48.7038 53.9004 47.8444 54.3444 47.3574 55.2539H44.7578L45.7031 46.4453H54.8984V48.7871H48.002L47.5293 52.9121H47.6797C47.9876 52.5612 48.4102 52.2783 48.9473 52.0635C49.4844 51.8415 50.0645 51.7305 50.6875 51.7305C51.64 51.7305 52.4993 51.9525 53.2656 52.3965C54.0319 52.8405 54.6299 53.4564 55.0596 54.2441C55.4964 55.0247 55.7148 55.9056 55.7148 56.8867C55.7148 57.9108 55.4714 58.8275 54.9844 59.6367C54.5046 60.446 53.8314 61.0798 52.9648 61.5381C52.1055 61.9893 51.1243 62.2148 50.0215 62.2148Z', + 4: 'M43.3555 59.8359V57.3984L50.6914 46.0312H54.4883V57.3281H56.7148V59.8359H54.4883V63H51.582V59.8359H43.3555ZM46.4727 57.3281H51.6289V49.5H51.4414L46.4727 57.2109V57.3281Z', + 3: 'M49.9219 63.2214C46.2891 63.2214 43.7109 61.2527 43.6406 58.3933H46.7109C46.8047 59.7527 48.1641 60.6433 49.9219 60.6433C51.7969 60.6433 53.1328 59.6121 53.1328 58.1121C53.1328 56.5886 51.8203 55.4871 49.6172 55.4871H48.0938V53.1433H49.6172C51.4219 53.1433 52.6875 52.1355 52.6641 50.6589C52.6875 49.2292 51.6094 48.2683 49.9453 48.2683C48.3516 48.2683 46.9688 49.1589 46.9219 50.5886H43.9922C44.0625 47.7292 46.6406 45.7839 49.9688 45.7839C53.4141 45.7839 55.6406 47.8933 55.6172 50.4949C55.6406 52.3933 54.375 53.7761 52.5234 54.1511V54.2917C54.9141 54.6199 56.2734 56.1433 56.25 58.2761C56.2734 61.1355 53.6016 63.2214 49.9219 63.2214Z', + 2: 'M44.6758 63V60.7969L50.6758 55.0078C52.3867 53.2969 53.2773 52.2891 53.2773 50.8594C53.2773 49.2891 52.0352 48.2812 50.3711 48.2812C48.6133 48.2812 47.4883 49.3828 47.5117 51.0938H44.6055C44.582 47.8828 46.9961 45.7969 50.3945 45.7969C53.8633 45.7969 56.207 47.8594 56.207 50.7188C56.207 52.6406 55.2695 54.1875 51.9414 57.3281L48.918 60.3281V60.4453H56.4648V63H44.6758Z', + 1: 'M52.7227 46.0184V62.9872H49.6523V48.995H49.5586L45.5977 51.5262V48.7372L49.793 46.0184H52.7227Z', + 0: 'M50 62.2344C48.6406 62.2344 47.4727 61.8945 46.4961 61.2148C45.5273 60.5273 44.7812 59.5312 44.2578 58.2266C43.7422 56.9219 43.4844 55.3516 43.4844 53.5156C43.4844 51.6875 43.7422 50.1211 44.2578 48.8164C44.7812 47.5039 45.5312 46.5078 46.5078 45.8281C47.4844 45.1406 48.6484 44.7969 50 44.7969C51.3438 44.7969 52.5039 45.1406 53.4805 45.8281C54.4648 46.5078 55.2148 47.5039 55.7305 48.8164C56.2539 50.1211 56.5156 51.6875 56.5156 53.5156C56.5156 55.3516 56.2539 56.9219 55.7305 58.2266C55.2148 59.5312 54.4688 60.5273 53.4922 61.2148C52.5234 61.8945 51.3594 62.2344 50 62.2344ZM50 59.6797C50.7188 59.6797 51.332 59.4492 51.8398 58.9883C52.3555 58.5195 52.75 57.8281 53.0234 56.9141C53.3047 55.9922 53.4453 54.8594 53.4453 53.5156C53.4453 52.1875 53.3047 51.0625 53.0234 50.1406C52.75 49.2109 52.3555 48.5117 51.8398 48.043C51.3242 47.5664 50.7109 47.3281 50 47.3281C49.2891 47.3281 48.6758 47.5664 48.1602 48.043C47.6445 48.5117 47.2461 49.2109 46.9648 50.1406C46.6914 51.0625 46.5547 52.1875 46.5547 53.5156C46.5547 54.8594 46.6914 55.9922 46.9648 56.9141C47.2461 57.8281 47.6406 58.5195 48.1484 58.9883C48.6641 59.4492 49.2812 59.6797 50 59.6797Z', }; const Timer = function Timer({ value, - size = 100, - on = '#FFBF00', - off = 'white', + size = 64, + on = DEFAULT_ON, + off = DEFAULT_OFF, }: Props) { const active = new Set(activeMap[value]); const stroke = (seg: SegmentKey) => (active.has(seg) ? on : off); - const center = centerPathMap[value]; + const centerD = centerPathMap[value]; return ( - {/* 공통 5개 곡선 세그먼트 */} - - - - - - - - - - - - - - - + + {/* 흰 동그라미 배경 */} + - {/* 중앙 숫자/원 */} - - - - - {/* 공통 필터들(원본에서 이름만 단순화) */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + {/* 중앙 숫자 */} + + + + + + + + ); diff --git a/src/renderer/src/components/ToggleSwitch/NotificationToggleSwitch.tsx b/src/renderer/src/components/ToggleSwitch/NotificationToggleSwitch.tsx new file mode 100644 index 0000000..c0b61bf --- /dev/null +++ b/src/renderer/src/components/ToggleSwitch/NotificationToggleSwitch.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import { cn } from '../../utils/cn'; + +interface NotificationToggleSwitchProps { + checked: boolean; + onChange: (checked: boolean) => void; + isDisabled?: boolean; +} + +const NotificationToggleSwitch = React.forwardRef< + HTMLButtonElement, + NotificationToggleSwitchProps +>(({ checked, onChange, isDisabled = false }, ref) => { + return ( + + ); +}); + +NotificationToggleSwitch.displayName = 'NotificationToggleSwitch'; +export { NotificationToggleSwitch }; diff --git a/src/renderer/src/components/ToggleSwitch/ToggleSwitch.tsx b/src/renderer/src/components/ToggleSwitch/ToggleSwitch.tsx new file mode 100644 index 0000000..fb80a72 --- /dev/null +++ b/src/renderer/src/components/ToggleSwitch/ToggleSwitch.tsx @@ -0,0 +1,90 @@ +import * as React from 'react'; + +import { cn } from '../../utils/cn'; + +interface ToggleSwitchProps { + checked: boolean; + onChange: (checked: boolean) => void; + uncheckedLabel?: string; + checkedLabel?: string; +} + +const ToggleSwitch = React.forwardRef( + ({ checked, onChange, uncheckedLabel, checkedLabel }, ref) => { + const uncheckedRef = React.useRef(null); + const checkedRef = React.useRef(null); + const [indicatorWidth, setIndicatorWidth] = React.useState(0); + const [translateX, setTranslateX] = React.useState(0); + + React.useEffect(() => { + const updateIndicator = () => { + if (uncheckedRef.current && checkedRef.current) { + const uncheckedWidth = uncheckedRef.current.offsetWidth; + const checkedWidth = checkedRef.current.offsetWidth; + const gap = 8; // gap-2 = 8px + const extraPadding = 16; // 인디케이터 추가 너비 (좌우 각 4px) + + if (checked) { + // 연간 선택됨: 인디케이터가 연간 위치로 + setIndicatorWidth(checkedWidth + extraPadding); + setTranslateX(uncheckedWidth + gap - extraPadding / 2); + } else { + // 월간 선택됨: 인디케이터가 월간 위치로 + setIndicatorWidth(uncheckedWidth + extraPadding); + setTranslateX(-extraPadding / 2); + } + } + }; + + // 레이아웃 완료 후 재계산 + const timeoutId = setTimeout(updateIndicator, 0); + return () => clearTimeout(timeoutId); + }, [uncheckedLabel, checkedLabel, checked]); + + return ( + + ); + }, +); + +ToggleSwitch.displayName = 'ToggleSwitch'; +export { ToggleSwitch }; diff --git a/src/renderer/src/components/Typography/Typography.tsx b/src/renderer/src/components/Typography/Typography.tsx index 204aa58..1ec53fc 100644 --- a/src/renderer/src/components/Typography/Typography.tsx +++ b/src/renderer/src/components/Typography/Typography.tsx @@ -25,7 +25,7 @@ interface TypographyProps { | 'caption-sm-semibold'; children: React.ReactNode; className?: string; - as?: keyof JSX.IntrinsicElements; + as?: React.ElementType; } export function Typography({ diff --git a/src/renderer/src/components/WidgetController/WidgetController.tsx b/src/renderer/src/components/WidgetController/WidgetController.tsx new file mode 100644 index 0000000..e06bf79 --- /dev/null +++ b/src/renderer/src/components/WidgetController/WidgetController.tsx @@ -0,0 +1,77 @@ +import { useState, useEffect } from 'react'; + +/* 위젯 창을 제어하는 컴포넌트 메인 창에서 위젯 창을 열고 닫을 수 있습니다 */ +export function WidgetController() { + const [isWidgetOpen, setIsWidgetOpen] = useState(false); + + /* 위젯 창이 열려있는지 확인 */ + useEffect(() => { + const checkWidgetStatus = async () => { + if (window.electronAPI?.widget) { + const isOpen = await window.electronAPI.widget.isOpen(); + setIsWidgetOpen(isOpen); + } + }; + + checkWidgetStatus(); + }, []); + + /*위젯 창 열기*/ + const handleOpenWidget = async () => { + try { + if (window.electronAPI?.widget) { + await window.electronAPI.widget.open(); + setIsWidgetOpen(true); + console.log('위젯 창이 열렸습니다'); + } + } catch (error) { + console.error('위젯 창 열기 실패:', error); + } + }; + + /* 위젯 창 닫기 */ + const handleCloseWidget = async () => { + try { + if (window.electronAPI?.widget) { + await window.electronAPI.widget.close(); + setIsWidgetOpen(false); + console.log('위젯 창이 닫혔습니다'); + } + } catch (error) { + console.error('위젯 창 닫기 실패:', error); + } + }; + + /* Electron 환경이 아닌 경우 */ + if (!window.electronAPI?.widget) { + return ( +
+

Electron 환경에서만 사용 가능합니다.

+
+ ); + } + + return ( +
+
+ + +
+
+ 상태: {isWidgetOpen ? '열림' : '닫힘'} +
+
+ ); +} diff --git a/src/renderer/src/components/WidgetTitleBar/WidgetTitleBar.tsx b/src/renderer/src/components/WidgetTitleBar/WidgetTitleBar.tsx new file mode 100644 index 0000000..aa75989 --- /dev/null +++ b/src/renderer/src/components/WidgetTitleBar/WidgetTitleBar.tsx @@ -0,0 +1,75 @@ +import MediumDragIcon from '../../assets/widget/drag_icon.svg?react'; +import MiniDragIcon from '../../assets/widget/mini_drag_icon.svg?react'; + +interface WidgetTitleBarProps { + onClose?: () => void; + isMini?: boolean; // 미니 모드 여부 +} + +/* 커스텀 위젯 타이틀바 (frame: false 일 때 사용) */ +export function WidgetTitleBar({ + onClose, + isMini = true, +}: WidgetTitleBarProps) { + // 위젯 닫기 + const handleClose = async () => { + try { + if (window.electronAPI?.widget) { + await window.electronAPI.widget.close(); + + // 위젯 닫힘 로그 저장 + if (window.electronAPI?.writeLog) { + try { + const logData = JSON.stringify({ + event: 'widget_closed', + timestamp: new Date().toISOString(), + }); + await window.electronAPI.writeLog(logData); + } catch (error) { + console.error('위젯 닫힘 로그 저장 실패:', error); + } + } + } + onClose?.(); + } catch (error) { + console.error('위젯 닫기 실패:', error); + } + }; + + return ( +
+ {/* 빨간 닫기 버튼 */} +
+ ); +} diff --git a/src/renderer/src/components/index.ts b/src/renderer/src/components/index.ts index 75f257c..1ba01fd 100644 --- a/src/renderer/src/components/index.ts +++ b/src/renderer/src/components/index.ts @@ -1,7 +1,6 @@ // UI 컴포넌트 export export { Button } from './Button/Button'; export { default as TextField } from './InputField/TextField'; -export { Typography } from './Typography/Typography'; -export { Timer } from './Timer/Timer'; -export { Header } from './Header/Header'; export * from './NotificateMessage'; +export { Timer } from './Timer/Timer'; +export { Typography } from './Typography/Typography'; diff --git a/src/renderer/src/components/pose-detection/PoseAnalyzer.tsx b/src/renderer/src/components/pose-detection/PoseAnalyzer.tsx deleted file mode 100644 index 2017d23..0000000 --- a/src/renderer/src/components/pose-detection/PoseAnalyzer.tsx +++ /dev/null @@ -1,313 +0,0 @@ -export interface PoseLandmark { - x: number; - y: number; - z: number; - visibility?: number; -} - -export interface WorldLandmark { - x: number; - y: number; - z: number; - visibility?: number; -} - -// PI 지표 계산 결과 -export interface PIResult { - PI_raw: number; - S: { x: number; y: number; z: number }; - E: { x: number; y: number; z: number }; - W: number; -} - -// 정면성 검사 결과 -export interface FrontalityResult { - pass: boolean; - roll: number; - centerRatio: number; -} - -// EMA 스무딩 클래스 -class EmaSmoother { - private alpha: number; - private y: number | null = null; - - constructor(alpha: number = 0.25) { - this.alpha = alpha; - } - - next(x: number): number { - this.y = this.y === null ? x : this.alpha * x + (1 - this.alpha) * this.y; - return this.y; - } - - reset() { - this.y = null; - } -} - -// PI 지표 계산 함수 -export function calculatePI( - landmarks: PoseLandmark[], - worldLandmarks: WorldLandmark[], -): PIResult | null { - if (!worldLandmarks) return null; - - const LEFT_EAR = 7; - const RIGHT_EAR = 8; - const LEFT_SHOULDER = 11; - const RIGHT_SHOULDER = 12; - - const LE = worldLandmarks[LEFT_EAR]; - const RE = worldLandmarks[RIGHT_EAR]; - const LS = worldLandmarks[LEFT_SHOULDER]; - const RS = worldLandmarks[RIGHT_SHOULDER]; - - if (!LE || !RE || !LS || !RS) return null; - - // S = (LEFT_SHOULDER + RIGHT_SHOULDER) / 2 - const S = { - x: (LS.x + RS.x) / 2, - y: (LS.y + RS.y) / 2, - z: (LS.z + RS.z) / 2, - }; - - // E = (LEFT_EAR + RIGHT_EAR) / 2 - const E = { - x: (LE.x + RE.x) / 2, - y: (LE.y + RE.y) / 2, - z: (LE.z + RE.z) / 2, - }; - - // W = || RIGHT_SHOULDER - LEFT_SHOULDER || (world 공간 길이) - const W = Math.sqrt( - Math.pow(RS.x - LS.x, 2) + - Math.pow(RS.y - LS.y, 2) + - Math.pow(RS.z - LS.z, 2), - ); - - if (W === 0) return null; - - // PI_raw = (z_S - z_E) / W - const PI_raw = (S.z - E.z) / W; - - return { PI_raw, S, E, W }; -} - -// 정면성 검사 함수 -export function checkFrontality(landmarks: PoseLandmark[]): FrontalityResult { - const LEFT_EAR = 7; - const RIGHT_EAR = 8; - const LEFT_SHOULDER = 11; - const RIGHT_SHOULDER = 12; - const NOSE = 0; - - const LE = landmarks[LEFT_EAR]; - const RE = landmarks[RIGHT_EAR]; - const LS = landmarks[LEFT_SHOULDER]; - const RS = landmarks[RIGHT_SHOULDER]; - const nose = landmarks[NOSE]; - - if (!LE || !RE || !LS || !RS || !nose) { - return { pass: false, roll: 0, centerRatio: 1 }; - } - - // roll = atan2(|(R_e - L_e).y|, (R_e - L_e).x) [deg] - const earDiff = { x: RE.x - LE.x, y: RE.y - LE.y }; - const roll = Math.abs( - (Math.atan2(Math.abs(earDiff.y), earDiff.x) * 180) / Math.PI, - ); - - // center_ratio = |NOSE.x - S.x| / ||R_s - L_s||_2D - const S_2D = { x: (LS.x + RS.x) / 2, y: (LS.y + RS.y) / 2 }; - const shoulderDiff = { x: RS.x - LS.x, y: RS.y - LS.y }; - const shoulderWidth2D = Math.sqrt( - shoulderDiff.x * shoulderDiff.x + shoulderDiff.y * shoulderDiff.y, - ); - const centerRatio = - shoulderWidth2D > 0 ? Math.abs(nose.x - S_2D.x) / shoulderWidth2D : 1; - - // 정면성 패스: |roll| ≤ 10°, center_ratio ≤ 0.15 - const pass = roll <= 10 && centerRatio <= 0.15; - - return { pass, roll, centerRatio }; -} - -// 자세 판정 결과 -export interface PostureClassification { - text: string; - cls: 'ok' | 'warn' | 'bad'; - zScore: number; - PI_EMA: number; - z_PI: number; - gamma: number; - Score: number; - events: string[]; -} - -// 자세 판정 엔진 -export class PostureClassifier { - private prevState = { - PI_EMA: null as number | null, - state: 'normal' as 'normal' | 'bad', - }; - private emaSmoother = new EmaSmoother(0.25); - - classify( - piData: PIResult, - mu: number, - sigma: number, - frontality: FrontalityResult, - ): PostureClassification { - if (sigma === 0) { - return { - text: '측정중', - cls: 'warn', - zScore: 0, - PI_EMA: 0, - z_PI: 0, - gamma: 0, - Score: 0, - events: [], - }; - } - - const PI_raw = piData.PI_raw; - - // PI_EMA_t = alpha * PI_raw + (1-alpha) * PI_EMA_(t-1) - const PI_EMA = this.emaSmoother.next(PI_raw); - - // z_PI = (PI_EMA_t - mu_PI) / (sigma_PI + 1e-6) - const z_PI = (PI_EMA - mu) / (sigma + 1e-6); - - // 정면성 가중치 gamma ∈ [0,1] - const gamma = frontality.pass ? 1.0 : 0.4; - - // Score = gamma * z_PI - const Score = gamma * z_PI; - - // 히스테리시스 임계값 - const enter_bad = 1.2; // Score ≥ 1.2 → 거북목 진입 - const exit_bad = 0.8; // Score ≤ 0.8 → 거북목 해제 - - // 상태 결정 (히스테리시스 반영) - let newState = this.prevState.state; - const events: string[] = []; - - if (this.prevState.state === 'normal' && Score >= enter_bad) { - newState = 'bad'; - events.push('enter_bad'); - } else if (this.prevState.state === 'bad' && Score <= exit_bad) { - newState = 'normal'; - events.push('exit_bad'); - } - - // 상태 업데이트 - this.prevState = { PI_EMA, state: newState }; - - // UI용 텍스트 변환 - const text = newState === 'bad' ? '거북목' : '정상'; - const cls = newState === 'bad' ? 'bad' : 'ok'; - - return { - text, - cls, - zScore: Score, - PI_EMA, - z_PI, - gamma, - Score, - events, - }; - } - - reset() { - this.prevState = { PI_EMA: null, state: 'normal' }; - this.emaSmoother.reset(); - } -} - -// 캘리브레이션 상태 -export interface CalibrationState { - isCalibrating: boolean; - isCalibrated: boolean; - startTime: number; - frames: Array<{ - lms: PoseLandmark[]; - pi: PIResult; - worldLms: WorldLandmark[]; - pi_ema?: number; // EMA 적용된 PI 값 (선택적) - }>; - mu_PI: number; - sigma_PI: number; - quality: 'poor' | 'medium' | 'good' | 'unknown'; -} - -// 상하 5% 절사 평균 및 표준편차 계산 -export function trimmedStats(values: number[], trimPercent: number = 0.05) { - if (values.length === 0) return { mean: 0, std: 0 }; - - const sorted = [...values].sort((a, b) => a - b); - const trimCount = Math.floor(sorted.length * trimPercent); - const trimmed = sorted.slice(trimCount, sorted.length - trimCount); - - if (trimmed.length === 0) return { mean: 0, std: 0 }; - - const mean = trimmed.reduce((sum, v) => sum + v, 0) / trimmed.length; - const variance = - trimmed.reduce((sum, v) => sum + (v - mean) ** 2, 0) / trimmed.length; - const std = Math.sqrt(variance); - - return { mean, std }; -} - -// 캘리브레이션 데이터 처리 -export function processCalibrationData( - frames: CalibrationState['frames'], - skipFrontalCheck: boolean = false, -) { - const nTotal = frames.length; - let nPass = 0; - const piValues: number[] = []; - - for (const frame of frames) { - const frontality = checkFrontality(frame.lms); - const shouldInclude = skipFrontalCheck || frontality.pass; - - if (shouldInclude && frame.pi !== null) { - // PI_EMA가 있으면 사용, 없으면 PI_raw 사용 (하위 호환성) - const piValue = - frame.pi_ema !== undefined ? frame.pi_ema : frame.pi.PI_raw; - piValues.push(piValue); - nPass++; - } - } - - if (piValues.length < 5) { - const passRate = ((nPass / nTotal) * 100).toFixed(1); - return { - success: false, - message: `정면성 통과 프레임이 너무 적습니다.\n통과: ${nPass}/${nTotal} (${passRate}%)\n\n💡 팁:\n- 정면을 바라보세요\n- 고개를 살짝 움직여보세요`, - }; - } - - const stats = trimmedStats(piValues, 0.05); - const passRate = nPass / nTotal; - - let quality: 'poor' | 'medium' | 'good' = 'poor'; - if (passRate >= 0.5 && stats.std < 0.2) { - quality = 'good'; - } else if (passRate >= 0.3 && stats.std < 0.3) { - quality = 'medium'; - } - - return { - success: true, - nTotal, - nPass, - mu_PI: stats.mean, - sigma_PI: stats.std, - quality, - passRate, - }; -} diff --git a/src/renderer/src/components/pose-detection/PoseDetection.tsx b/src/renderer/src/components/pose-detection/PoseDetection.tsx index 8429b05..d3ad5b1 100644 --- a/src/renderer/src/components/pose-detection/PoseDetection.tsx +++ b/src/renderer/src/components/pose-detection/PoseDetection.tsx @@ -1,12 +1,19 @@ import { FilesetResolver, PoseLandmarker } from '@mediapipe/tasks-vision'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { + useCallback, + useEffect, + useRef, + useState, + type RefObject, +} from 'react'; +import Webcam from 'react-webcam'; interface WebcamRef { video?: HTMLVideoElement | null; } interface PoseDetectionProps { - videoRef: React.RefObject; // Webcam 컴포넌트 ref + videoRef: RefObject; // Webcam 컴포넌트 ref onPoseDetected?: ( landmarks: PoseLandmark[], worldLandmarks?: PoseLandmark[], @@ -56,7 +63,6 @@ const PoseDetection = ({ ); setIsInitialized(true); - console.log('Pose landmarker initialized successfully'); } catch (error) { console.error('Failed to initialize pose landmarker:', error); } @@ -98,10 +104,6 @@ const PoseDetection = ({ ...landmark, z: landmark.z || 0, // z값이 없으면 0으로 설정 })); - console.log( - 'World landmarks 없음 - 2D 랜드마크를 3D로 변환:', - worldLandmarks.length, - ); } onPoseDetected?.(keyLandmarks, worldLandmarks); @@ -155,7 +157,16 @@ const PoseDetection = ({ const getVideoElement = () => { // Webcam 컴포넌트에서 video 요소 가져오기 - return videoRef.current?.video || null; + const ref = videoRef.current; + if (!ref) return null; + // WebcamRef 인터페이스인 경우 + if ('video' in ref) { + return ref.video || null; + } + // Webcam 컴포넌트인 경우 - video 속성이 있을 수 있음 + return ( + (ref as unknown as { video?: HTMLVideoElement | null })?.video || null + ); }; const interval = setInterval(() => { diff --git a/src/renderer/src/components/pose-detection/PoseVisualizer.tsx b/src/renderer/src/components/pose-detection/PoseVisualizer.tsx index c88b4ce..0e4fe85 100644 --- a/src/renderer/src/components/pose-detection/PoseVisualizer.tsx +++ b/src/renderer/src/components/pose-detection/PoseVisualizer.tsx @@ -1,4 +1,5 @@ import { useEffect, useRef } from 'react'; +import { usePostureStore } from '../../store/usePostureStore'; interface PoseLandmark { x: number; @@ -53,6 +54,7 @@ const PoseVisualizer = ({ videoHeight, isVisible = true, }: PoseVisualizerProps) => { + const postureClass = usePostureStore((state) => state.postureClass); const canvasRef = useRef(null); const smootherRef = useRef(new LandmarkSmoother()); @@ -70,6 +72,25 @@ const PoseVisualizer = ({ const ctx = canvas.getContext('2d'); if (!ctx) return; + // --- 색상 정의 --- + const computedStyle = getComputedStyle(document.documentElement); + const successColor = computedStyle + .getPropertyValue('--color-success') + .trim(); + const errorColor = computedStyle.getPropertyValue('--color-error').trim(); + const defaultColor = computedStyle + .getPropertyValue('--color-yellow-500') + .trim(); + + // --- 상태에 따른 색상 결정 --- + // 레벨 1-3: 초록색, 레벨 4-6: 빨간색, 레벨 0(측정중): 노란색 + const LineColor = + postureClass >= 1 && postureClass <= 3 + ? successColor + : postureClass >= 4 && postureClass <= 6 + ? errorColor + : defaultColor; + // 부모 컨테이너의 실제 크기 가져오기 const parent = canvas.parentElement; const displayWidth = parent?.clientWidth || videoWidth; @@ -94,41 +115,38 @@ const PoseVisualizer = ({ const smoothedLandmarks = smootherRef.current.smooth(landmarks); // 랜드마크 그리기 (거울모드 반전) + const relevantLandmarks = [7, 8, 11, 12]; // 귀, 어깨 smoothedLandmarks.forEach((landmark, index) => { - if (landmark.visibility && landmark.visibility > 0.2) { - // 임계값 낮춤 - // displayWidth/Height로 변환 (실제 표시 크기에 맞춤) + if ( + relevantLandmarks.includes(index) && + landmark.visibility && + landmark.visibility > 0.2 + ) { const x = displayWidth - landmark.x * displayWidth; // X축 반전 (거울모드) const y = landmark.y * displayHeight; - // 랜드마크 점 크기 (얼굴은 작게, 어깨는 크게) - const pointSize = index < 11 ? 4 : 6; + // 랜드마크 점 크기 + const pointSize = 4; - // 랜드마크 점 그리기 + // 랜드마크 점 그리기 (테두리 효과) ctx.beginPath(); - ctx.arc(x, y, pointSize, 0, 2 * Math.PI); + ctx.arc(x, y, pointSize + 1, 0, 2 * Math.PI); // 테두리 + ctx.fillStyle = 'white'; + ctx.fill(); - // 색상 구분 (얼굴: 연한 회색, 어깨: 파란색) - if (index >= 0 && index <= 10) { - // 얼굴 (0-10) - ctx.fillStyle = '#e5e7eb'; // 연한 회색 + ctx.beginPath(); + ctx.arc(x, y, pointSize, 0, 2 * Math.PI); // 원래 점 + + // 색상 구분 (귀: 분홍색, 어깨: 파란색) + if (index === 7 || index === 8) { + // 귀 + ctx.fillStyle = LineColor; } else if (index === 11 || index === 12) { - // 어깨 (11, 12) - ctx.fillStyle = '#60a5fa'; // 파란색 - } else { - ctx.fillStyle = '#e5e7eb'; // 기본값 + // 어깨 + ctx.fillStyle = LineColor; } ctx.fill(); - ctx.strokeStyle = 'rgba(229,231,235,0.9)'; - ctx.lineWidth = 1; - ctx.stroke(); - - // 랜드마크 번호 표시 (작은 폰트로) - ctx.fillStyle = 'rgba(229,231,235,0.9)'; - ctx.font = '11px ui-sans-serif, system-ui'; - ctx.textAlign = 'left'; - ctx.fillText(index.toString(), x + 5, y - 5); } }); @@ -149,13 +167,36 @@ const PoseVisualizer = ({ const rightShoulderX = displayWidth - rightShoulder.x * displayWidth; const rightShoulderY = rightShoulder.y * displayHeight; - ctx.strokeStyle = 'rgba(255,255,255,0.6)'; + ctx.strokeStyle = LineColor; + ctx.lineWidth = 4; ctx.beginPath(); ctx.moveTo(leftShoulderX, leftShoulderY); ctx.lineTo(rightShoulderX, rightShoulderY); ctx.stroke(); } + // 귀 라인 + const leftEarLine = smoothedLandmarks[7]; + const rightEarLine = smoothedLandmarks[8]; + if ( + leftEarLine && + rightEarLine && + (leftEarLine.visibility ?? 0) > 0.2 && + (rightEarLine.visibility ?? 0) > 0.2 + ) { + const leftEarX = displayWidth - leftEarLine.x * displayWidth; + const leftEarY = leftEarLine.y * displayHeight; + const rightEarX = displayWidth - rightEarLine.x * displayWidth; + const rightEarY = rightEarLine.y * displayHeight; + + ctx.strokeStyle = LineColor; + ctx.lineWidth = 4; + ctx.beginPath(); + ctx.moveTo(leftEarX, leftEarY); + ctx.lineTo(rightEarX, rightEarY); + ctx.stroke(); + } + // 귀 중점 - 어깨 중점 라인 (상태에 따른 색상) const leftEar = smoothedLandmarks[7]; const rightEar = smoothedLandmarks[8]; @@ -188,26 +229,39 @@ const PoseVisualizer = ({ const shoulderMidX = (leftShoulderX + rightShoulderX) / 2; const shoulderMidY = (leftShoulderY + rightShoulderY) / 2; - // 귀-어깨 중점 연결선 (초록색) - ctx.strokeStyle = '#22c55e'; + // 귀-어깨 중점 연결선 + ctx.strokeStyle = LineColor; + ctx.lineWidth = 4; ctx.beginPath(); ctx.moveTo(shoulderMidX, shoulderMidY); ctx.lineTo(earMidX, earMidY); ctx.stroke(); - // 어깨 중점 강조 (파란색) - ctx.fillStyle = '#60a5fa'; + // 어깨 중점 강조 (테두리) + ctx.fillStyle = 'white'; + ctx.beginPath(); + ctx.arc(shoulderMidX, shoulderMidY, 4 + 1, 0, Math.PI * 2); + ctx.fill(); + + // 어깨 중점 강조 (원래 점) + ctx.fillStyle = LineColor; + ctx.beginPath(); + ctx.arc(shoulderMidX, shoulderMidY, 4, 0, Math.PI * 2); + ctx.fill(); + + // 귀 중점 강조 (테두리) + ctx.fillStyle = 'white'; ctx.beginPath(); - ctx.arc(shoulderMidX, shoulderMidY, 6, 0, Math.PI * 2); + ctx.arc(earMidX, earMidY, 4 + 1, 0, Math.PI * 2); ctx.fill(); - // 귀 중점 강조 (분홍색) - ctx.fillStyle = '#f472b6'; + // 귀 중점 강조 (원래 점) + ctx.fillStyle = LineColor; ctx.beginPath(); - ctx.arc(earMidX, earMidY, 6, 0, Math.PI * 2); + ctx.arc(earMidX, earMidY, 4, 0, Math.PI * 2); ctx.fill(); } - }, [landmarks, videoWidth, videoHeight, isVisible]); + }, [landmarks, videoWidth, videoHeight, isVisible, postureClass]); if (!isVisible) return null; diff --git a/src/renderer/src/components/pose-detection/PostureClassifier.ts b/src/renderer/src/components/pose-detection/PostureClassifier.ts new file mode 100644 index 0000000..51c68e3 --- /dev/null +++ b/src/renderer/src/components/pose-detection/PostureClassifier.ts @@ -0,0 +1,175 @@ +import { getScoreLevel } from '../../utils/getScoreLevel'; +import { EmaSmoother } from './calculations'; +import { PostureStabilizer } from './PostureStabilizer'; +import { ScoreProcessor } from './ScoreProcessor'; +import { FrontalityResult, PIResult, PostureClassification } from './types'; + +// 안정화 검사 및 점수 업데이트 주기 +// 거북이/기린 경계 전환: 매우 빠르게 반영 (100ms) +// 일반 레벨 변경: 빠르게 반영 (150ms) +// 레벨 유지 시: 더 빠르게 반영 (200ms) +const SCORE_UPDATE_INTERVAL_MS_NORMAL = 200; // 일반 업데이트 주기 +const SCORE_UPDATE_INTERVAL_MS_LEVEL_CHANGE = 150; // 레벨 변경 시 주기 +const SCORE_UPDATE_INTERVAL_MS_BOUNDARY = 50; // 거북이/기린 경계 전환 시 주기 + +// 자세 판정 엔진 +export class PostureClassifier { + private prevState = { + PI_EMA: null as number | null, + state: 'normal' as 'normal' | 'bad', + }; + + private emaSmoother = new EmaSmoother(0.25); + private scoreProcessor = new ScoreProcessor(); + // windowMs=300ms, threshold=0.6, minBufferSize=3으로 조정하여 더 빠른 반응 + private stabilizer = new PostureStabilizer(300, 0.6, 3); + + // 마지막으로 반환된 안정화된 상태 + private lastStableState: PostureClassification | null = null; + // 마지막 스코어 업데이트 시간 + private lastScoreUpdateTime: number = 0; + + classify( + piData: PIResult, + mu: number, + sigma: number, + frontality: FrontalityResult, + ): PostureClassification { + const currentTime = Date.now(); + + // 캘리브레이션 데이터가 유효하지 않으면 초기 상태 반환 + if (sigma === 0) { + return ( + this.lastStableState ?? { + text: '측정중', + cls: 0, + zScore: 0, + PI_EMA: 0, + z_PI: 0, + gamma: 0, + Score: 0, + events: [], + } + ); + } + + const PI_raw = piData.PI_raw; + const PI_EMA = this.emaSmoother.next(PI_raw); + const z_PI = (PI_EMA - mu) / (sigma + 1e-6); + const gamma = 1.0; + const rawScore = gamma * z_PI; + const finalScore = this.scoreProcessor.next(rawScore); + + // 현재 프레임의 분류 결과 생성 + const currentClassification = this.createClassification(finalScore, { + PI_EMA, + z_PI, + gamma, + }); + + // 안정화 버퍼에 현재 점수 추가 + this.stabilizer.addScore(currentClassification.Score, currentTime); + + // 레벨 변경 여부 확인 + const levelChanged = this.lastStableState + ? this.lastStableState.cls !== currentClassification.cls + : false; + + // 거북이/기린 경계 전환 여부 확인 (레벨 3↔4 전환) + const isBoundaryCrossing = + levelChanged && + this.lastStableState && + ((this.lastStableState.cls === 3 && currentClassification.cls === 4) || + (this.lastStableState.cls === 4 && currentClassification.cls === 3)); + + // 업데이트 주기 결정: 경계 전환 > 레벨 변경 > 일반 업데이트 + const requiredInterval = isBoundaryCrossing + ? SCORE_UPDATE_INTERVAL_MS_BOUNDARY + : levelChanged + ? SCORE_UPDATE_INTERVAL_MS_LEVEL_CHANGE + : SCORE_UPDATE_INTERVAL_MS_NORMAL; + + // 업데이트 주기가 되지 않았으면 이전 상태 반환 + const timeSinceLastUpdate = currentTime - this.lastScoreUpdateTime; + if (timeSinceLastUpdate < requiredInterval && this.lastStableState) { + return this.lastStableState; + } + + // 안정화 검사 + // 거북이/기린 경계 전환 시에는 threshold를 완화하여 더 빠르게 반영 + const relaxedThreshold = isBoundaryCrossing ? 0.6 * 2 : undefined; // 경계 전환 시 2배 완화 + const shouldUpdate = this.stabilizer.shouldUpdate( + currentClassification.Score, + relaxedThreshold, + ); + + if (shouldUpdate) { + // 안정화 통과: 새로운 상태를 안정된 상태로 업데이트 + this.lastStableState = currentClassification; + } + // 안정화 실패 시, lastStableState는 변경되지 않고 유지됨 + + // 업데이트 시간 갱신 + this.lastScoreUpdateTime = currentTime; + + // 항상 마지막으로 안정화된 상태를 반환 (실패 시 이전 상태가 반환됨) + return ( + this.lastStableState ?? { + // 초기 상태 (null일 경우 대비) + text: '측정중', + cls: 0, + zScore: 0, + PI_EMA: 0, + z_PI: 0, + gamma: 0, + Score: 0, + events: [], + } + ); + } + + /** + * 점수와 추가 데이터를 기반으로 PostureClassification 객체를 생성합니다. + * 히스테리시스 로직을 포함합니다. + */ + private createClassification( + score: number, + details: { PI_EMA: number; z_PI: number; gamma: number }, + ): PostureClassification { + const enter_bad = 1.2; + const exit_bad = 0.8; + + let newState = this.prevState.state; + const events: string[] = []; + + if (this.prevState.state === 'normal' && score >= enter_bad) { + newState = 'bad'; + events.push('enter_bad'); + } else if (this.prevState.state === 'bad' && score <= exit_bad) { + newState = 'normal'; + events.push('exit_bad'); + } + + this.prevState = { PI_EMA: details.PI_EMA, state: newState }; + + const levelInfo = getScoreLevel(score); + + return { + text: levelInfo.name, + cls: levelInfo.level, + zScore: score, + Score: score, + events, + ...details, + }; + } + + reset() { + this.prevState = { PI_EMA: null, state: 'normal' }; + this.emaSmoother.reset(); + this.scoreProcessor.reset(); + this.stabilizer.reset(); + this.lastStableState = null; + this.lastScoreUpdateTime = 0; + } +} diff --git a/src/renderer/src/components/pose-detection/PostureStabilizer.ts b/src/renderer/src/components/pose-detection/PostureStabilizer.ts new file mode 100644 index 0000000..79c0835 --- /dev/null +++ b/src/renderer/src/components/pose-detection/PostureStabilizer.ts @@ -0,0 +1,148 @@ +/** + * 단계 전환 안정화 검사 클래스 + * 급격한 자세 변화로 인한 잘못된 단계 전환을 방지합니다. + */ +export class PostureStabilizer { + private scoreBuffer: Array<{ score: number; timestamp: number }> = []; + private readonly windowMs: number; + private readonly threshold: number; + private readonly minBufferSize: number; + + constructor( + windowMs: number = 500, + threshold: number = 0.5, + minBufferSize: number = 5, + ) { + this.windowMs = windowMs; + this.threshold = threshold; + this.minBufferSize = minBufferSize; + } + + /** + * 현재 프레임의 Score를 버퍼에 추가하고 오래된 데이터를 제거합니다. + * @param score 현재 프레임의 Score + * @param timestamp 현재 시간 (ms) + */ + public addScore(score: number, timestamp: number): void { + this.scoreBuffer.push({ score, timestamp }); + + // 윈도우 시간 이전 데이터 제거 + const cutoffTime = timestamp - this.windowMs; + this.scoreBuffer = this.scoreBuffer.filter( + (entry) => entry.timestamp >= cutoffTime, + ); + } + + /** + * 현재 Score가 안정화 검사를 통과하는지 확인합니다. + * @param currentScore 현재 프레임의 Score + * @param relaxedThreshold 선택적 완화된 threshold (기본값: this.threshold) + * @returns true면 업데이트 허용, false면 이전 상태 유지 + */ + public shouldUpdate( + currentScore: number, + relaxedThreshold?: number, + ): boolean { + // 버퍼에 충분한 데이터가 없으면 업데이트 허용 + if (this.scoreBuffer.length < this.minBufferSize) { + return true; + } + + // 현재 점수는 이미 버퍼에 추가되어 있으므로, 이전 점수들만으로 평균 계산 + const previousScores = this.scoreBuffer.slice(0, -1); + + // 이전 점수가 없으면 (버퍼에 현재 점수만 있으면) 업데이트 허용 + if (previousScores.length === 0) { + return true; + } + + const currentEntry = this.scoreBuffer[this.scoreBuffer.length - 1]; + const averageScore = this.calculateWeightedAverage( + previousScores, + currentEntry.timestamp, + ); + + // 현재 프레임과 이전 점수들의 평균의 오차 계산 + const scoreDifference = Math.abs(currentScore - averageScore); + + // 사용할 threshold 결정 (완화된 threshold가 제공되면 사용) + const effectiveThreshold = relaxedThreshold ?? this.threshold; + + // 오차가 임계값보다 크면 이전 상태 유지 + if (scoreDifference > effectiveThreshold) { + return false; + } + + return true; + } + + /** + * 디버깅용: 현재 버퍼 상태 정보를 반환합니다. + */ + public getDebugInfo(currentScore: number): { + bufferSize: number; + averageScore: number; + currentScore: number; + scoreDifference: number; + threshold: number; + shouldUpdate: boolean; + } { + // 현재 점수를 제외한 이전 점수들의 평균 계산 + const previousScores = this.scoreBuffer.slice(0, -1); + const currentEntry = this.scoreBuffer[this.scoreBuffer.length - 1]; + const averageScore = + previousScores.length > 0 + ? this.calculateWeightedAverage(previousScores, currentEntry.timestamp) + : currentScore; + const scoreDifference = Math.abs(currentScore - averageScore); + const shouldUpdate = this.shouldUpdate(currentScore); + + return { + bufferSize: this.scoreBuffer.length, + averageScore, + currentScore, + scoreDifference, + threshold: this.threshold, + shouldUpdate, + }; + } + + /** + * 내부 버퍼를 초기화합니다. + */ + public reset(): void { + this.scoreBuffer = []; + } + + private calculateWeightedAverage( + entries: Array<{ score: number; timestamp: number }>, + currentTimestamp: number, + ): number { + if (entries.length === 0) { + return 0; + } + + let weightedSum = 0; + let totalWeight = 0; + + for (const entry of entries) { + const elapsed = currentTimestamp - entry.timestamp; + const weight = Math.max(0, 1 - elapsed / this.windowMs); + + if (weight <= 0) { + continue; + } + + weightedSum += entry.score * weight; + totalWeight += weight; + } + + if (totalWeight === 0) { + return ( + entries.reduce((sum, entry) => sum + entry.score, 0) / entries.length + ); + } + + return weightedSum / totalWeight; + } +} diff --git a/src/renderer/src/components/pose-detection/ScoreProcessor.ts b/src/renderer/src/components/pose-detection/ScoreProcessor.ts new file mode 100644 index 0000000..126686c --- /dev/null +++ b/src/renderer/src/components/pose-detection/ScoreProcessor.ts @@ -0,0 +1,137 @@ +// Helper functions from the python script, translated to JS +function getPercentile(data: number[], percentile: number): number { + if (data.length === 0) return 0; + const sortedData = [...data].sort((a, b) => a - b); + const index = (percentile / 100) * (sortedData.length - 1); + if (Number.isInteger(index)) { + return sortedData[index]; + } + const lowerIndex = Math.floor(index); + const upperIndex = Math.ceil(index); + const weight = index - lowerIndex; + return ( + sortedData[lowerIndex] * (1 - weight) + sortedData[upperIndex] * weight + ); +} + +// function getMedian(data: number[]): number { +// if (data.length === 0) return 0; +// const sortedData = [...data].sort((a, b) => a - b); +// const mid = Math.floor(sortedData.length / 2); +// if (sortedData.length % 2 === 0) { +// return (sortedData[mid - 1] + sortedData[mid]) / 2; +// } +// return sortedData[mid]; +// } + +// function removeOutliersIqr(scores: number[], multiplier: number): number[] { +// if (scores.length === 0) return []; + +// const q1 = getPercentile(scores, 25); +// const q3 = getPercentile(scores, 75); +// const iqr = q3 - q1; +// const lowerBound = q1 - multiplier * iqr; +// const upperBound = q3 + multiplier * iqr; + +// const cleanedScores: number[] = []; +// const median = getMedian(scores); + +// for (let i = 0; i < scores.length; i++) { +// const score = scores[i]; +// if (score < lowerBound || score > upperBound) { +// if (i > 0) { +// cleanedScores.push(cleanedScores[cleanedScores.length - 1]); +// } else { +// cleanedScores.push(median); +// } +// } else { +// cleanedScores.push(score); +// } +// } +// return cleanedScores; +// } + +function applyMovingAverage(scores: number[], window: number): number[] { + if (scores.length === 0) return []; + + const smoothed: number[] = []; + for (let i = 0; i < scores.length; i++) { + const start = Math.max(0, i - Math.floor(window / 2)); + const end = Math.min(scores.length, i + Math.floor(window / 2) + 1); + const windowSlice = scores.slice(start, end); + const mean = + windowSlice.reduce((sum, val) => sum + val, 0) / windowSlice.length; + smoothed.push(mean); + } + return smoothed; +} + +function applyEma(scores: number[], window: number): number[] { + if (scores.length === 0) return []; + + const alpha = 2 / (window + 1); + const emaScores = [scores[0]]; + + for (let i = 1; i < scores.length; i++) { + const ema = + alpha * scores[i] + (1 - alpha) * emaScores[emaScores.length - 1]; + emaScores.push(ema); + } + return emaScores; +} + +/** + * Applies a series of smoothing and filtering operations to a buffer of scores, + * exactly replicating the logic from the provided Python script. + */ +export class ScoreProcessor { + private scoreBuffer: number[] = []; + private readonly bufferSize = 100; // A buffer to run the batch processing on + + /** + * Adds a new score to the buffer and re-processes the entire buffer. + * @param score The raw score to process. + * @returns The latest processed score from the buffer. + */ + public next(score: number): number { + this.scoreBuffer.push(score); + if (this.scoreBuffer.length > this.bufferSize) { + this.scoreBuffer.shift(); + } + + // Need a minimum number of scores to get meaningful stats + if (this.scoreBuffer.length < 30) { + return Math.max(-10, Math.min(40, score)); // Clamp raw score + } + + // Run the full batch processing every time, exactly as in the python script + // 1. Clamp scores + const filteredScores = this.scoreBuffer.map((s) => + Math.max(-10, Math.min(40, s)), + ); + + // 2. Remove outliers + // const cleanedScores = removeOutliersIqr(filteredScores, 1.0); + + // 3. Moving Average (window=15) + const smoothed1 = applyMovingAverage(filteredScores, 15); + + // 4. EMA (window=30) + const smoothed2 = applyEma(smoothed1, 30); + + // 5. EMA (window=70) + const finalScores = applyEma(smoothed2, 70); + + const finalScore = finalScores[finalScores.length - 1]; + + // Return the final score, also clamped for safety. + return Math.max(-10, Math.min(40, finalScore)); + } + + /** + * Resets the internal score buffer. + */ + public reset(): void { + this.scoreBuffer = []; + } +} diff --git a/src/renderer/src/components/pose-detection/calculations.ts b/src/renderer/src/components/pose-detection/calculations.ts new file mode 100644 index 0000000..b2c93f1 --- /dev/null +++ b/src/renderer/src/components/pose-detection/calculations.ts @@ -0,0 +1,130 @@ +import { + PoseLandmark, + WorldLandmark, + PIResult, + FrontalityResult, +} from './types'; + +// EMA 스무딩 클래스 +export class EmaSmoother { + private alpha: number; + private y: number | null = null; + + constructor(alpha: number = 0.25) { + this.alpha = alpha; + } + + next(x: number): number { + this.y = this.y === null ? x : this.alpha * x + (1 - this.alpha) * this.y; + return this.y; + } + + reset() { + this.y = null; + } +} + +// PI 지표 계산 함수 +export function calculatePI( + landmarks: PoseLandmark[], + worldLandmarks: WorldLandmark[], +): PIResult | null { + if (!worldLandmarks) return null; + + const LEFT_EAR = 7; + const RIGHT_EAR = 8; + const LEFT_SHOULDER = 11; + const RIGHT_SHOULDER = 12; + + const LE = worldLandmarks[LEFT_EAR]; + const RE = worldLandmarks[RIGHT_EAR]; + const LS = worldLandmarks[LEFT_SHOULDER]; + const RS = worldLandmarks[RIGHT_SHOULDER]; + + if (!LE || !RE || !LS || !RS) return null; + + // S = (LEFT_SHOULDER + RIGHT_SHOULDER) / 2 + const S = { + x: (LS.x + RS.x) / 2, + y: (LS.y + RS.y) / 2, + z: (LS.z + RS.z) / 2, + }; + + // E = (LEFT_EAR + RIGHT_EAR) / 2 + const E = { + x: (LE.x + RE.x) / 2, + y: (LE.y + RE.y) / 2, + z: (LE.z + RE.z) / 2, + }; + + // W = || RIGHT_SHOULDER - LEFT_SHOULDER || (world 공간 길이) + const W = Math.sqrt( + Math.pow(RS.x - LS.x, 2) + + Math.pow(RS.y - LS.y, 2) + + Math.pow(RS.z - LS.z, 2), + ); + + if (W === 0) return null; + + // PI_raw = (z_S - z_E) / W + const PI_raw = (S.z - E.z) / W; + + return { PI_raw, S, E, W }; +} + +// 정면성 검사 함수 +export function checkFrontality(landmarks: PoseLandmark[]): FrontalityResult { + const LEFT_EAR = 7; + const RIGHT_EAR = 8; + const LEFT_SHOULDER = 11; + const RIGHT_SHOULDER = 12; + const NOSE = 0; + + const LE = landmarks[LEFT_EAR]; + const RE = landmarks[RIGHT_EAR]; + const LS = landmarks[LEFT_SHOULDER]; + const RS = landmarks[RIGHT_SHOULDER]; + const nose = landmarks[NOSE]; + + if (!LE || !RE || !LS || !RS || !nose) { + return { pass: false, roll: 0, centerRatio: 1 }; + } + + // roll = atan2(|(R_e - L_e).y|, (R_e - L_e).x) [deg] + const earDiff = { x: RE.x - LE.x, y: RE.y - LE.y }; + const roll = Math.abs( + (Math.atan2(Math.abs(earDiff.y), earDiff.x) * 180) / Math.PI, + ); + + // center_ratio = |NOSE.x - S.x| / ||R_s - L_s||_2D + const S_2D = { x: (LS.x + RS.x) / 2, y: (LS.y + RS.y) / 2 }; + const shoulderDiff = { x: RS.x - LS.x, y: RS.y - LS.y }; + const shoulderWidth2D = Math.sqrt( + shoulderDiff.x * shoulderDiff.x + shoulderDiff.y * shoulderDiff.y, + ); + const centerRatio = + shoulderWidth2D > 0 ? Math.abs(nose.x - S_2D.x) / shoulderWidth2D : 1; + + // 정면성 패스: |roll| ≤ 10°, center_ratio ≤ 0.15 + const pass = roll <= 10 && centerRatio <= 0.15; + + return { pass, roll, centerRatio }; +} + +// 상하 5% 절사 평균 및 표준편차 계산 +export function trimmedStats(values: number[], trimPercent: number = 0.05) { + if (values.length === 0) return { mean: 0, std: 0 }; + + const sorted = [...values].sort((a, b) => a - b); + const trimCount = Math.floor(sorted.length * trimPercent); + const trimmed = sorted.slice(trimCount, sorted.length - trimCount); + + if (trimmed.length === 0) return { mean: 0, std: 0 }; + + const mean = trimmed.reduce((sum, v) => sum + v, 0) / trimmed.length; + const variance = + trimmed.reduce((sum, v) => sum + (v - mean) ** 2, 0) / trimmed.length; + const std = Math.sqrt(variance); + + return { mean, std }; +} diff --git a/src/renderer/src/components/pose-detection/calibration.ts b/src/renderer/src/components/pose-detection/calibration.ts new file mode 100644 index 0000000..86234e9 --- /dev/null +++ b/src/renderer/src/components/pose-detection/calibration.ts @@ -0,0 +1,54 @@ +import { CalibrationState } from './types'; +import { checkFrontality } from './calculations'; +import { trimmedStats } from './calculations'; + +// 캘리브레이션 데이터 처리 +export function processCalibrationData( + frames: CalibrationState['frames'], + skipFrontalCheck: boolean = false, +) { + const nTotal = frames.length; + let nPass = 0; + const piValues: number[] = []; + + for (const frame of frames) { + const frontality = checkFrontality(frame.lms); + const shouldInclude = skipFrontalCheck || frontality.pass; + + if (shouldInclude && frame.pi !== null) { + // PI_EMA가 있으면 사용, 없으면 PI_raw 사용 (하위 호환성) + const piValue = + frame.pi_ema !== undefined ? frame.pi_ema : frame.pi.PI_raw; + piValues.push(piValue); + nPass++; + } + } + + if (piValues.length < 5) { + const passRate = ((nPass / nTotal) * 100).toFixed(1); + return { + success: false, + message: `정면성 통과 프레임이 너무 적습니다.\n통과: ${nPass}/${nTotal} (${passRate}%)\n\n💡 팁:\n- 정면을 바라보세요\n- 고개를 살짝 움직여보세요`, + }; + } + + const stats = trimmedStats(piValues, 0.05); + const passRate = nPass / nTotal; + + let quality: 'poor' | 'medium' | 'good' = 'poor'; + if (passRate >= 0.5 && stats.std < 0.2) { + quality = 'good'; + } else if (passRate >= 0.3 && stats.std < 0.3) { + quality = 'medium'; + } + + return { + success: true, + nTotal, + nPass, + mu_PI: stats.mean, + sigma_PI: stats.std, + quality, + passRate, + }; +} diff --git a/src/renderer/src/components/pose-detection/errorChecks.ts b/src/renderer/src/components/pose-detection/errorChecks.ts new file mode 100644 index 0000000..122e3fa --- /dev/null +++ b/src/renderer/src/components/pose-detection/errorChecks.ts @@ -0,0 +1,220 @@ +import { calculatePI } from './calculations'; +import { CalibrationFrame, PoseLandmark, WorldLandmark } from './types'; + +// 스텝 1: 측정 시작 전 체크 - "귀와 어깨가 일직선이 되도록 턱을 살짝 당겨주세요" +export function checkStep1Error( + landmarks: PoseLandmark[], + worldLandmarks: WorldLandmark[], +): string | null { + const pi = calculatePI(landmarks, worldLandmarks); + if (!pi) return null; + + if (pi.PI_raw > 0.7) { + return '귀와 어깨가 일직선이 되도록 턱을 살짝 당겨주세요'; + } + + return null; +} + +// 스텝 2: 측정 중 예외 케이스 체크 함수들 + +// 1. 얼굴과 어깨 visibility 체크 +export function checkLandmarkVisibility( + frames: CalibrationFrame[], +): string | null { + if (frames.length < 5) return null; + + const recentFrames = frames.slice(-10); + const requiredLandmarks = [7, 8, 11, 12]; // LEFT_EAR, RIGHT_EAR, LEFT_SHOULDER, RIGHT_SHOULDER + const minVisibility = 0.3; + + let lowVisibilityCount = 0; + for (const frame of recentFrames) { + const hasLowVisibility = requiredLandmarks.some((idx) => { + const lm = frame.lms[idx]; + return !lm || (lm.visibility || 0) < minVisibility; + }); + if (hasLowVisibility) lowVisibilityCount++; + } + + // 10개 중 8개 이상이 낮으면 경고 + if (lowVisibilityCount >= 8) { + return '얼굴과 어깨가 모두 보일 수 있게 뒤로 가주세요'; + } + return null; +} + +// 2. 거리 및 위치 체크 +export function checkDistanceAndPosition( + frames: CalibrationFrame[], +): string | null { + if (frames.length < 5) return null; + + const recentFrames = frames.slice(-10); + + // 평균 어깨 너비 계산 + const avgW = + recentFrames.reduce((sum, f) => { + const LS = f.worldLms[11]; + const RS = f.worldLms[12]; + if (!LS || !RS) return sum; + + const W = Math.sqrt( + Math.pow(RS.x - LS.x, 2) + + Math.pow(RS.y - LS.y, 2) + + Math.pow(RS.z - LS.z, 2), + ); + return sum + W; + }, 0) / recentFrames.length; + + // 평균 어깨 중심 위치 계산 + const avgShoulderCenter = recentFrames.reduce( + (sum, f) => { + const LS = f.lms[11]; + const RS = f.lms[12]; + if (!LS || !RS) return sum; + + const centerX = (LS.x + RS.x) / 2; + const centerY = (LS.y + RS.y) / 2; + return { + x: sum.x + centerX, + y: sum.y + centerY, + }; + }, + { x: 0, y: 0 }, + ); + + avgShoulderCenter.x /= recentFrames.length; + avgShoulderCenter.y /= recentFrames.length; + + const distanceFromCenter = Math.sqrt( + Math.pow(avgShoulderCenter.x - 0.5, 2) + + Math.pow(avgShoulderCenter.y - 0.5, 2), + ); + + // 너무 멀리 있거나 화면 중앙에서 벗어난 경우 + if (avgW < 0.03 || distanceFromCenter > 0.7) { + return '조금 더 가까이, 화면 중앙으로 와주세요'; + } + return null; +} + +// 비디오 프레임의 평균 밝기 계산 (0.0 ~ 1.0) +export function calculateFrameBrightness( + videoElement: HTMLVideoElement, +): number | null { + if (!videoElement || videoElement.readyState < 2) return null; + + try { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d', { willReadFrequently: true }); + if (!ctx) return null; + + canvas.width = videoElement.videoWidth || 640; + canvas.height = videoElement.videoHeight || 480; + + // 비디오 프레임을 캔버스에 그리기 + ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height); + + // 이미지 데이터 가져오기 + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const data = imageData.data; + + // RGB 값을 밝기(Luminance)로 변환 + // Luminance = 0.299*R + 0.587*G + 0.114*B + let totalBrightness = 0; + const pixelCount = data.length / 4; // RGBA이므로 4개씩 + + for (let i = 0; i < data.length; i += 4) { + const r = data[i]; + const g = data[i + 1]; + const b = data[i + 2]; + // Luminance 계산 (0~255 범위) + const luminance = 0.299 * r + 0.587 * g + 0.114 * b; + // 0.0 ~ 1.0 범위로 정규화 + totalBrightness += luminance / 255; + } + + return totalBrightness / pixelCount; + } catch (error) { + console.error('Failed to calculate frame brightness:', error); + return null; + } +} + +// 3. 밝기 체크 (실제 프레임 밝기 사용) +export function checkBrightness(frames: CalibrationFrame[]): string | null { + if (frames.length < 5) return null; + + const recentFrames = frames.slice(-15); + + // brightness 값이 있는 프레임만 필터링 + const framesWithBrightness = recentFrames.filter( + (frame) => frame.brightness !== undefined && frame.brightness !== null, + ); + + if (framesWithBrightness.length < 5) return null; + + // 평균 밝기 계산 + const avgBrightness = + framesWithBrightness.reduce((sum, frame) => { + return sum + (frame.brightness || 0); + }, 0) / framesWithBrightness.length; + + // 밝기가 0.2 미만이면 어둡다고 판단 (0.0 ~ 1.0 범위) + if (avgBrightness < 0.2) { + return '주변을 조금 더 밝게 해주세요'; + } + + return null; +} + +// 4. 자세 안정성 체크 +export function checkPostureStability( + frames: CalibrationFrame[], +): string | null { + // 최소 프레임 수 (5개 이상) + if (frames.length < 15) return null; + + // 최근 5개 프레임만 확인 + const recentFrames = frames.slice(-15); + const recentPIs = recentFrames.map((f) => { + // EMA 대신 PI_raw 사용 (변동을 더 정확히 감지하기 위해) + return f.pi.PI_raw; + }); + + // 표준편차 체크 + const mean = recentPIs.reduce((a, b) => a + b, 0) / recentPIs.length; + const variance = + recentPIs.reduce((sum, pi) => { + return sum + Math.pow(pi - mean, 2); + }, 0) / recentPIs.length; + const std = Math.sqrt(variance); + + // 연속된 프레임 간의 급격한 변화 체크 (포즈가 갑자기 감지될 때) + for (let i = 1; i < recentPIs.length; i++) { + const diff = Math.abs(recentPIs[i] - recentPIs[i - 1]); + // 연속된 프레임 간 차이가 0.3 이상이면 급격한 변화 + if (diff > 0.3) { + return '정확한 측정을 위해, 5초 동안 자세를 그대로 유지해주세요'; + } + } + + // 표준편차 임계값 완화 + if (std > 0.04) { + return '정확한 측정을 위해, 5초 동안 자세를 그대로 유지해주세요'; + } + + return null; +} + +// 스텝 2 에러 메시지 결정 (우선순위 순) +export function getStep2Error(frames: CalibrationFrame[]): string | null { + // Step 2 에러들 (우선순위 순) + return ( + checkLandmarkVisibility(frames) || + checkDistanceAndPosition(frames) || + checkBrightness(frames) || + checkPostureStability(frames) + ); +} diff --git a/src/renderer/src/components/pose-detection/index.ts b/src/renderer/src/components/pose-detection/index.ts new file mode 100644 index 0000000..6769577 --- /dev/null +++ b/src/renderer/src/components/pose-detection/index.ts @@ -0,0 +1,8 @@ +// Barrel export - 모든 것을 재수출하여 기존 import 경로 유지 +export * from './types'; +export * from './calculations'; +export * from './PostureClassifier'; +export * from './calibration'; +export * from './errorChecks'; +export * from './ScoreProcessor'; +export * from './PostureStabilizer'; diff --git a/src/renderer/src/components/pose-detection/types.ts b/src/renderer/src/components/pose-detection/types.ts new file mode 100644 index 0000000..19f6ac0 --- /dev/null +++ b/src/renderer/src/components/pose-detection/types.ts @@ -0,0 +1,61 @@ +// 포즈 랜드마크 타입 +export interface PoseLandmark { + x: number; + y: number; + z: number; + visibility?: number; +} + +export interface WorldLandmark { + x: number; + y: number; + z: number; + visibility?: number; +} + +// PI 지표 계산 결과 +export interface PIResult { + PI_raw: number; + S: { x: number; y: number; z: number }; + E: { x: number; y: number; z: number }; + W: number; +} + +// 정면성 검사 결과 +export interface FrontalityResult { + pass: boolean; + roll: number; + centerRatio: number; +} + +// 자세 판정 결과 +export interface PostureClassification { + text: string; + cls: 1 | 2 | 3 | 4 | 5 | 6 | 0; + zScore: number; + PI_EMA: number; + z_PI: number; + gamma: number; + Score: number; + events: string[]; +} + +// 캘리브레이션 상태 +export interface CalibrationState { + isCalibrating: boolean; + isCalibrated: boolean; + startTime: number; + frames: Array<{ + lms: PoseLandmark[]; + pi: PIResult; + worldLms: WorldLandmark[]; + pi_ema?: number; // EMA 적용된 PI 값 (선택적) + brightness?: number; // 프레임의 평균 밝기 (0.0 ~ 1.0) + }>; + mu_PI: number; + sigma_PI: number; + quality: 'poor' | 'medium' | 'good' | 'unknown'; +} + +// 캘리브레이션 프레임 타입 +export type CalibrationFrame = CalibrationState['frames'][number]; diff --git a/src/renderer/src/hooks/useModal.ts b/src/renderer/src/hooks/useModal.ts new file mode 100644 index 0000000..3ba1302 --- /dev/null +++ b/src/renderer/src/hooks/useModal.ts @@ -0,0 +1,27 @@ +import { useState } from 'react'; + +/** + * 모달 상태를 관리하는 훅 + * + * @example + * ```tsx + * const { isOpen, open, close } = useModal(); + * + * + * {isOpen && } + * ``` + */ +export const useModal = () => { + const [isOpen, setIsOpen] = useState(false); + + const open = () => setIsOpen(true); + const close = () => setIsOpen(false); + const toggle = () => setIsOpen((prev) => !prev); + + return { + isOpen, + open, + close, + toggle, + }; +}; diff --git a/src/renderer/src/hooks/useNotificationScheduler.ts b/src/renderer/src/hooks/useNotificationScheduler.ts new file mode 100644 index 0000000..d6ec139 --- /dev/null +++ b/src/renderer/src/hooks/useNotificationScheduler.ts @@ -0,0 +1,134 @@ +import { useEffect, useRef } from 'react'; +import { useNotificationStore } from '../store/useNotificationStore'; +import { usePostureStore } from '../store/usePostureStore'; + +/* 알림 스케줄러 훅 , 설정된 시간에 따라 시스템 알림을 자동으로 표시 */ +export const useNotificationScheduler = () => { + const { isAllow, stretching, turtleNeck } = useNotificationStore(); + const postureClass = usePostureStore((state) => state.postureClass); + + /* 타이머 저장 변수 */ + const stretchingTimerRef = useRef | null>( + null, + ); + const turtleNeckCheckRef = useRef | null>( + null, + ); + /* 거북목 상태 시작 시간 */ + const badPostureStartTime = useRef(null); + + /* 스트레칭 알림 표시 */ + const showStretchingNotification = async () => { + try { + await window.electronAPI.notification.show( + '스트레칭 시간이에요! 🧘', + `${stretching.interval}분이 지났어요. 잠시 스트레칭을 해보는 건 어떨까요?`, + ); + } catch (error) { + console.error('Failed to show stretching notification:', error); + } + }; + + /* 거북목 알림 표시 */ + const showTurtleNeckNotification = async () => { + try { + await window.electronAPI.notification.show( + '자세를 확인해주세요! 🐢', + `${turtleNeck.interval}분 동안 거북목 자세가 감지되었어요. 자세를 바로잡아주세요.`, + ); + } catch (error) { + console.error('Failed to show turtle neck notification:', error); + } + }; + + /* 스트레칭 타이머 설정 */ + useEffect(() => { + /* 기존 타이머 정리 */ + if (stretchingTimerRef.current) { + clearInterval(stretchingTimerRef.current); + stretchingTimerRef.current = null; + } + + /* 알림이 허용되고 스트레칭 알림이 활성화된 경우에만 타이머 시작 */ + if (isAllow && stretching.isEnabled && stretching.interval > 0) { + const intervalMs = stretching.interval * 60 * 1000; + + stretchingTimerRef.current = setInterval(() => { + showStretchingNotification(); + }, intervalMs); + + console.log(`✅ 스트레칭 알림 활성화: ${stretching.interval}분마다 알림`); + } else { + console.log('⏸️ 스트레칭 알림 비활성화'); + } + + /* 클린업: 컴포넌트 언마운트 시 타이머 정리 */ + return () => { + if (stretchingTimerRef.current) { + clearInterval(stretchingTimerRef.current); + stretchingTimerRef.current = null; + } + }; + }, [isAllow, stretching.isEnabled, stretching.interval]); + + /* 거북목 상태 추적 - postureClass가 4, 5, 6 (bugi 계열)일 때 시작 시간 기록 */ + useEffect(() => { + const isBadPosture = postureClass >= 4 && postureClass <= 6; + + if (isBadPosture) { + if (!badPostureStartTime.current) { + badPostureStartTime.current = Date.now(); + console.log('🐢 거북목 상태 시작'); + } + } else { + if (badPostureStartTime.current) { + console.log('✅ 정상 자세로 복귀'); + } + badPostureStartTime.current = null; + } + }, [postureClass]); + + /* 거북목 지속 시간 체크 - 설정된 시간 초과 시 알림 */ + useEffect(() => { + if (turtleNeckCheckRef.current) { + clearInterval(turtleNeckCheckRef.current); + turtleNeckCheckRef.current = null; + } + + if (isAllow && turtleNeck.isEnabled && turtleNeck.interval > 0) { + const thresholdMs = turtleNeck.interval * 60 * 1000; + + turtleNeckCheckRef.current = setInterval(() => { + if (badPostureStartTime.current) { + const duration = Date.now() - badPostureStartTime.current; + + if (duration >= thresholdMs) { + showTurtleNeckNotification(); + /* 알림 후 타이머 리셋 (다음 알림을 위해) */ + badPostureStartTime.current = Date.now(); + console.log(`🔔 거북목 알림 발송 (${turtleNeck.interval}분 지속)`); + } + } + }, 10000); /* 30초마다 체크 */ + + console.log( + `✅ 거북목 알림 활성화: ${turtleNeck.interval}분 지속 시 알림`, + ); + } else { + console.log('⏸️ 거북목 알림 비활성화'); + } + + return () => { + if (turtleNeckCheckRef.current) { + clearInterval(turtleNeckCheckRef.current); + turtleNeckCheckRef.current = null; + } + }; + }, [isAllow, turtleNeck.isEnabled, turtleNeck.interval]); + + /* 수동으로 알림을 트리거하는 함수들 (테스트용) */ + return { + showStretchingNotification, + showTurtleNeckNotification, + }; +}; diff --git a/src/renderer/src/hooks/useThemePreference.ts b/src/renderer/src/hooks/useThemePreference.ts new file mode 100644 index 0000000..b508e1b --- /dev/null +++ b/src/renderer/src/hooks/useThemePreference.ts @@ -0,0 +1,75 @@ +import { useEffect, useRef, useState } from 'react'; + +type UseThemePreferenceReturn = [boolean, (value: boolean) => void]; + +const THEME_STORAGE_KEY = 'theme'; + +export function useThemePreference(): UseThemePreferenceReturn { + const isApplyingSystemTheme = useRef(false); + + const [isDark, setIsDark] = useState(() => { + if (typeof window === 'undefined') { + return false; + } + + const savedTheme = window.localStorage.getItem(THEME_STORAGE_KEY); + if (savedTheme === 'dark' || savedTheme === 'light') { + return savedTheme === 'dark'; + } + + return false; + }); + + useEffect(() => { + if (typeof window === 'undefined') { + return; + } + + const savedTheme = window.localStorage.getItem(THEME_STORAGE_KEY); + + if (!savedTheme && window.electronAPI?.getSystemTheme) { + isApplyingSystemTheme.current = true; + window.electronAPI + .getSystemTheme() + .then((systemTheme: 'dark' | 'light') => { + const shouldBeDark = systemTheme === 'dark'; + setIsDark(shouldBeDark); + + if (shouldBeDark) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + + setTimeout(() => { + isApplyingSystemTheme.current = false; + }, 0); + }) + .catch((error: unknown) => { + console.error('시스템 테마 조회 실패:', error); + isApplyingSystemTheme.current = false; + }); + } else if (savedTheme) { + if (savedTheme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + } + }, []); + + useEffect(() => { + if (isDark) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + + if (!isApplyingSystemTheme.current) { + window.localStorage.setItem(THEME_STORAGE_KEY, isDark ? 'dark' : 'light'); + } + }, [isDark]); + + return [isDark, setIsDark]; +} + diff --git a/src/renderer/src/hooks/useWidget.ts b/src/renderer/src/hooks/useWidget.ts new file mode 100644 index 0000000..686133f --- /dev/null +++ b/src/renderer/src/hooks/useWidget.ts @@ -0,0 +1,74 @@ +import { useEffect, useState } from 'react'; + +/** + * 위젯 창 상태를 관리하는 훅 + * 위젯 창의 열림/닫힘 상태를 추적하고 토글 기능을 제공합니다. + * + * @example + * ```tsx + * const { isWidgetOpen, toggleWidget } = useWidget(); + * + * + * ``` + */ +export const useWidget = () => { + const [isWidgetOpen, setIsWidgetOpen] = useState(false); + + // 위젯 창 상태 주기적 확인 (1초마다) + useEffect(() => { + const checkWidgetStatus = async () => { + if (window.electronAPI?.widget) { + const isOpen = await window.electronAPI.widget.isOpen(); + setIsWidgetOpen(isOpen); + } + }; + + checkWidgetStatus(); + const interval = setInterval(checkWidgetStatus, 1000); + return () => clearInterval(interval); + }, []); + + // 위젯 로그 저장 헬퍼 함수 + const logWidgetEvent = async (event: 'widget_opened' | 'widget_closed') => { + if (window.electronAPI?.writeLog) { + try { + const logData = JSON.stringify({ + event, + timestamp: new Date().toISOString(), + }); + await window.electronAPI.writeLog(logData); + } catch (error) { + console.error( + `위젯 ${event === 'widget_opened' ? '열림' : '닫힘'} 로그 저장 실패:`, + error, + ); + } + } + }; + + // 위젯 토글 함수 + const toggleWidget = async () => { + try { + if (window.electronAPI?.widget) { + if (isWidgetOpen) { + await window.electronAPI.widget.close(); + setIsWidgetOpen(false); + console.log('위젯 창이 닫혔습니다'); + await logWidgetEvent('widget_closed'); + } else { + await window.electronAPI.widget.open(); + setIsWidgetOpen(true); + console.log('위젯 창이 열렸습니다'); + await logWidgetEvent('widget_opened'); + } + } + } catch (error) { + console.error('위젯 창 토글 실패:', error); + } + }; + + return { + isWidgetOpen, + toggleWidget, + }; +}; diff --git a/src/renderer/src/index.css b/src/renderer/src/index.css index f761ba0..9677945 100644 --- a/src/renderer/src/index.css +++ b/src/renderer/src/index.css @@ -1,16 +1,15 @@ +@import 'tailwindcss'; +@import './styles/globals.css'; + @font-face { font-family: 'Pretendard'; - src: url('../../assets/fonts/PretendardVariable.woff2') - format('woff2-variations'); + src: url('/fonts/PretendardVariable.woff2') format('woff2-variations'); font-weight: 100 900; font-style: normal; font-display: swap; } -@import 'tailwindcss'; -@import './styles/globals.css'; - -@source './**/*.{ts,tsx}'; +@source './**/*.{ts,tsx,js,jsx}'; /* web 앱에만 필요한 스타일이 있다면 여기에 추가합니다 */ body { @@ -28,5 +27,5 @@ body { 'Helvetica Neue', sans-serif; - @apply bg-[#F9F8F7]; + @apply bg-grey-25; } diff --git a/src/renderer/src/layout/Header/Header.tsx b/src/renderer/src/layout/Header/Header.tsx index 2ddcb61..1760b47 100644 --- a/src/renderer/src/layout/Header/Header.tsx +++ b/src/renderer/src/layout/Header/Header.tsx @@ -1,11 +1,19 @@ import Logo from '../../assets/logo.svg?react'; +import Symbol from '../../assets/symbol.svg?react'; +import { ThemeToggleSwitch } from '../../components/ThemeToggleSwitch/ThemeToggleSwitch'; +import { useThemePreference } from '../../hooks/useThemePreference'; const Header = () => { + const [isDark, setIsDark] = useThemePreference(); + return (
-
- - +
+
+ + +
+
); diff --git a/src/renderer/src/layout/Layout.tsx b/src/renderer/src/layout/Layout.tsx index b3c79f3..e8c990c 100644 --- a/src/renderer/src/layout/Layout.tsx +++ b/src/renderer/src/layout/Layout.tsx @@ -1,16 +1,11 @@ -import { Outlet, useLocation } from 'react-router-dom'; -import DevNavbar from '../components/DevNavbar/DevNavbar'; +import { Outlet } from 'react-router-dom'; import Header from './Header/Header'; const Layout = () => { - /* 로그인 페이지 헤더 숨김 */ - const location = useLocation(); - const hideHeader = location.pathname === '/auth/login'; - return ( -
- - {!hideHeader &&
} +
+ {/* */} +
); diff --git a/src/renderer/src/pages/Calibration/CalibrationPage.tsx b/src/renderer/src/pages/Calibration/CalibrationPage.tsx index 1201bc7..b0c4a10 100644 --- a/src/renderer/src/pages/Calibration/CalibrationPage.tsx +++ b/src/renderer/src/pages/Calibration/CalibrationPage.tsx @@ -1,12 +1,24 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { + useCallback, + useEffect, + useRef, + useState, + type RefObject, +} from 'react'; import { useNavigate } from 'react-router-dom'; +import Webcam from 'react-webcam'; +import CalibrationGuide from '../../assets/calibration_guide.svg?react'; import { PoseLandmark as AnalyzerPoseLandmark, + calculateFrameBrightness, calculatePI, + CalibrationFrame, + checkStep1Error, + getStep2Error, PIResult, processCalibrationData, WorldLandmark, -} from '../../components/pose-detection/PoseAnalyzer'; +} from '../../components/pose-detection'; import MeasuringPanel from './components/MeasuringPanel'; import WebcamView from './components/WebcamView'; import WelcomePanel from './components/WelcomePanel'; @@ -40,7 +52,6 @@ class EmaSmoother { const CalibrationPage = () => { const navigate = useNavigate(); const LOCAL_STORAGE_KEY = 'calibration_result_v1'; - const [isWebcamOn, setIsWebcamOn] = useState(true); // 기본적으로 웹캠 켜짐 const [detectedLandmarks, setDetectedLandmarks] = useState( [], ); @@ -58,9 +69,20 @@ const CalibrationPage = () => { lms: PoseLandmark[]; pi: PIResult; worldLms: WorldLandmark[]; + brightness?: number; }> >([]); + // 예외 케이스 에러 메시지 상태 + const [step1Error, setStep1Error] = useState(null); // Step 1 에러 (WelcomePanel용) + const [step2Error, setStep2Error] = useState(null); // Step 2 에러 (MeasuringPanel step={2}용) + + // 스텝 1: 최근 PI 값들을 저장하여 평균 계산 + const recentPIsRef = useRef([]); + + // 비디오 ref 저장 + const videoRefRef = useRef | null>(null); + const handlePoseDetected = ( landmarks: PoseLandmark[], detectedWorldLandmarks?: WorldLandmark[], @@ -75,11 +97,17 @@ const CalibrationPage = () => { // 캘리브레이션 시작 const startCalibration = useCallback(() => { + // 스텝 1 에러가 있으면 시작하지 않음 + if (step1Error) { + return; + } + setIsCalibrating(true); setCalibrationFrames([]); setCalibrationProgress(0); setRemainingTime(5); - }, []); + setStep2Error(null); + }, [step1Error]); // 캘리브레이션 중단 const stopCalibration = () => { @@ -94,31 +122,54 @@ const CalibrationPage = () => { }; // 측정하기 버튼 클릭 - const handleStartMeasurement = () => { - if (detectedLandmarks.length > 0) { + const handleStartMeasurement = useCallback(() => { + if (detectedLandmarks.length > 0 && !step1Error) { setTimeout(() => { startCalibration(); }, 1000); } - }; + }, [detectedLandmarks.length, step1Error, startCalibration]); // 캘리브레이션 처리 - useEffect(() => { - if (!isCalibrating) return; - - const frames: Array<{ + /* eslint-disable react-hooks/purity */ + const startTimeRef = useRef(Date.now()); + const framesRef = useRef< + Array<{ lms: PoseLandmark[]; pi: PIResult; worldLms: WorldLandmark[]; - pi_ema?: number; // EMA 적용된 PI 값 - }> = []; - const startTime = Date.now(); - const emaSmoother = new EmaSmoother(0.25); // 메인과 동일한 alpha 값 - emaSmoother.reset(); // 캘리브레이션 시작 시 초기화 + pi_ema?: number; + brightness?: number; + }> + >([]); + const emaSmootherRef = useRef(new EmaSmoother(0.25)); + + // 이전 에러 상태 추적용 ref + const prevStep2ErrorRef = useRef(null); + const errorResetTimeRef = useRef(0); + const ERROR_HOLD_DURATION = 500; // 에러 상태를 500ms 동안 유지 + + useEffect(() => { + if (!isCalibrating) return; + + // 캘리브레이션 시작 시 초기화 + startTimeRef.current = Date.now(); + framesRef.current = []; + emaSmootherRef.current.reset(); + setCalibrationProgress(0); + setRemainingTime(5); + setStep2Error(null); + prevStep2ErrorRef.current = null; + errorResetTimeRef.current = 0; + }, [isCalibrating]); + + // 캘리브레이션 타이머 및 데이터 수집 + useEffect(() => { + if (!isCalibrating) return; // 타이머 업데이트 (1초마다) const timerInterval = setInterval(() => { - const elapsed = Date.now() - startTime; + const elapsed = Date.now() - startTimeRef.current; const progress = Math.min(100, (elapsed / 5000) * 100); const remaining = Math.max(0, Math.ceil((5000 - elapsed) / 1000)); setCalibrationProgress(progress); @@ -128,9 +179,9 @@ const CalibrationPage = () => { clearInterval(timerInterval); clearInterval(dataInterval); stopCalibration(); - const result = processCalibrationData(frames, true); + const result = processCalibrationData(framesRef.current, true); if (result.success) { - setCalibrationFrames(frames); + setCalibrationFrames(framesRef.current); // 측정 완료 수치를 한 번만 콘솔에 출력 console.log('측정 완료 수치', { mu_PI: (result.mu_PI || 0).toFixed(4), @@ -165,7 +216,7 @@ const CalibrationPage = () => { } }, 1000); // 1초마다 타이머 업데이트 - // 데이터 수집 (100ms마다) + // 데이터 수집 및 스텝 2 예외 케이스 체크 (100ms마다) const dataInterval = setInterval(() => { const current2D = detectedLandmarksRef.current; const currentWorld = worldLandmarksRef.current; @@ -182,16 +233,71 @@ const CalibrationPage = () => { if (!pi) return; // EMA 적용 (메인과 동일한 방식) - const pi_ema = emaSmoother.next(pi.PI_raw); + const pi_ema = emaSmootherRef.current.next(pi.PI_raw); + + // 비디오 프레임의 밝기 계산 + let brightness: number | undefined = undefined; + if (videoRefRef.current?.current?.video) { + const brightnessValue = calculateFrameBrightness( + videoRefRef.current.current.video, + ); + if (brightnessValue !== null) { + brightness = brightnessValue; + } + } // const frontality = checkFrontality(current2D as AnalyzerPoseLandmark[]); - frames.push({ + framesRef.current.push({ lms: current2D, pi, worldLms: currentWorld, pi_ema, // EMA 적용된 값 저장 + brightness, // 프레임 밝기 저장 }); + + // frames가 너무 많이 쌓이지 않도록 제한 (최대 50개) + if (framesRef.current.length > 50) { + framesRef.current.shift(); // 가장 오래된 프레임 제거 + } + + // 스텝 1 에러 체크 (실시간) + const step1Err = checkStep1Error( + current2D as AnalyzerPoseLandmark[], + landmarksToUse, + ); + + // 스텝 1 에러가 발생했거나 계속 발생 중이면 시간 리셋 + if (step1Err) { + startTimeRef.current = Date.now(); + setCalibrationProgress(0); + setRemainingTime(5); + errorResetTimeRef.current = Date.now(); + setStep1Error(step1Err); + // Step 1 에러가 있으면 Step 2 체크 건너뛰기 + setStep2Error(null); + return; + } + + setStep1Error(step1Err); + + // 스텝 2 예외 케이스 실시간 체크 (충분한 프레임이 쌓인 후, Step 1 에러가 없을 때만) + if (framesRef.current.length >= 5) { + const error = getStep2Error(framesRef.current as CalibrationFrame[]); + + // 에러가 발생했거나 계속 발생 중이면 시간 리셋 (frames는 유지) + if (error) { + startTimeRef.current = Date.now(); + setCalibrationProgress(0); + setRemainingTime(5); + errorResetTimeRef.current = Date.now(); + } + + setStep2Error(error); + } else { + // 프레임이 충분하지 않으면 에러 초기화 + setStep2Error(null); + } }, 100); // 100ms마다 데이터 수집 return () => { @@ -200,22 +306,38 @@ const CalibrationPage = () => { }; }, [isCalibrating]); + // 상태에 따른 패딩 클래스 + const paddingClass = isCalibrating + ? 'minimum:px-[29px] labtop:px-[44px] desktop:px-[164px]' // MeasuringPanel 상태 + : 'minimum:px-[90px] labtop:px-[105px] desktop:px-[164px]'; // WelcomePanel 상태 + return ( -
-
+
+
{/* 메인 콘텐츠 영역 */}
{/* 왼쪽 웹캠 영역 */} - - {/* 오른쪽 안내 영역 - 상태별 컴포넌트 (완료 화면 제거) */} +
+ { + videoRefRef.current = ref; + }} + /> + {/* 캘리브레이션 가이드 오버레이 (캘리브레이션 중일 때만) */} + +
+ +
+
+ {/* 오른쪽 안내 영역 */} {isCalibrating ? ( - + ) : ( { +interface MeasuringPanelProps { + step1Error?: string | null; + step2Error?: string | null; +} + +const MeasuringPanel = ({ step1Error, step2Error }: MeasuringPanelProps) => { return ( -
+

- 바른 자세 기준점 등록 + 바른자세 기준점 등록

diff --git a/src/renderer/src/pages/Calibration/components/WebcamView.tsx b/src/renderer/src/pages/Calibration/components/WebcamView.tsx index 69c8ef4..4432a54 100644 --- a/src/renderer/src/pages/Calibration/components/WebcamView.tsx +++ b/src/renderer/src/pages/Calibration/components/WebcamView.tsx @@ -1,15 +1,16 @@ -import { useRef, useState } from 'react'; +import SleepIcon from '@assets/sleep.svg?react'; +import { useEffect, useRef, useState, type RefObject } from 'react'; import Webcam from 'react-webcam'; import { Timer } from '../../../components/Timer/Timer'; import { PoseLandmark, WorldLandmark, -} from '../../../components/pose-detection/PoseAnalyzer'; +} from '../../../components/pose-detection'; import PoseDetection from '../../../components/pose-detection/PoseDetection'; import PoseVisualizer from '../../../components/pose-detection/PoseVisualizer'; +import { useCameraStore } from '../../../store/useCameraStore'; interface WebcamViewProps { - isWebcamOn: boolean; onPoseDetected?: ( landmarks: PoseLandmark[], worldLandmarks?: WorldLandmark[], @@ -17,16 +18,25 @@ interface WebcamViewProps { showPoseOverlay?: boolean; showTimer?: boolean; remainingTime?: number; + onVideoRefReady?: (videoRef: RefObject) => void; } const WebcamView = ({ - isWebcamOn, onPoseDetected, showPoseOverlay = false, showTimer = false, remainingTime = 0, + onVideoRefReady, }: WebcamViewProps) => { const webcamRef = useRef(null); + + // 비디오 ref를 부모 컴포넌트에 전달 + useEffect(() => { + if (onVideoRefReady) { + onVideoRefReady(webcamRef as RefObject); + } + }, [onVideoRefReady]); + const containerRef = useRef(null); const [detectedLandmarks, setDetectedLandmarks] = useState( [], ); @@ -35,11 +45,37 @@ const WebcamView = ({ height: 428, }); - const videoConstraints = { - width: 760, - height: 428, - facingMode: 'user', - }; + // 초기 마운트 시 container 크기로 초기화 + useEffect(() => { + const container = containerRef.current; + if (container) { + const { clientWidth, clientHeight } = container; + if (clientWidth > 0 && clientHeight > 0) { + setVideoDimensions({ + width: clientWidth, + height: clientHeight, + }); + } + } + }, []); + + const { cameraState, setShow } = useCameraStore(); + const isWebcamOn = cameraState === 'show'; + + // 저장된 카메라 deviceId 사용 + const preferredDeviceId = localStorage.getItem('preferred-camera-device'); + + const videoConstraints = preferredDeviceId + ? { + deviceId: { exact: preferredDeviceId }, + width: 1000, + height: 563, + } + : { + facingMode: 'user', + width: 1000, + height: 563, + }; const handlePoseDetected = ( landmarks: PoseLandmark[], @@ -50,12 +86,11 @@ const WebcamView = ({ }; const handleUserMedia = (stream: MediaStream | null) => { - console.log('[WebcamView] handleUserMedia called, stream:', stream); if (stream) { + setShow(); const videoTrack = stream.getVideoTracks()[0]; if (videoTrack) { const settings = videoTrack.getSettings(); - console.log('[WebcamView] Video settings:', settings); setVideoDimensions({ width: settings.width || 760, height: settings.height || 428, @@ -74,20 +109,93 @@ const WebcamView = ({ } }; + // 카메라 스트림 정리 + useEffect(() => { + if (cameraState === 'hide' || cameraState === 'exit') { + if ( + webcamRef.current && + webcamRef.current.video && + webcamRef.current.video.srcObject + ) { + const stream = webcamRef.current.video.srcObject as MediaStream; + const tracks = stream.getTracks(); + tracks.forEach((track) => track.stop()); + } + } + }, [cameraState]); + + // containerRef 크기 변경 감지 + useEffect(() => { + const container = containerRef.current; + if (!container) return; + + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + const { width, height } = entry.contentRect; + if (width > 0 && height > 0) { + setVideoDimensions((prev) => { + // 카메라가 켜져있을 때는 실제 비디오 크기를 우선 사용 + if (cameraState === 'show' && webcamRef.current?.video) { + const video = webcamRef.current.video; + return { + width: video.videoWidth || width, + height: video.videoHeight || height, + }; + } + // 카메라가 꺼져있을 때는 container 크기 사용 + return { + width, + height, + }; + }); + } + } + }); + + resizeObserver.observe(container); + + return () => { + resizeObserver.disconnect(); + }; + }, [cameraState]); + + // 비디오 요소 크기 변경 감지 (카메라가 켜져있을 때) + useEffect(() => { + if (cameraState !== 'show') return; + + const video = webcamRef.current?.video; + if (!video) return; + + const handleResize = () => { + if (video.videoWidth > 0 && video.videoHeight > 0) { + setVideoDimensions({ + width: video.videoWidth, + height: video.videoHeight, + }); + } + }; + + video.addEventListener('loadedmetadata', handleResize); + video.addEventListener('resize', handleResize); + + return () => { + video.removeEventListener('loadedmetadata', handleResize); + video.removeEventListener('resize', handleResize); + }; + }, [cameraState]); + return ( -
- {isWebcamOn ? ( +
+ {cameraState === 'show' ? (
{showPoseOverlay && detectedLandmarks.length > 0 && (
)} + } onPoseDetected={handlePoseDetected} isEnabled={isWebcamOn} />
+ ) : cameraState === 'hide' ? ( +
+
+ 측정을 멈췄어요!
+ 준비되면 카메라 버튼을 눌러주세요. +
+
) : ( -
-
-
📹
-
웹캠이 꺼져있습니다
+
+
+
+ 오늘 한걸음 나아갔네요
+ 내일을 위해 쉬어요 + +
)} diff --git a/src/renderer/src/pages/Calibration/components/WelcomePanel.tsx b/src/renderer/src/pages/Calibration/components/WelcomePanel.tsx index 50a76c8..cb09f84 100644 --- a/src/renderer/src/pages/Calibration/components/WelcomePanel.tsx +++ b/src/renderer/src/pages/Calibration/components/WelcomePanel.tsx @@ -10,10 +10,10 @@ const WelcomePanel = ({ onStartMeasurement, }: WelcomePanelProps) => { return ( -
+

- 바른 자세 기준점 등록 + 바른자세 기준점 등록

거부기온앤온님의 바른 자세를 등록할 준비가 되셨다면 @@ -21,7 +21,6 @@ const WelcomePanel = ({ 측정하기 버튼을 눌러주세요.

- )} diff --git a/src/renderer/src/pages/Main/MainPage.tsx b/src/renderer/src/pages/Main/MainPage.tsx index 3b1d762..904cd12 100644 --- a/src/renderer/src/pages/Main/MainPage.tsx +++ b/src/renderer/src/pages/Main/MainPage.tsx @@ -1,30 +1,67 @@ import { useEffect, useRef, useState } from 'react'; -import DevNavbar from '../../components/DevNavbar/DevNavbar'; +import { useSaveMetricsMutation } from '../../api/session/useSaveMetricsMutation'; import { PoseLandmark as AnalyzerPoseLandmark, calculatePI, checkFrontality, PostureClassifier, WorldLandmark, -} from '../../components/pose-detection/PoseAnalyzer'; -import CharacterPanel from './components/CharacterPanel'; +} from '../../components/pose-detection'; +import { useCameraStore } from '../../store/useCameraStore'; +import { usePostureStore } from '../../store/usePostureStore'; +import { MetricData } from '../../types/main/session'; +import AttendacePanel from './components/AttendacePanel'; +import AveragePosturePanel from './components/AveragePosture/AveragePosturePanel'; import HighlightsPanel from './components/HighlightsPanel'; -import LevelProgressPanel from './components/LevelProgressPanel'; +import MainHeader from './components/MainHeader'; import MiniRunningPanel from './components/MiniRunningPanel'; -import SummaryPanel from './components/SummaryPanel'; -import TrendPanel from './components/TrendPanel'; +import PosePatternPanel from './components/PosePatternPanel'; import WebcamPanel from './components/WebcamPanel'; +import TotalDistancePanel from './components/TotalDistancePanel'; +import NotificationModal from '../../components/Modal/NotificationModal'; +import { ModalPortal } from '@ui/Modal/ModalPortal'; +import AverageGraphPannel from './components/AverageGraph/AverageGraphPannel'; +import { useModal } from '../../hooks/useModal'; +import { useNotificationScheduler } from '../../hooks/useNotificationScheduler'; const LOCAL_STORAGE_KEY = 'calibration_result_v1'; const MainPage = () => { - const [isWebcamOn, setIsWebcamOn] = useState(true); - const [statusText, setStatusText] = useState<'정상' | '거북목' | '측정중'>( - '측정중', - ); + const setStatus = usePostureStore((state) => state.setStatus); + const { cameraState, setHide, setShow } = useCameraStore(); + + // 메트릭 저장 mutation + const { mutate: saveMetrics } = useSaveMetricsMutation(); + + // 메트릭 데이터를 저장할 ref (리렌더링 방지) + const metricsRef = useRef([]); + + // 마지막 저장 시간을 추적 (1초마다 저장용) + const lastSaveTimeRef = useRef(0); const classifierRef = useRef(new PostureClassifier()); + const handleToggleWebcam = () => { + if (cameraState === 'show') { + setHide(); + } else { + setShow(); + } + }; + + // 메트릭을 서버로 전송하는 함수 + const sendMetricsToServer = () => { + const sessionId = localStorage.getItem('sessionId'); + if (sessionId && metricsRef.current.length > 0) { + saveMetrics({ + sessionId, + metrics: metricsRef.current, + }); + // 전송 후 메트릭 초기화 + metricsRef.current = []; + } + }; + // 캘리브레이션 로드 const calib = (() => { try { @@ -37,7 +74,7 @@ const MainPage = () => { } })(); - // 캘리브레이션이 로드될 때 EMA 초기화 + // 캘리브레이션이 로드될 때 초기화 useEffect(() => { if (calib) { classifierRef.current.reset(); @@ -45,7 +82,7 @@ const MainPage = () => { }, [calib]); const handleUserMediaError = () => { - setIsWebcamOn(false); + setHide(); }; const handlePoseDetected = async ( @@ -63,26 +100,29 @@ const MainPage = () => { if (!pi) return; const frontal = checkFrontality(landmarks); + // PostureClassifier가 내부적으로 안정화 로직을 처리함 const result = classifierRef.current.classify( pi, calib.mu, calib.sigma, frontal, ); - setStatusText(result.text as '정상' | '거북목'); - // 기존 결과 배열 가져오기 - const existingData = localStorage.getItem('classificationResult'); - const existingResults = existingData ? JSON.parse(existingData) : []; + // 안정화된 결과로 상태 업데이트 + setStatus(result.cls, result.Score); - // 배열이 아니면 새 배열로 시작 - const resultsArray = Array.isArray(existingResults) ? existingResults : []; + // 메트릭 데이터 수집 (1초마다 한 번씩만 저장) + const currentTime = Date.now(); + const timeSinceLastSave = currentTime - lastSaveTimeRef.current; - // 새 결과 추가 (Score만) - resultsArray.push(result.Score); - - // localStorage에 저장 - // localStorage.setItem('classificationResult', JSON.stringify(resultsArray)); + if (timeSinceLastSave >= 1000) { + // 1초(1000ms) 이상 지났으면 저장 + metricsRef.current.push({ + score: result.Score, + timestamp: new Date().toISOString(), + }); + lastSaveTimeRef.current = currentTime; + } // Electron 환경에서 로그 파일로 저장 if (typeof window !== 'undefined' && window.electronAPI?.writeLog) { @@ -101,31 +141,85 @@ const MainPage = () => { } }; + /* 모달 오픈 */ + const { isOpen, open: handleOpenModal, close: handleCloseModal } = useModal(); + + /* 알림 스케줄러 활성화 */ + useNotificationScheduler(); + return ( <> - -
- {/* 전체 레이아웃: 좌(콘텐츠) / 우(웹캠 패널) - 화면 꽉 차게 */} -
- {/* 좌측 콘텐츠 영역: 단일 Grid 구성 */} -
- - - - - -
- - {/* 우측 사이드 패널: 좌/우 구분선 */} - +
+ + +
+ {isOpen && ( + + + + )}
diff --git a/src/renderer/src/pages/Main/components/AttendacePanel.tsx b/src/renderer/src/pages/Main/components/AttendacePanel.tsx new file mode 100644 index 0000000..74ba183 --- /dev/null +++ b/src/renderer/src/pages/Main/components/AttendacePanel.tsx @@ -0,0 +1,219 @@ +import DownIcon from '@assets/arrow-narrow-down.svg?react'; +import UpIcon from '@assets/arrow-narrow-up.svg?react'; +import { useState } from 'react'; +import { IntensitySlider } from '../../../components/IntensitySlider/IntensitySlider'; +import { PageMoveButton } from '../../../components/PageMoveButton/PageMoveButton'; +import { PannelHeader } from '../../../components/PannelHeader/PannelHeader'; +import { ToggleSwitch } from '../../../components/ToggleSwitch/ToggleSwitch'; + +type CalendarProps = { year: number; month: number }; // month: 0~11 + +interface CircleProps { + level: number; // 1~5 + today: boolean; +} + +const LEVEL_COLORS = [ + 'bg-yellow-500', // 1레벨 + 'bg-yellow-400', // 2레벨 + 'bg-yellow-200', // 3레벨 + 'bg-yellow-100', // 4레벨 + 'bg-yellow-50', // 5레벨 +] as const; + +const Circle = ({ level, today }: CircleProps) => { + // 혹시 level이 1~5를 벗어나면 안전하게 클램프 + const clampedLevel = Math.min(Math.max(level, 1), LEVEL_COLORS.length); + const colorClass = LEVEL_COLORS[clampedLevel - 1]; + + return ( +
+ ); +}; + +const Calendar = ({ year, month }: CalendarProps) => { + const days = ['일', '월', '화', '수', '목', '금', '토']; + + const firstDayOfMonth = new Date(year, month, 1).getDay(); + const daysInMonth = new Date(year, month + 1, 0).getDate(); + + // 7의 배수 칸으로 맞추기 (마지막 주 패딩) + const totalCells = Math.ceil((firstDayOfMonth + daysInMonth) / 7) * 7; + const trailing = totalCells - (firstDayOfMonth + daysInMonth); + + const calendarDays: (number | null)[] = [ + ...(Array(firstDayOfMonth).fill(null) as (number | null)[]), + ...Array.from({ length: daysInMonth }, (_, i) => i + 1), + ...(Array(trailing).fill(null) as (number | null)[]), + ]; + + // 오늘 정보 + const today = new Date(); + const todayYear = today.getFullYear(); + const todayMonth = today.getMonth(); + const todayDate = today.getDate(); + + const isSameMonth = todayYear === year && todayMonth === month; + + // 🔥 레벨/사용 여부는 실제 데이터 들어오면 여기만 갈아끼우면 됨 + const getLevelForDay = (day: number): number | null => { + // 예시: 4의 배수 날짜는 "안 사용한 날"이라고 가정해서 null 리턴 + if (day % 4 === 0) return null; + + // 그 외에는 1~5 레벨 순환 + return ((day - 1) % LEVEL_COLORS.length) + 1; + }; + + const isFutureDay = (day: number) => { + // 같은 달 기준으로 오늘 이후 + if (year > todayYear) return true; + if (year === todayYear && month > todayMonth) return true; + if (year === todayYear && month === todayMonth && day > todayDate) + return true; + return false; + }; + + return ( +
+ {/* 요일 헤더 */} +
+ {days.map((day, i) => ( +
+ {day} +
+ ))} +
+ + {/* 이번 달 칸만 동그라미 */} +
+ {calendarDays.map((day, index) => ( +
+ {day !== null && + (() => { + const future = isFutureDay(day); + const isToday = isSameMonth && day === todayDate; + + if (future) { + // 👉 미래 날짜: bg-transparent border-bg-line + return ( +
+ ); + } + + const level = getLevelForDay(day); + + if (!level) { + // 👉 안 사용한 날: bg-grey-50 + return ( +
+ ); + } + + // 👉 사용한 날: 레벨 색 Circle + return ; + })()} +
+ ))} +
+
+ ); +}; + +const AttendacePanel = () => { + // 오늘 월(1일)로 정규화 + const today = new Date(); + const todayYm = new Date(today.getFullYear(), today.getMonth(), 1); + + const [viewDate, setViewDate] = useState(todayYm); + const viewYear = viewDate.getFullYear(); + const viewMonth = viewDate.getMonth(); // 0~11 + + const clampToTodayMonth = (d: Date) => { + const y = d.getFullYear(); + const m = d.getMonth(); + const ty = todayYm.getFullYear(); + const tm = todayYm.getMonth(); + if (y > ty || (y === ty && m > tm)) return todayYm; // 미래 달로 못감 + return d; + }; + + const addMonthsSafe = (base: Date, delta: number) => + clampToTodayMonth(new Date(base.getFullYear(), base.getMonth() + delta, 1)); + + const isAtCurrentMonth = + viewYear === todayYm.getFullYear() && viewMonth === todayYm.getMonth(); + + return ( +
+
+ 출석 현황 +
+ {viewMonth + 1}월 +
+
+ + {/* ←/→ 월 이동 버튼 */} +
+
+ setViewDate((d) => addMonthsSafe(d, -1))} + /> + setViewDate((d) => addMonthsSafe(d, +1))} + disabled={isAtCurrentMonth} + /> +
+
+ +
+ +
+ { }} + /> + +
+ +
+ +
+ +
+
+
+ 잘하고 있어요 +
+
+
+ + 첫날보다 기린 시간이 하루 평균 45분 늘었어요 +
+
+ + 가장 나빴던 뽀각거부기 상태가 80% 감소했어요 +
+
+
+
+
+ 당신은 매일 골든리트리버 한 마리를 목에 업고 작업한 것과 같아요 🥺 +
+
+
+ ); +}; + +export default AttendacePanel; diff --git a/src/renderer/src/pages/Main/components/AverageGraph/AverageGraphPannel.tsx b/src/renderer/src/pages/Main/components/AverageGraph/AverageGraphPannel.tsx new file mode 100644 index 0000000..57c2c64 --- /dev/null +++ b/src/renderer/src/pages/Main/components/AverageGraph/AverageGraphPannel.tsx @@ -0,0 +1,116 @@ +import { useState } from 'react'; +import { + Area, + AreaChart, + CartesianGrid, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; +import { PannelHeader } from '@ui/PannelHeader/PannelHeader'; +import { ToggleSwitch } from '@ui/ToggleSwitch/ToggleSwitch'; +import { + useAverageGraphChart, + type AverageGraphPeriod, +} from './hooks/useAverageGraphChart'; + +const AverageGraphPannel = () => { + const [activePeriod, setActivePeriod] = + useState('weekly'); + + const { data, maxDomain, fillColor, strokeColor, gridColor, yAxisTicks } = + useAverageGraphChart(activePeriod); + + const handleToggleChange = (isMonthly: boolean) => { + setActivePeriod(isMonthly ? 'monthly' : 'weekly'); + }; + + /* 월간일 때는 12개 항목이 부모 너비 100%를 차지하도록 설정 */ + /* 12개 이하면 항상 100%, 12개 초과면 스크롤로 나머지 데이터 표시 */ + const chartWidth = + activePeriod === 'monthly' && data.length > 12 + ? (`${(100 / 12) * data.length}%` as `${number}%`) + : '100%'; + + /* 월간일 때만 스크롤 o */ + const showScroll = activePeriod === 'monthly' && data.length > 12; + + return ( +
+
+ 바른 자세 점수 + +
+

+ + 점수 +

+ + {/* 시계열 그래프 */} +
+ + + + + + + + + + + + {/* 그래프 hover시 스코어 표기 */} + ''} + itemStyle={{ fontSize: 12 }} + /> + + + +
+
+ ); +}; + +export default AverageGraphPannel; diff --git a/src/renderer/src/pages/Main/components/AverageGraph/hooks/useAverageGraphChart.ts b/src/renderer/src/pages/Main/components/AverageGraph/hooks/useAverageGraphChart.ts new file mode 100644 index 0000000..f3648cf --- /dev/null +++ b/src/renderer/src/pages/Main/components/AverageGraph/hooks/useAverageGraphChart.ts @@ -0,0 +1,84 @@ +import { useEffect, useMemo, useState } from 'react'; +import { getColor } from '@utils/getColor'; +import { usePostureGraphQuery } from '@api/dashboard/usePostureGraphQuery'; + +type AverageGraphDatum = { + periodLabel: string; + score: number; +}; + +export type AverageGraphPeriod = 'weekly' | 'monthly'; + +type ChartConfig = { + data: AverageGraphDatum[]; + maxDomain: number; + fillColor: string; + strokeColor: string; + gridColor: string; + yAxisTicks: number[]; +}; + +export function useAverageGraphChart(activePeriod: AverageGraphPeriod) { + const [isDark, setIsDark] = useState(() => + document.documentElement.classList.contains('dark'), + ); + + const { data: apiData } = usePostureGraphQuery(); + + /* html의 class 속성 변경될 때마다 콜백 실행(다크모드 감지) */ + useEffect(() => { + const observer = new MutationObserver(() => { + setIsDark(document.documentElement.classList.contains('dark')); + }); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + return () => observer.disconnect(); + }, []); + + /* 그래프 색상 */ + const chartConfig = useMemo(() => { + const gridColorValue = getColor('--color-grey-50', '#efeeed'); + const fillColorValue = getColor('--color-yellow-200', '#ffe28a'); + const strokeColorValue = getColor( + '--color-sementic-brand-primary', + '#ffbf00', + ); + + /* API 데이터를 그래프 형식으로 변환 */ + let data: AverageGraphDatum[] = []; + if (apiData?.data?.points) { + const points = apiData.data.points; + const sortedEntries = Object.entries(points).sort(([dateA], [dateB]) => + dateA.localeCompare(dateB), + ); + + /* 주간: 최근 7일, 월간: 전체 31일 */ + const slicedEntries = + activePeriod === 'weekly' ? sortedEntries.slice(-7) : sortedEntries; + + data = slicedEntries.map(([date, score]) => ({ + periodLabel: new Date(date).getDate().toString(), + score, + })); + } + + /* 최댓값 100 */ + const domainMax = 100; + + /* y축 눈금 */ + const ticks: number[] = [25, 50, 75, 100]; + + return { + data, + maxDomain: domainMax, + fillColor: fillColorValue, + strokeColor: strokeColorValue, + gridColor: gridColorValue, + yAxisTicks: ticks, + }; + }, [activePeriod, isDark, apiData]); + + return chartConfig; +} diff --git a/src/renderer/src/pages/Main/components/AveragePosture/AveragePosturePanel.tsx b/src/renderer/src/pages/Main/components/AveragePosture/AveragePosturePanel.tsx new file mode 100644 index 0000000..09135f6 --- /dev/null +++ b/src/renderer/src/pages/Main/components/AveragePosture/AveragePosturePanel.tsx @@ -0,0 +1,45 @@ +import { useAverageScoreQuery } from '../../../../api/dashboard/useAverageScoreQuery'; +import { LEVEL_INFO, getLevel } from './levelConfig'; + +const AveragePosturePanel = () => { + const { data, isLoading } = useAverageScoreQuery(); + const score = data?.data.score ?? 0; + const level = getLevel(score); + const levelInfo = LEVEL_INFO[level - 1]; + + return ( +
+
+

+ 평균 자세 점수 + + {isLoading ? '-' : `${score}점`} + + + 목 평균 기울기 {levelInfo.tilt} +
+ 예상 하중 {levelInfo.weight} +
+

+

+ + {levelInfo.name} + + {levelInfo.name} +

+
+ +
+

+ Step. {level} +

+
+
+ ); +}; + +export default AveragePosturePanel; diff --git a/src/renderer/src/pages/Main/components/AveragePosture/levelConfig.ts b/src/renderer/src/pages/Main/components/AveragePosture/levelConfig.ts new file mode 100644 index 0000000..2b60c6b --- /dev/null +++ b/src/renderer/src/pages/Main/components/AveragePosture/levelConfig.ts @@ -0,0 +1,61 @@ +import stepOneCharacter from '../../../../assets/main/averagePosture/step_one_character.png'; +import stepTwoCharacter from '../../../../assets/main/averagePosture/step_two_character.png'; +import stepThreeCharacter from '../../../../assets/main/averagePosture/step_three_character.png'; +import stepFourCharacter from '../../../../assets/main/averagePosture/step_four_character.png'; +import stepFiveCharacter from '../../../../assets/main/averagePosture/step_five_character.png'; + +export interface LevelInfo { + level: number; + name: string; + tilt: string; + weight: string; + character: string; +} + +// 점수에 따른 레벨 정보 +export const LEVEL_INFO: LevelInfo[] = [ + { + level: 1, + name: '뽀각거부기', + tilt: '약 55–60°', + weight: '약 26–27 kg', + character: stepOneCharacter, + }, + { + level: 2, + name: '꾸부정 거북기', + tilt: '약 40–45°', + weight: '약 20–22 kg', + character: stepTwoCharacter, + }, + { + level: 3, + name: '아기기린', + tilt: '약 25–30°', + weight: '약 16–18 kg', + character: stepThreeCharacter, + }, + { + level: 4, + name: '쑥쑥기린', + tilt: '약 10–15°', + weight: '약 10–12 kg', + character: stepFourCharacter, + }, + { + level: 5, + name: '꼿꼿기린', + tilt: '약 0–5°', + weight: '약 5–6 kg', + character: stepFiveCharacter, + }, +]; + +// 점수에 따른 레벨 계산 +export const getLevel = (score: number): number => { + if (score < 35) return 1; + if (score < 55) return 2; + if (score < 72) return 3; + if (score < 88) return 4; + return 5; +}; diff --git a/src/renderer/src/pages/Main/components/ExitPanel.tsx b/src/renderer/src/pages/Main/components/ExitPanel.tsx new file mode 100644 index 0000000..e5617ed --- /dev/null +++ b/src/renderer/src/pages/Main/components/ExitPanel.tsx @@ -0,0 +1,280 @@ +import { useEffect, useMemo, useState } from 'react'; +import { Cell, Pie, PieChart, ResponsiveContainer } from 'recharts'; +import { useSessionReportQuery } from '../../../api/session/useSessionReportQuery'; + +const ExitPanel = () => { + const [sessionId, setSessionId] = useState(null); + + // localStorage에서 sessionId 가져오기 (없으면 lastSessionId 사용) + /* eslint-disable react-hooks/set-state-in-effect */ + useEffect(() => { + const id = + localStorage.getItem('sessionId') || + localStorage.getItem('lastSessionId'); + if (id && id !== sessionId) { + setSessionId(id); + } + }, []); + + // 세션 리포트 조회 + const { data, isLoading, error } = useSessionReportQuery(sessionId); + + // 다크모드 상태 (간단한 방법) + const [isDark, setIsDark] = useState(() => + document.documentElement.classList.contains('dark'), + ); + + useEffect(() => { + const observer = new MutationObserver(() => { + setIsDark(document.documentElement.classList.contains('dark')); + }); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + return () => observer.disconnect(); + }, []); + + // CSS 변수에서 색상 가져오기 + const getColor = (cssVar: string, fallback: string) => { + return ( + getComputedStyle(document.documentElement) + .getPropertyValue(cssVar) + .trim() || fallback + ); + }; + + // 예시 데이터 , 세션 조회 api 수정 후 수정하기 + const totalTime = 169; // 총 169분 (2시간 49분) + const correctPostureTime = 54; // 바른 자세 시간 (분) + const correctPosturePercentage = Math.round( + (correctPostureTime / totalTime) * 100, + ); // 32% + const score = 80; // 바른 자세 점수 + + // CSS 변수에서 색상 가져오기 (다크모드 변경 시 재계산) + const colors = useMemo( + () => ({ + time: getColor('--color-point-green', '#22c55e'), + background: getColor('--color-grey-25', '#e5e7eb'), + score: getColor('--color-yellow-500', '#fbbf24'), + }), + [isDark], + ); + + // 안쪽 링 배경 데이터 (회색) - 전체를 회색으로 채움 + const innerBackgroundData = useMemo( + () => [{ name: '배경', value: 100, color: colors.background }], + [colors.background], + ); + + // 안쪽 링 프로그레스 데이터 (노란색) - 바른 자세 점수만큼 노란색 + const ScoreProgressData = useMemo( + () => [{ name: '바른 자세 점수', value: score, color: colors.score }], + [score, colors.score], + ); + + // 바깥쪽 링 배경 데이터 (회색) - 전체를 회색으로 채움 + const BackgroundData = useMemo( + () => [{ name: '배경', value: 100, color: colors.background }], + [colors.background], + ); + + // 바깥쪽 링 프로그레스 데이터 (녹색) - 바른 자세 비율만큼 녹색 + const TimeProgressData = useMemo( + () => [ + { + name: '바른 자세 시간', + value: correctPosturePercentage, + color: colors.time, + }, + ], + [correctPosturePercentage, colors.time], + ); + + const formatTime = (minutes: number) => { + const hours = Math.floor(minutes / 60); + const mins = minutes % 60; + return `${hours}시간 ${mins}분`; + }; + + // 로딩 중 + if (isLoading) { + return ( +
+
+
+

+ 리포트를 불러오는 중... +

+
+
+
+ ); + } + + // 에러 발생 + if (error) { + return ( +
+
+
+

+ 리포트를 불러올 수 없습니다 +

+
+
+
+ ); + } + + // 데이터 없음 + if (!data) { + return ( +
+
+
+

+ 세션 데이터가 없습니다 +

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

+ 오늘의 리포트 +

+

+ 뽀각거부기 2cm 성장 +

+
+ + {/* 도넛 차트 */} +
+ + + {/* 1. 바깥쪽 링 배경 (회색, 둥글지 않음) */} + + + + + {/* 2. 바깥쪽 링 프로그레스 (녹색, 둥글게) */} + + + + + {/* 3. 안쪽 링 배경 (회색, 둥글지 않음) */} + + + + + {/* 4. 안쪽 링 프로그레스 (노란색, 둥글게) */} + + + + + + + {/* 중앙 텍스트 */} +
+

사용시간

+

+ {formatTime(totalTime)} +

+
+
+ + {/* 하단 지표 */} +
+
+
+
+ + 바른 자세 시간 + +
+

+ {correctPosturePercentage}% +

+
+ +
+
+
+ + 바른 자세 점수 + +
+

+ {score}점 +

+
+
+
+
+ ); +}; + +export default ExitPanel; diff --git a/src/renderer/src/pages/Main/components/HighlightsPanel.tsx b/src/renderer/src/pages/Main/components/HighlightsPanel.tsx index 6d4c56e..ee38ac6 100644 --- a/src/renderer/src/pages/Main/components/HighlightsPanel.tsx +++ b/src/renderer/src/pages/Main/components/HighlightsPanel.tsx @@ -1,13 +1,178 @@ +import { useState } from 'react'; +import { + Bar, + BarChart, + CartesianGrid, + Cell, + LabelList, + ResponsiveContainer, + XAxis, + YAxis, +} from 'recharts'; + +import { PannelHeader } from '../../../components/PannelHeader/PannelHeader'; +import { ToggleSwitch } from '../../../components/ToggleSwitch/ToggleSwitch'; +import type { HighlightDatum } from './HighlightsPanel/data'; +import { + useHighlightsChart, + type HighlightPeriod, +} from './HighlightsPanel/hooks/useHighlightsChart'; + const HighlightsPanel = () => { + const [activePeriod, setActivePeriod] = useState('weekly'); + + const { + data, + unitLabel, + maxDomain, + barSize, + barRadius, + categoryGap, + chartColors, + labelColor, + previousLabelColor, + labelStyle, + labelPosition, + gridColor, + yAxisTicks, + } = useHighlightsChart(activePeriod); + + const handleToggleChange = (isMonthly: boolean) => { + setActivePeriod(isMonthly ? 'monthly' : 'weekly'); + }; + return ( -
-
-

하이라이트

-
- 주간 -
+
+
+ 하이라이트 + +
+ +
+ + {unitLabel} + +
+ +
+ + + {/* 이번주/이번달(진한색), 저번주/저번달(연한색)용 그라디언트 정의 */} + + + + + + + + + + + + + + + + + + + {data.map((datum: HighlightDatum) => ( + + ))} + + { + const { value, index, viewBox } = props; + if (viewBox == null || index == null) return null; + + const { x, y, width, height } = viewBox as { + x: number; + y: number; + width: number; + height: number; + }; + + const datum = data[index] as HighlightDatum; + const isCurrent = datum.barKey === 'current'; + + // 막대 중앙 좌표 + const cx = x + width / 2; + const cy = y + height / 2; + + const fill = isCurrent ? labelColor : previousLabelColor; + + let text: string; + if (typeof value === 'number') text = value.toString(); + else if (typeof value === 'string') text = value; + else return null; + + return ( + + {text} + + ); + }} + /> + + +
-
); }; diff --git a/src/renderer/src/pages/Main/components/HighlightsPanel/data.ts b/src/renderer/src/pages/Main/components/HighlightsPanel/data.ts new file mode 100644 index 0000000..87d3128 --- /dev/null +++ b/src/renderer/src/pages/Main/components/HighlightsPanel/data.ts @@ -0,0 +1,23 @@ +export type HighlightDatum = { + periodLabel: string; + value: number; + barKey: 'previous' | 'current'; +}; + +export const WEEKLY_DATA: HighlightDatum[] = [ + { + periodLabel: '저번 주', + value: 257, + barKey: 'previous', + }, + { + periodLabel: '이번 주', + value: 321, + barKey: 'current', + }, +]; + +export const MONTHLY_DATA: HighlightDatum[] = [ + { periodLabel: '저번 달', value: 210, barKey: 'previous' }, + { periodLabel: '이번 달', value: 225, barKey: 'current' }, +]; diff --git a/src/renderer/src/pages/Main/components/HighlightsPanel/hooks/useHighlightsChart.ts b/src/renderer/src/pages/Main/components/HighlightsPanel/hooks/useHighlightsChart.ts new file mode 100644 index 0000000..e8174c5 --- /dev/null +++ b/src/renderer/src/pages/Main/components/HighlightsPanel/hooks/useHighlightsChart.ts @@ -0,0 +1,125 @@ +import { useEffect, useMemo, useState } from 'react'; +import { getColor } from '../../../../../utils/getColor'; +import { MONTHLY_DATA, WEEKLY_DATA, type HighlightDatum } from '../data'; + +export type HighlightPeriod = 'weekly' | 'monthly'; + +type ChartColors = { + previous: string; + current: string; +}; + +type ChartConfig = { + data: HighlightDatum[]; + unitLabel: string; + maxDomain: number; + barSize: number; + barRadius: [number, number, number, number]; + categoryGap: number; + chartColors: ChartColors; + // 라벨 색 분리 + labelColor: string; // current(이번 주/달) 라벨 색 + previousLabelColor: string; // previous(저번 주/달) 라벨 색 + labelStyle: { + fontSize: number; + fontWeight: number; + fill: string; + }; + labelPosition: 'center' | 'top' | 'insideTop'; + gridColor: string; + yAxisTickColor: string; + yAxisTicks: number[]; +}; + +export function useHighlightsChart(activePeriod: HighlightPeriod): ChartConfig { + // 다크모드 상태 감지 + const [isDark, setIsDark] = useState(() => + document.documentElement.classList.contains('dark'), + ); + + useEffect(() => { + const observer = new MutationObserver(() => { + setIsDark(document.documentElement.classList.contains('dark')); + }); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + return () => observer.disconnect(); + }, []); + + // CSS 변수에서 색상 가져오기 (다크모드 변경 시 재계산) + const chartColors = useMemo( + () => ({ + previous: getColor('--color-grey-100', '#e3e1df'), // 저번 주/달 바 색 + current: getColor('--color-sementic-brand-primary', '#ffbf00'), // 이번 주/달 바 색 + }), + [isDark], + ); + + const chartConfig = useMemo(() => { + const gridColorValue = getColor('--color-grey-50', '#efeeed'); + const yAxisTickColorValue = getColor('--color-grey-300', '#a8a7a4'); + + const currentLabelColor = getColor('--color-yellow-50', '#fff9e6'); // 이번 주/달 라벨 + const prevLabelColor = getColor('--color-grey-0', '#ffffff'); // 저번 주/달 라벨 + + // 공통 스타일 + const baseConfig = { + unitLabel: '단위: 분/일', + barSize: 130, + barRadius: [8, 8, 0, 0] as [number, number, number, number], + categoryGap: 64, + chartColors, + labelColor: currentLabelColor, + previousLabelColor: prevLabelColor, + labelStyle: { + fontSize: 22, + fontWeight: 700, + fill: currentLabelColor, + }, + labelPosition: 'center' as const, + gridColor: gridColorValue, + yAxisTickColor: yAxisTickColorValue, + }; + + const domainPadding = 40; + + if (activePeriod === 'weekly') { + const calculatedMaxValue = + WEEKLY_DATA.reduce((acc, item) => Math.max(acc, item.value), 0) + + domainPadding; + const maxValue = Math.ceil(calculatedMaxValue / 100) * 100; + const ticks: number[] = Array.from( + { length: maxValue / 100 + 1 }, + (_, i) => i * 100, + ); + + return { + ...baseConfig, + data: WEEKLY_DATA, + maxDomain: maxValue, + yAxisTicks: ticks, + }; + } + + // activePeriod === 'monthly' + const calculatedMaxValue = + MONTHLY_DATA.reduce((acc, item) => Math.max(acc, item.value), 0) + + domainPadding; + const maxValue = Math.ceil(calculatedMaxValue / 100) * 100; + const ticks: number[] = Array.from( + { length: maxValue / 100 + 1 }, + (_, i) => i * 100, + ); + + return { + ...baseConfig, + data: MONTHLY_DATA, + maxDomain: maxValue, + yAxisTicks: ticks, + }; + }, [activePeriod, chartColors]); + + return chartConfig; +} diff --git a/src/renderer/src/pages/Main/components/MainHeader.tsx b/src/renderer/src/pages/Main/components/MainHeader.tsx new file mode 100644 index 0000000..1d62821 --- /dev/null +++ b/src/renderer/src/pages/Main/components/MainHeader.tsx @@ -0,0 +1,90 @@ +import DashboardIcon from '@assets/dashboard.svg?react'; +import SettingIcon from '@assets/setting.svg?react'; +import { useState } from 'react'; +import Logo from '../../../assets/logo.svg?react'; +import NotificationIcon from '../../../assets/main/bell_icon.svg?react'; +import Symbol from '../../../assets/symbol.svg?react'; +import { Button } from '../../../components/Button/Button'; + +import { ThemeToggleSwitch } from '../../../components/ThemeToggleSwitch/ThemeToggleSwitch'; +import { useThemePreference } from '../../../hooks/useThemePreference'; +import { cn } from '../../../utils/cn'; + +type TabType = 'dashboard' | 'plan' | 'settings'; + +interface MainHeaderProps { + onClickNotification?: () => void; +} + +const MainHeader = ({ onClickNotification }: MainHeaderProps) => { + const [isDark, setIsDark] = useThemePreference(); + + const [activeTab, setActiveTab] = useState('dashboard'); + + const tabs = [ + { id: 'dashboard' as TabType, label: '대시보드', icon: DashboardIcon }, + { id: 'settings' as TabType, label: '설정', icon: SettingIcon }, + ]; + + return ( +
+ {/* 타이틀 영역 */} +
+
+ + +
+ + {/* 네비게이션 탭 */} + +
+ +
+ +
+
+ ); +}; + +export default MainHeader; diff --git a/src/renderer/src/pages/Main/components/MiniRunningPanel.tsx b/src/renderer/src/pages/Main/components/MiniRunningPanel.tsx index 8a20f42..7956f3e 100644 --- a/src/renderer/src/pages/Main/components/MiniRunningPanel.tsx +++ b/src/renderer/src/pages/Main/components/MiniRunningPanel.tsx @@ -1,28 +1,12 @@ -interface Props { - statusText: '정상' | '거북목' | '측정중'; -} +import { useCameraStore } from '../../../store/useCameraStore'; +import ExitPanel from './ExitPanel'; +import RunningPanel from './RunningPanel'; -const MiniRunningPanel = ({ statusText }: Props) => { - const badgeClass = - statusText === '거북목' - ? 'bg-error-50 text-error-600' - : statusText === '정상' - ? 'bg-success-50 text-success-600' - : 'bg-grey-50 text-grey-600'; +const MiniRunningPanel = () => { + const { cameraState } = useCameraStore(); + const isExit = cameraState === 'exit'; - return ( -
-
-

업급업급 가는중..

- - {statusText} - -
-
-
- ); + return isExit ? : ; }; export default MiniRunningPanel; diff --git a/src/renderer/src/pages/Main/components/PosePatternPanel.tsx b/src/renderer/src/pages/Main/components/PosePatternPanel.tsx new file mode 100644 index 0000000..1375c96 --- /dev/null +++ b/src/renderer/src/pages/Main/components/PosePatternPanel.tsx @@ -0,0 +1,107 @@ +import * as React from 'react'; + +import CalendarIcon from '@assets/calendar.svg?react'; +import ChevronRigthIcon from '@assets/chevron-right.svg?react'; +import ClockIcon from '@assets/clock.svg?react'; +import GlassHourIcon from '@assets/hourglass.svg?react'; +import TumbupIcon from '@assets/thumbup.svg?react'; +import { PannelHeader } from '../../../components/PannelHeader/PannelHeader'; + +type PatternHeaderIcon = 'thumb' | 'clock' | 'calendar' | 'hourglass'; + +interface PatternHeaderProps { + children?: React.ReactNode; + icon: PatternHeaderIcon; + className?: string; + iconSize?: number; +} + +const iconMap: Record< + PatternHeaderIcon, + React.ComponentType> +> = { + thumb: TumbupIcon, + clock: ClockIcon, + calendar: CalendarIcon, + hourglass: GlassHourIcon, +}; + +const PatternHeader = React.forwardRef( + ({ children, icon, className, iconSize = 20 }, ref) => { + const IconComp = iconMap[icon]; + + return ( +
+ + + + {children} +
+ ); + }, +); +PatternHeader.displayName = 'PatternHeader'; + +const PosePatternPanel = () => { + return ( +
+ 자세 패턴 분석 + +
+
+ TIP +
+
+ 금요일 오후 2시에 자세가 급격히 나빠져요! 이 시간대에 맞춰 스트레칭 + 알림을 설정해드릴까요? +
+
+ +
+
+ + 안좋은 시간 + +
+ 오후 2시 +
+
+ +
+ + 안좋은 요일 + +
수요일
+
+ +
+ + 회복까지 평균 + +
18분
+
+ +
+ + 가장 좋은 시간 + +
+ 오전 10시 +
+
+
+
+ ); +}; + +export default PosePatternPanel; diff --git a/src/renderer/src/pages/Main/components/RunningPanel.tsx b/src/renderer/src/pages/Main/components/RunningPanel.tsx new file mode 100644 index 0000000..836a50f --- /dev/null +++ b/src/renderer/src/pages/Main/components/RunningPanel.tsx @@ -0,0 +1,148 @@ +import AngelRiniVideo from '@assets/video/angel-rini.webm'; +import BackgroundVideo from '@assets/video/background.webm'; +import BugiVideo from '@assets/video/bugi.webm'; +import PmRiniVideo from '@assets/video/pm-rini.webm'; +import RiniVideo from '@assets/video/rini.webm'; +import StoneBugiVideo from '@assets/video/stone-bugi.webm'; +import TireBugiVideo from '@assets/video/tire-bugi.webm'; + +import { useEffect, useMemo } from 'react'; +import { usePostureStore } from '../../../store/usePostureStore'; +import { cn } from '../../../utils/cn'; +import { getScoreLevel } from '../../../utils/getScoreLevel'; + +const RunningPanel = () => { + const score = usePostureStore((state) => state.score); + + // 점수 기반 레벨 계산 + const levelInfo = useMemo(() => getScoreLevel(score), [score]); + + // 레벨에 따른 비디오 선택 + const levelVideo = useMemo(() => { + switch (levelInfo.level) { + case 1: + return AngelRiniVideo; + case 2: + return PmRiniVideo; + case 3: + return RiniVideo; + case 4: + return BugiVideo; + case 5: + return StoneBugiVideo; + case 6: + return TireBugiVideo; + default: + return RiniVideo; + } + }, [levelInfo.level]); + + // 레벨에 따른 게이지바 비율 (레벨이 낮을수록(좋을수록) 더 많이 채워짐) + const gaugeWidth = useMemo(() => { + // 레벨 1(가장 좋음): 100%, 레벨 2: 95%, 레벨 3: 70%, 레벨 4: 45%, 레벨 5: 20%, 레벨 6(가장 나쁨): 5% + const widthMap: Record = { + 1: '100%', + 2: '75%', + 3: '50%', + 4: '50%', + 5: '75%', + 6: '100%', + }; + return widthMap[levelInfo.level] || '70%'; + }, [levelInfo.level]); + + // 레벨에 따른 그라데이션 색상 + const gradient = useMemo(() => { + // 레벨이 낮을수록(좋을수록) 초록색, 높을수록(나쁠수록) 빨간색 + if (levelInfo.level <= 3) { + return 'linear-gradient(90deg, var(--color-olive-green) 0.18%, var(--color-success) 99.7%)'; + } else { + return 'linear-gradient(90deg, var(--color-coral-red) 0%, var(--color-error) 100%)'; + } + }, [levelInfo.level]); + + // 레벨에 따른 상태 텍스트 + const runningStatus = useMemo(() => { + const statusMap: Record = { + 1: '최고 속도로 가는 중!', // 가장 좋음 + 2: '빠르게 가는 중!', + 3: '씽씽 가는 중!', + 4: '천천히 가는 중', + 5: '느릿느릿 가는중..', + 6: '엉금엉금 가는중..', // 가장 나쁨 + }; + return statusMap[levelInfo.level] || '가는 중'; + }, [levelInfo.level]); + + // 위젯 창 상태 확인 + useEffect(() => { + const checkWidgetStatus = async () => { + if (window.electronAPI?.widget) { + const isOpen = await window.electronAPI.widget.isOpen(); + } + }; + + checkWidgetStatus(); + + // 주기적으로 위젯 상태 확인 (위젯이 외부에서 닫힐 수 있음) + const interval = setInterval(checkWidgetStatus, 1000); + return () => clearInterval(interval); + }, []); + + // 위젯 열기/닫기 핸들러 + + return ( +
+
+

{runningStatus}

+
+ +
+ {/* 배경 영상 */} +
+ ); +}; + +export default RunningPanel; diff --git a/src/renderer/src/pages/Main/components/SummaryPanel.tsx b/src/renderer/src/pages/Main/components/SummaryPanel.tsx deleted file mode 100644 index aab23dd..0000000 --- a/src/renderer/src/pages/Main/components/SummaryPanel.tsx +++ /dev/null @@ -1,9 +0,0 @@ -const SummaryPanel = () => { - return ( -
-
-
- ); -}; - -export default SummaryPanel; diff --git a/src/renderer/src/pages/Main/components/TotalDistancePanel.tsx b/src/renderer/src/pages/Main/components/TotalDistancePanel.tsx new file mode 100644 index 0000000..07c9fe1 --- /dev/null +++ b/src/renderer/src/pages/Main/components/TotalDistancePanel.tsx @@ -0,0 +1,50 @@ +import { PannelHeader } from '@ui/PannelHeader/PannelHeader'; +import AchivementMedal from '../../../assets/main/achivement_meadl.svg?react'; +import { useLevelQuery } from '../../../api/dashboard/useLevelQuery'; + +const TotalDistance = () => { + const { data, isLoading } = useLevelQuery(); + + const level = data?.data.level ?? 1; + const current = data?.data.current ?? 0; + const required = data?.data.required ?? 1000; + const progressPercentage = (current / required) * 100; + + return ( +
+ + {isLoading ? '로딩 중...' : `LV.${level + 1} `} + +

+ + {isLoading ? '-' : current.toLocaleString()} + + + / {isLoading ? '-' : required.toLocaleString()}m + +

+ {/*게이지 바*/} +
+
+
+ {/*진행바 */} +
+
+
+ +
+
+ {Array.from({ length: 4 }, (_, i) => i * (required / 3)).map( + (value) => ( + {Math.floor(value).toLocaleString()} + ), + )} +
+
+ ); +}; + +export default TotalDistance; diff --git a/src/renderer/src/pages/Main/components/WebcamPanel.tsx b/src/renderer/src/pages/Main/components/WebcamPanel.tsx index 7703a6b..279bcaf 100644 --- a/src/renderer/src/pages/Main/components/WebcamPanel.tsx +++ b/src/renderer/src/pages/Main/components/WebcamPanel.tsx @@ -1,30 +1,155 @@ +import HideIcon from '@assets/hide.svg?react'; +import ShowIcon from '@assets/show.svg?react'; +import WidgetIcon from '@assets/widget.svg?react'; +import { useCreateSessionMutation } from '../../../api/session/useCreateSessionMutation'; +import { usePauseSessionMutation } from '../../../api/session/usePauseSessionMutation'; +import { useResumeSessionMutation } from '../../../api/session/useResumeSessionMutation'; +import { useStopSessionMutation } from '../../../api/session/useStopSessionMutation'; +import { Button } from '../../../components'; import { PoseLandmark, WorldLandmark, -} from '../../../components/pose-detection/PoseAnalyzer'; +} from '../../../components/pose-detection'; +import { useWidget } from '../../../hooks/useWidget'; +import { useCameraStore } from '../../../store/useCameraStore'; import WebcamView from '../../Calibration/components/WebcamView'; interface Props { - isWebcamOn: boolean; onUserMediaError: (e: string | DOMException) => void; onPoseDetected: ( landmarks: PoseLandmark[], worldLandmarks?: WorldLandmark[], ) => void; + onToggleWebcam: () => void; + onSendMetrics: () => void; } const WebcamPanel = ({ - isWebcamOn, - onUserMediaError, onPoseDetected, + onToggleWebcam, + onSendMetrics, }: Props) => { + const { cameraState, setShow, setHide, setExit } = useCameraStore(); + const { toggleWidget } = useWidget(); + const isWebcamOn = cameraState === 'show'; + const isExit = cameraState === 'exit'; + + const { mutate: createSession, isPending: isCreatingSession } = + useCreateSessionMutation(); + const { mutate: stopSession, isPending: isStoppingSession } = + useStopSessionMutation(); + const { mutate: pauseSession, isPending: isPausingSession } = + usePauseSessionMutation(); + const { mutate: resumeSession, isPending: isResumingSession } = + useResumeSessionMutation(); + const handleStartStop = () => { + if (isExit) { + // 시작하기: 세션 생성 후 카메라 시작 + createSession(undefined, { + onSuccess: () => { + setShow(); + }, + }); + } else { + // 종료하기: 메트릭 전송 → 세션 중단 → 카메라 종료 + const sessionId = localStorage.getItem('sessionId'); + if (sessionId) { + // 1. 수집된 메트릭을 서버로 전송 + onSendMetrics(); + + // 2. 세션 종료 + stopSession(sessionId, { + onSuccess: () => { + setExit(); + }, + }); + } else { + // sessionId가 없으면 그냥 카메라만 종료 + setExit(); + } + } + }; + + // 카메라 보이기/숨기기 버튼: 일시정지/재개 + const handleToggleCamera = () => { + const sessionId = localStorage.getItem('sessionId'); + + if (isWebcamOn) { + // 카메라 보이는 상태 → 숨기기: 세션 일시정지 + if (sessionId) { + pauseSession(sessionId, { + onSuccess: () => { + setHide(); + onToggleWebcam(); + }, + }); + } else { + setHide(); + onToggleWebcam(); + } + } else { + // 카메라 숨김 상태 → 보이기: 세션 재개 + if (sessionId) { + resumeSession(sessionId, { + onSuccess: () => { + setShow(); + onToggleWebcam(); + }, + }); + } else { + setShow(); + onToggleWebcam(); + } + } + }; + return ( -
-
- +
+ +
+
+
+ } />
diff --git a/src/renderer/src/pages/Onboarding/OnboardingCompletionPage.tsx b/src/renderer/src/pages/Onboarding/OnboardingCompletionPage.tsx index 59f56d4..89f7cf3 100644 --- a/src/renderer/src/pages/Onboarding/OnboardingCompletionPage.tsx +++ b/src/renderer/src/pages/Onboarding/OnboardingCompletionPage.tsx @@ -1,15 +1,15 @@ -import CompletionCharacter from '../../assets/completion.svg?react'; import { useNavigate } from 'react-router-dom'; +import CompletionCharacter from '../../assets/completion.svg?react'; import { Button } from '../../components/Button/Button'; const OnboardingCompletionPage = () => { const navigate = useNavigate(); return ( -
+
{/* 캐릭터 영역 */} - + {/* 색종이 효과 */} {/* 텍스트 영역 */} diff --git a/src/renderer/src/pages/Onboarding/OnboardingInitPage.tsx b/src/renderer/src/pages/Onboarding/OnboardingInitPage.tsx new file mode 100644 index 0000000..5eaeb83 --- /dev/null +++ b/src/renderer/src/pages/Onboarding/OnboardingInitPage.tsx @@ -0,0 +1,48 @@ +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import ImageDescriptionPannel from './components/ImageDescriptionPanel'; +import InfoPanel from './components/InfoPanel'; + +const OnboardinInitPage = () => { + const navigate = useNavigate(); + const [currentStep, setCurrentStep] = useState(1); + const [direction, setDirection] = useState<'next' | 'prev'>('next'); + + const handlePrev = () => { + if (currentStep > 1) { + setDirection('prev'); + setCurrentStep(currentStep - 1); + } + }; + + const handleNext = () => { + if (currentStep < 5) { + setDirection('next'); + setCurrentStep(currentStep + 1); + } else { + // 5단계에서 시작하기 클릭 시 카메라 권한 요청 페이지로 이동 + navigate('/onboarding'); + } + }; + + return ( +
+
+
+ + +
+
+
+ ); +}; + +export default OnboardinInitPage; diff --git a/src/renderer/src/pages/Onboarding/OnboardingPage.tsx b/src/renderer/src/pages/Onboarding/OnboardingPage.tsx index cf0ac19..99f1a1a 100644 --- a/src/renderer/src/pages/Onboarding/OnboardingPage.tsx +++ b/src/renderer/src/pages/Onboarding/OnboardingPage.tsx @@ -3,9 +3,9 @@ import CameraPermissionButton from './components/CameraPermissionButton'; const OnboardingPage = () => { return ( -
+
-
+
카메라 사용 권한 diff --git a/src/renderer/src/pages/Onboarding/components/CameraPermissionButton.tsx b/src/renderer/src/pages/Onboarding/components/CameraPermissionButton.tsx index bca725e..4bafa19 100644 --- a/src/renderer/src/pages/Onboarding/components/CameraPermissionButton.tsx +++ b/src/renderer/src/pages/Onboarding/components/CameraPermissionButton.tsx @@ -1,31 +1,65 @@ import { useNavigate } from 'react-router-dom'; import { Button } from '../../../components/Button/Button'; +import { useCameraStore } from '../../../store/useCameraStore'; const CameraPermissionButton = () => { const navigate = useNavigate(); + const { setShow } = useCameraStore(); const requestCameraPermission = async () => { try { - // 카메라 권한 요청 - console.log('[CameraPermission] Requesting camera access...'); - const stream = await navigator.mediaDevices.getUserMedia({ - video: true, - audio: false, - }); + const isWindows = navigator.platform.includes('Win'); + + let stream: MediaStream | null = null; + let selectedDeviceId: string | null = null; + + // Windows 환경이면 Device 1 (두 번째 카메라) 사용 + if (isWindows) { + const devices = await navigator.mediaDevices.enumerateDevices(); // 연결된 모든 미디어 장치 탐색 + const videoDevices = devices.filter((d) => d.kind === 'videoinput'); // 카메라 목록만 구함 + + const targetDevice = videoDevices[1]; // 카메라 목록중 두 번째 카메라 선택 + if (targetDevice) { + stream = await navigator.mediaDevices.getUserMedia({ + video: { deviceId: { exact: targetDevice.deviceId } }, //지정한 카메라에 스트림 요청 + audio: false, + }); + selectedDeviceId = targetDevice.deviceId; //사용하는 카메라id 저장 변수 + } else { + stream = await navigator.mediaDevices.getUserMedia({ + video: true, + audio: false, + }); // 카메라 1대이면 기존 방식 사용 + } + } else { + // macOS 등 다른 환경: 기존 로직 + + stream = await navigator.mediaDevices.getUserMedia({ + video: true, + audio: false, + }); + const track = stream.getVideoTracks()[0]; + selectedDeviceId = track.getSettings().deviceId || null; + } + + if (!stream) { + throw new Error('사용 가능한 카메라를 찾을 수 없습니다.'); + } - console.log( - '[CameraPermission] Camera access granted, stopping tracks...', - ); - // 권한이 허용되면 스트림을 중지 stream.getTracks().forEach((track) => { track.stop(); - console.log('[CameraPermission] Track stopped:', track.id); }); // 스트림이 완전히 해제될 때까지 약간의 딜레이 await new Promise((resolve) => setTimeout(resolve, 100)); - console.log('[CameraPermission] Navigating to calibration page...'); + // 성공한 카메라 저장 + if (selectedDeviceId) { + localStorage.setItem('preferred-camera-device', selectedDeviceId); + } + + setShow(); // Set camera state to 'show' after permission is granted + navigate('/onboarding/calibration'); } catch (error) { console.error('[CameraPermission] 카메라 권한 요청 실패:', error); diff --git a/src/renderer/src/pages/Onboarding/components/FirstImageDescription.tsx b/src/renderer/src/pages/Onboarding/components/FirstImageDescription.tsx new file mode 100644 index 0000000..61e9cd2 --- /dev/null +++ b/src/renderer/src/pages/Onboarding/components/FirstImageDescription.tsx @@ -0,0 +1,20 @@ +import GiraffeIcon from '../../../assets/onboarding/giraffe.svg?react'; +import TurtleIcon from '../../../assets/onboarding/turtle.svg?react'; + +const FirstImageDescription = () => { + const userName = localStorage.getItem('userName') || '사용자'; + + return ( +
+

+ 안녕하세요! {userName}님의 자세 건강을 책임질 AI 파트너, 거부기린이에요. +

+
+ + +
+
+ ); +}; + +export default FirstImageDescription; diff --git a/src/renderer/src/pages/Onboarding/components/ImageDescriptionPanel.tsx b/src/renderer/src/pages/Onboarding/components/ImageDescriptionPanel.tsx new file mode 100644 index 0000000..eebfe99 --- /dev/null +++ b/src/renderer/src/pages/Onboarding/components/ImageDescriptionPanel.tsx @@ -0,0 +1,118 @@ +import FirstImageDescription from './FirstImageDescription'; +import PrevIcon from '@assets/onboarding/prev_icon.svg?react'; +import firstImage from '@assets/onboarding/first_image.png'; +import secondImage from '@assets/onboarding/second_image.png'; +import thirdImage from '@assets/onboarding/third_image.png'; +import fourthImage from '@assets/onboarding/fourth_image.png'; +import firstDarkImage from '@assets/onboarding/first_dark_image.png'; +import secondDarkImage from '@assets/onboarding/second_dark_image.png'; +import thirdDarkImage from '@assets/onboarding/third_dark_image.png'; +import fourthDarkImage from '@assets/onboarding/fourth_dark_image.png'; +import RockIcon from '@assets/onboarding/rock_icon.svg?react'; +import { useState, useEffect } from 'react'; + +/* 단계별 이미지 (1단계는 null, 2~5단계는 이미지) */ +const STEP_IMAGES_LIGHT = [ + null, + firstImage, + secondImage, + thirdImage, + fourthImage, +]; +const STEP_IMAGES_DARK = [ + null, + firstDarkImage, + secondDarkImage, + thirdDarkImage, + fourthDarkImage, +]; + +interface ImageDescriptionPannelProps { + currentStep: number; + onPrev: () => void; + direction: 'next' | 'prev'; +} + +const ImageDescriptionPannel = ({ + currentStep, + onPrev, + direction, +}: ImageDescriptionPannelProps) => { + const [isDark, setIsDark] = useState(() => + document.documentElement.classList.contains('dark'), + ); + + useEffect(() => { + const observer = new MutationObserver(() => { + setIsDark(document.documentElement.classList.contains('dark')); + }); + + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + + return () => observer.disconnect(); + }, []); + + /* 이미지 프리로드 */ + useEffect(() => { + const allImages = [...STEP_IMAGES_LIGHT, ...STEP_IMAGES_DARK].filter( + (src): src is string => src !== null, + ); + + allImages.forEach((src) => { + const img = new Image(); + img.src = src; + }); + }, []); + + const stepImages = isDark ? STEP_IMAGES_DARK : STEP_IMAGES_LIGHT; + const stepImage = stepImages[currentStep - 1]; + + return ( +
+
+ {/* 2단계부터 이전 버튼 표시 */} + {currentStep > 1 && ( +
+ +
+ )} + +
+ {currentStep === 1 ? ( + + ) : ( + stepImage && ( + {`step + ) + )} +
+ +

+ + + 영상은 사용자의 PC에서만 처리되며, 어디에도 저장되거나 전송되지 + 않으니 안심하세요. + +

+
+
+ ); +}; + +export default ImageDescriptionPannel; diff --git a/src/renderer/src/pages/Onboarding/components/InfoPanel.tsx b/src/renderer/src/pages/Onboarding/components/InfoPanel.tsx new file mode 100644 index 0000000..663d1a7 --- /dev/null +++ b/src/renderer/src/pages/Onboarding/components/InfoPanel.tsx @@ -0,0 +1,113 @@ +import { Button } from '@ui/index'; +import FirstIcon from '@assets/onboarding/first_progress_icon.svg?react'; +import SecondIcon from '@assets/onboarding/second_progress_icon.svg?react'; +import ThirdIcon from '@assets/onboarding/third_progress_icon.svg?react'; +import FourthIcon from '@assets/onboarding/fourth_progress_icon.svg?react'; +import FifthIcon from '@assets/onboarding/fifth_progress_icon.svg?react'; + +// 단계별 아이콘 +const STEP_ICONS = [FirstIcon, SecondIcon, ThirdIcon, FourthIcon, FifthIcon]; + +// 단계별 데이터 +const STEP_DATA = [ + { + title: '바른 자세 분석', + description: + '이제부터 Username님이 일하는 동안 웹캠을 통해 실시간으로 자세를 분석해 드릴게요.', + }, + { + title: '실시간 위젯 피드백', + description: + '화면 상단 작은 위젯의 기린과 거북이가 실시간 자세 피드백을 제공해요.', + }, + { + title: '데이터로 보는 대시보드', + description: [ + '주간, 월간 단위의 개인화 통계와 패턴 분석을 통해 나도 몰랐던 나의 자세 습관을 발견할 수 있어요.', + 'AI가 제안하는 맞춤형 팁을 통해 자발적이고 지속적인 변화를 느껴보세요.', + ], + }, + { + title: '스마트 알림', + description: + '자세가 심하게 나빠지거나 스트레칭이 필요한 순간을 AI가 정확하게 포착하여 똑똑하게 알려드려요.', + }, + { + title: '즐거운 게임을 통한 자세 교정', + description: [ + '건강 관리는 지루하다는 편견을 깨기 위해 게이미페케이션 요소를 넣었어요.', + '바른 자세를 유지할수록 나의 캐릭터가 레벨업하고 더 빨리 달려 보상을 받을 수 있어요.', + ], + }, +]; + +interface InfoPanelProps { + currentStep: number; + onNext: () => void; + direction: 'next' | 'prev'; +} + +const InfoPanel = ({ currentStep, onNext, direction }: InfoPanelProps) => { + const stepData = STEP_DATA[currentStep - 1]; + const StepIcon = STEP_ICONS[currentStep - 1]; + + return ( +
+
+ {/* 현재 단계 프로그레스바 */} +
+
+ {Array.from({ length: 5 }).map((_, index) => ( + + ))} +
+
+ + {/*설명 부분 */} +
+ {/* Keypoint */} +

+ Keypoint {currentStep} +

+ +
+

+ {/* 서비스 설명 */} +

+ + {stepData.title} + + {Array.isArray(stepData.description) ? ( + + {stepData.description.map((desc, index) => ( + {desc} + ))} + + ) : ( + + {stepData.description} + + )} +

+
+
+ + {/* 버튼 부분 */} +
+ ); +}; + +export default InfoPanel; diff --git a/src/renderer/src/pages/SignUp/EmailVerificationCallbackPage.tsx b/src/renderer/src/pages/SignUp/EmailVerificationCallbackPage.tsx new file mode 100644 index 0000000..c6facbb --- /dev/null +++ b/src/renderer/src/pages/SignUp/EmailVerificationCallbackPage.tsx @@ -0,0 +1,40 @@ +import { useEffect } from 'react'; +import { useSearchParams } from 'react-router-dom'; +import { useVerifyEmailMutation } from '../../api/signup/verifyEmail'; +import CompletionCharacter from '../../assets/completion.svg?react'; + +const EmailVerificationCallbackPage = () => { + const [searchParams] = useSearchParams() + + const verifyEmailMutation = useVerifyEmailMutation(); + useEffect(() => { + const token = searchParams.get('token'); + if (token) { + verifyEmailMutation.mutate(token); + } + }, [searchParams]); + + return ( +
+
+
+
+
+

환영합니다

+

+ 이메일 인증이 완료되었습니다. +
+ 거부기린 앱으로 돌아가서 +
+ 로그인하여 서비스를 이용해주세요. +

+
+
+
+
+
+ ); +}; + +export default EmailVerificationCallbackPage; + diff --git a/src/renderer/src/pages/SignUp/EmailVerificationPage.tsx b/src/renderer/src/pages/SignUp/EmailVerificationPage.tsx index 6625316..afabce2 100644 --- a/src/renderer/src/pages/SignUp/EmailVerificationPage.tsx +++ b/src/renderer/src/pages/SignUp/EmailVerificationPage.tsx @@ -1,28 +1,20 @@ -import { Button } from '../../components/Button/Button'; -import EmailHeroSection from './components/EmailHeroSection'; -import ResendSection from './components/ResendSection'; -import { useNavigate, useSearchParams } from 'react-router-dom'; -import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; import { - useResendVerifyEmailMuation, - useVerifyEmailMutation, + useResendVerifyEmailMuation } from '../../api/signup/verifyEmail'; +import { Button } from '../../components/Button/Button'; import { useEmailStore } from '../../store/useSignUpStore'; +import EmailHeroSection from './components/EmailHeroSection'; +import ResendSection from './components/ResendSection'; const EmailVerificationPage = () => { - const [searchParams] = useSearchParams(); - const verifyEmailMutation = useVerifyEmailMutation(); + const resendverifyEmailMutation = useResendVerifyEmailMuation(); const email = useEmailStore((state) => state.email); const navigate = useNavigate(); /* 토큰 여부에 따른 이메일 인증 */ - useEffect(() => { - const token = searchParams.get('token'); - if (token) { - verifyEmailMutation.mutate(token); - } - }, [searchParams]); + /*이메일 다시 보내기 */ const onResendClick = () => { diff --git a/src/renderer/src/pages/SignUp/components/EmailHeroSection.tsx b/src/renderer/src/pages/SignUp/components/EmailHeroSection.tsx index 24a3973..9499ea2 100644 --- a/src/renderer/src/pages/SignUp/components/EmailHeroSection.tsx +++ b/src/renderer/src/pages/SignUp/components/EmailHeroSection.tsx @@ -8,8 +8,8 @@ export default function EmailHeroSection() {
-

이메일 인증

-

+

이메일 인증

+

본인 인증 메일을 귀하의 {' ' + email} diff --git a/src/renderer/src/pages/SignUp/components/ResendEmailHeroSection.tsx b/src/renderer/src/pages/SignUp/components/ResendEmailHeroSection.tsx index 6c52b1c..9b3ab51 100644 --- a/src/renderer/src/pages/SignUp/components/ResendEmailHeroSection.tsx +++ b/src/renderer/src/pages/SignUp/components/ResendEmailHeroSection.tsx @@ -1,8 +1,10 @@ export default function ResendEmailHerosection() { return (

-

인증 링크를 메일로 전송했습니다

-

+

+ 인증 링크를 메일로 전송했습니다 +

+

이메일로 전송 받은 인증 링크를 확인해주세요.
링크는 발송 시점으로부터 24시간 동안 유효합니다. diff --git a/src/renderer/src/pages/SignUp/components/SignUpform.tsx b/src/renderer/src/pages/SignUp/components/SignUpform.tsx index 2393d06..20b979e 100644 --- a/src/renderer/src/pages/SignUp/components/SignUpform.tsx +++ b/src/renderer/src/pages/SignUp/components/SignUpform.tsx @@ -94,7 +94,7 @@ const SignUpForm = () => { htmlFor="email" className="text-body-lg-semibold hbp:text-headline-2xl-semibold text-grey-600" > - 이메일 * + 이메일 *

{ })} className={`hbp:text-body-xl-regular aspect-[338/60] flex-1 ${ errors.email - ? '!border-red-500' + ? '!border-error' : duplicateSuccess === true - ? '!border-green-500' + ? '!border-success' : duplicateSuccess === false - ? '!border-red-500' + ? '!border-error' : '' }`} /> @@ -130,10 +130,10 @@ const SignUpForm = () => {
{(errors.email || duplicateMessage) && (
{errors.email || duplicateSuccess === false ? ( @@ -154,7 +154,7 @@ const SignUpForm = () => { htmlFor="password" className="text-body-lg-semibold hbp:text-headline-2xl-semibold text-grey-600" > - 비밀번호 * + 비밀번호 *

영문, 숫자, 특수문자를 조합하여 8-16글자로 입력해주세요. @@ -162,6 +162,7 @@ const SignUpForm = () => { {/* 비밀번호 재입력 섹션 */} @@ -174,8 +175,8 @@ const SignUpForm = () => { ? '' // 아무 입력 없으면 기본 : formValues.password === formValues.confirmPassword && !errors.password - ? '!border-green-500' // 입력 있음 + 비밀번호 조건 통과 + 일치시 초록색 - : '!border-red-500' // 그 외는 모두 빨간색 + ? '!border-success' // 입력 있음 + 비밀번호 조건 통과 + 일치시 초록색 + : '!border-error' // 그 외는 모두 빨간색 } /> @@ -188,14 +189,14 @@ const SignUpForm = () => { formValues.password !== formValues.confirmPassword || !!errors.password; - const colorClass = isError ? 'text-red-500' : 'text-green-500'; + const colorClass = isError ? 'text-error' : 'text-success'; const Icon = isError ? FailIcon : SuccessIcon; const message = isError ? errors.password?.message || '비밀번호가 일치하지 않습니다.' : '비밀번호가 일치합니다.'; return ( -

+

{message}

@@ -210,7 +211,7 @@ const SignUpForm = () => { htmlFor="name" className="text-body-lg-semibold hbp:text-headline-2xl-semibold text-grey-600" > - 이름 * + 이름 *

최대 10글자 이내로 작성해주세요. @@ -220,13 +221,13 @@ const SignUpForm = () => { type="text" placeholder="이름을 입력해주세요." {...register('name')} - className={`hbp:text-body-xl-regular ${errors.name ? '!border-red-500' : formValues.name ? '!border-green-500' : ''}`} + className={`hbp:text-body-xl-regular ${errors.name ? '!border-error' : formValues.name ? '!border-success' : ''}`} /> {(formValues.name || !!errors.name) && (

{errors.name ? : } diff --git a/src/renderer/src/pages/Widget/WidgetPage.tsx b/src/renderer/src/pages/Widget/WidgetPage.tsx new file mode 100644 index 0000000..fcfd664 --- /dev/null +++ b/src/renderer/src/pages/Widget/WidgetPage.tsx @@ -0,0 +1,92 @@ +/* 위젯 창에 표시될 페이지 - 반응형 */ + +import { useEffect, useState } from 'react'; +import { WidgetTitleBar } from '../../components/WidgetTitleBar/WidgetTitleBar'; +import { usePostureStore } from '../../store/usePostureStore'; +import { MediumWidgetContent } from './components/MediumWidgetContent'; +import { MiniWidgetContent } from './components/MiniWidgetContent'; +import { usePostureSyncWithLocalStorage } from './hooks/usePostureSyncWithLocalStorage'; +import { useThemeSync } from './hooks/useThemeSync'; + +type WidgetSize = 'mini' | 'medium'; +type PostureState = 'turtle' | 'giraffe'; + +/* 레이아웃 전환 기준점 */ +const BREAKPOINT = { + height: 62, +} as const; + +export function WidgetPage() { + const [widgetSize, setWidgetSize] = useState('medium'); + const currentPostureClass = usePostureStore((state) => state.postureClass); + + /* usePostureStore에서 실시간 자세 상태 가져오기 */ + + /* 실시간 자세 상태 동기화 */ + usePostureSyncWithLocalStorage(); + + /* 위젯 라이트/다크 모드 */ + useThemeSync(); + + /* 위젯 페이지 로드 시 로그 */ + useEffect(() => { + console.log('위젯 페이지가 로드되었습니다'); + + if (window.electronAPI?.writeLog) { + const logData = JSON.stringify({ + event: 'widget_page_loaded', + timestamp: new Date().toISOString(), + }); + window.electronAPI.writeLog(logData).catch((error: unknown) => { + console.error('위젯 페이지 로드 로그 저장 실패:', error); + }); + } + }, []); + + /* 위젯 resize 이벤트 */ + useEffect(() => { + /* resize 디바운스 타이머 ID 저장용 변수 */ + let resizeTimeout: number; + + /* 창 크기 변경 감지 핸들러 */ + const handleResize = () => { + const isMedium = innerHeight > BREAKPOINT.height; + /* breakpoint를 넘으면 medium, 아니면 mini */ + setWidgetSize(isMedium ? 'medium' : 'mini'); + }; + + /* 디바운스 래퍼 함수 */ + const handleResizeDebounced = () => { + clearTimeout(resizeTimeout); + resizeTimeout = window.setTimeout(() => { + handleResize(); + }, 10); + }; + + handleResize(); + window.addEventListener('resize', handleResizeDebounced); + + return () => { + window.removeEventListener('resize', handleResizeDebounced); + clearTimeout(resizeTimeout); + }; + }, []); + + const isMini = widgetSize === 'mini'; + + return ( +
+
+ {/* 커스텀 타이틀바 */} + + + {/* 위젯 내용 - 창 크기에 따라 자동 전환 */} + {isMini ? ( + + ) : ( + + )} +
+
+ ); +} diff --git a/src/renderer/src/pages/Widget/components/MediumWidgetContent.tsx b/src/renderer/src/pages/Widget/components/MediumWidgetContent.tsx new file mode 100644 index 0000000..c5e9957 --- /dev/null +++ b/src/renderer/src/pages/Widget/components/MediumWidgetContent.tsx @@ -0,0 +1,102 @@ +import { useEffect, useState } from 'react'; +import MediumGiraffe from '../../../assets/widget/medium_giraffe.svg?react'; +import MediumTurtle from '../../../assets/widget/medium_turtle.svg?react'; +import messages from '../data.json'; + +/* 실시간 자세 판별 */ +type PostureState = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +interface Message { + level: number; + mainTitle: string; + subTitles: string[]; +} + +interface MediumWidgetContentProps { + posture: PostureState; +} + +/* 미디엄 위젯 레이아웃 */ +export function MediumWidgetContent({ posture }: MediumWidgetContentProps) { + const [mainTitle, setMainTitle] = useState('자세를 측정하고 있어요'); + const [subTitle, setSubTitle] = useState('잠시만 기다려주세요...'); + + /* eslint-disable react-hooks/set-state-in-effect */ + useEffect(() => { + const messageData = messages.find((m: Message) => m.level === posture); + + if (messageData) { + setMainTitle(messageData.mainTitle); + const { subTitles } = messageData; + const randomIndex = Math.floor(Math.random() * subTitles.length); + setSubTitle(subTitles[randomIndex]); + } else { + // posture가 0이거나 유효하지 않은 경우 기본 메시지 설정 + setMainTitle('자세를 측정하고 있어요'); + setSubTitle('잠시만 기다려주세요...'); + } + }, [posture]); + /* eslint-enable react-hooks/set-state-in-effect */ + + const isGiraffe = [1, 2, 3].includes(posture); + const gradient = isGiraffe + ? 'linear-gradient(180deg, var(--color-olive-green) 0.18%, var(--color-success) 99.7%)' + : 'linear-gradient(180deg, var(--color-coral-red) 0%, var(--color-error) 100%)'; + + /* 게이지 비율: 등급별 차등 적용 */ + let gaugeWidth: string; + switch (posture) { + case 1: + case 6: + gaugeWidth = '100%'; + break; + case 2: + case 5: + gaugeWidth = '75%'; + break; + case 3: + case 4: + gaugeWidth = '50%'; + break; + default: // posture 0 + gaugeWidth = '25%'; + break; + } + + return ( +
+ {/* 캐릭터 영역 */} +
+ {isGiraffe ? ( + + ) : ( + + )} +
+ + {/* 상세 정보 영역 */} +
+ {/* 진행 바 */} +
+
+
+
+
+
+
+ + {/* 메시지 */} +
+
{mainTitle}
+
{subTitle}
+
+
+
+ ); +} diff --git a/src/renderer/src/pages/Widget/components/MiniWidgetContent.tsx b/src/renderer/src/pages/Widget/components/MiniWidgetContent.tsx new file mode 100644 index 0000000..77cf641 --- /dev/null +++ b/src/renderer/src/pages/Widget/components/MiniWidgetContent.tsx @@ -0,0 +1,54 @@ +import MiniGiraffe from '../../../assets/widget/mini_giraffe.svg?react'; +import MiniTurtle from '../../../assets/widget/mini_turtle.svg?react'; + +/* 실시간 자세 판별 */ +type PostureState = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +interface MiniWidgetContentProps { + posture: PostureState; +} + +/* 미니 위젯 레이아웃 - 최대 50px 높이에 맞게 가로 배치 */ +export function MiniWidgetContent({ posture }: MiniWidgetContentProps) { + const isGiraffe = [1, 2, 3].includes(posture); + const gradient = isGiraffe + ? 'linear-gradient(180deg, var(--color-olive-green) 0.18%, var(--color-success) 99.7%)' + : 'linear-gradient(180deg, var(--color-coral-red) 0%, var(--color-error) 100%)'; + + /* 게이지 비율: 등급별 차등 적용 */ + let gaugeWidth: string; + switch (posture) { + case 1: + case 6: + gaugeWidth = '100%'; + break; + case 2: + case 5: + gaugeWidth = '75%'; + break; + case 3: + case 4: + gaugeWidth = '50%'; + break; + default: // posture 0 + gaugeWidth = '25%'; + break; + } + + return ( +
+ {/* 캐릭터 이미지 영역 - 작게 */} +
+
+ {isGiraffe ? ( + + ) : ( + + )} +
+
+ ); +} diff --git a/src/renderer/src/pages/Widget/data.json b/src/renderer/src/pages/Widget/data.json new file mode 100644 index 0000000..c27f307 --- /dev/null +++ b/src/renderer/src/pages/Widget/data.json @@ -0,0 +1,63 @@ +[ + { + "level": 6, + "mainTitle": "앗! 지금은 거북이 상태예요", + "subTitles": [ + "초등학교 3학년 아이를 얹고 있어요", + "시멘트 한 포대를 얹고 있어요", + "대형견 셰퍼드를 얹고 있어요", + "미래 병원비 3,000만원을 적립 중입니다", + "생산성 최악! 지금 당장 일어나세요!" + ] + }, + { + "level": 5, + "mainTitle": "앗! 지금은 거북이 상태예요", + "subTitles": [ + "골든 리트리버 한 마리를 얹고 있어요", + "42인치 TV를 얹고 있어요", + "자동차 타이어 1개를 얹고 있어요", + "목 디스크가 다가오고있어요", + "지금 느끼는 어깨 통증, 자세 때문이에요" + ] + }, + { + "level": 4, + "mainTitle": "앗! 지금은 거북이 상태예요", + "subTitles": [ + "7살 아이 한 명을 얹고 있어요", + "2L 생수병 9개 묶음을 얹고 있어요", + "비행기 기내용 캐리어를 얹고 있어요", + "본격적인 거북목 증후군 시작!", + "뇌로 가는 산소가 부족해지고 있어요" + ] + }, + { + "level": 3, + "mainTitle": "좋아요, 기린 상태 유지중!", + "subTitles": [ + "아직은 목 근육 긴장 가능성이 있어요", + "턱을 살짝만 더 당겨볼까요?", + "이 정도면 잘하고 있어요!" + ] + }, + { + "level": 2, + "mainTitle": "좋아요, 기린 상태 유지중!", + "subTitles": [ + "집중력 최고 상태예요", + "목과 어깨가 편안한 상태예요", + "생산성이 상승하고있어요" + ] + }, + { + "level": 1, + "mainTitle": "좋아요, 기린 상태 유지중!", + "subTitles": [ + "완벽해요! 최고의 퍼포먼스를 내고있어요", + "최고의 자세! 이 상태를 유지하세요", + "척추가 교과서처럼 정렬되었어요", + "이 자세, 몸이 기억하게 해주세요" + ] + } +] diff --git a/src/renderer/src/pages/Widget/hooks/usePostureSyncWithLocalStorage.ts b/src/renderer/src/pages/Widget/hooks/usePostureSyncWithLocalStorage.ts new file mode 100644 index 0000000..a8609a5 --- /dev/null +++ b/src/renderer/src/pages/Widget/hooks/usePostureSyncWithLocalStorage.ts @@ -0,0 +1,43 @@ +import { useEffect } from 'react'; +import { usePostureStore } from '../../../store/usePostureStore'; + +/* 메인 창의 실시간 자세 상태 위젯 창에 실시간 동기화 + localStorage의 storage 이벤트를 통해 창 간 통신 */ + +export function usePostureSyncWithLocalStorage() { + const postureClass = usePostureStore((state) => state.postureClass); + const setStatus = usePostureStore((state) => state.setStatus); + + useEffect(() => { + const handleStorageChange = (e: StorageEvent) => { + /* posture-state-storage만 처리 (다른 localStorage 변경은 무시) */ + if (e.key !== 'posture-state-storage' || !e.newValue) return; + + try { + const storageData = JSON.parse(e.newValue); + const { postureClass: newPostureClass, score: newScore } = + storageData.state; + + console.log('[위젯] 메인 창에서 자세 변경 감지:', { + from: { postureClass }, + to: { postureClass: newPostureClass, score: newScore }, + }); + + setStatus(newPostureClass, newScore); + } catch (error) { + console.error('[위젯] localStorage 파싱 오류:', error); + } + }; + + window.addEventListener('storage', handleStorageChange); + return () => window.removeEventListener('storage', handleStorageChange); + }, [postureClass, setStatus]); + + /* 디버깅용 로그 */ + useEffect(() => { + console.log('[위젯] 자세 상태 업데이트:', { + postureClass, + timestamp: new Date().toLocaleTimeString(), + }); + }, [postureClass]); +} diff --git a/src/renderer/src/pages/Widget/hooks/useThemeSync.ts b/src/renderer/src/pages/Widget/hooks/useThemeSync.ts new file mode 100644 index 0000000..6043db7 --- /dev/null +++ b/src/renderer/src/pages/Widget/hooks/useThemeSync.ts @@ -0,0 +1,28 @@ +import { useEffect } from 'react'; + +/* 메인 창의 테마 위젯 창에 동시에 반영 */ +export function useThemeSync() { + useEffect(() => { + const applyTheme = () => { + const isDark = localStorage.getItem('theme') === 'dark'; + if (isDark) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }; + + // 초기 테마 적용 + applyTheme(); + + /*메인 창에서 테마 변경 시 자동 반영 */ + const handleStorageChange = (e: StorageEvent) => { + if (e.key === 'theme') { + applyTheme(); + } + }; + + window.addEventListener('storage', handleStorageChange); + return () => window.removeEventListener('storage', handleStorageChange); + }, []); +} diff --git a/src/renderer/src/routers/index.tsx b/src/renderer/src/routers/index.tsx index 51a726b..7a47ac8 100644 --- a/src/renderer/src/routers/index.tsx +++ b/src/renderer/src/routers/index.tsx @@ -1,4 +1,5 @@ -import { createBrowserRouter } from 'react-router-dom'; +import { createBrowserRouter, redirect } from 'react-router-dom'; +import api from '../api/api'; import Layout from '../layout/Layout'; import CalibrationPage from '../pages/Calibration/CalibrationPage'; import LoginPage from '../pages/Login/LoginPage'; @@ -6,30 +7,76 @@ import MainPage from '../pages/Main/MainPage'; import OnboardingCompletionPage from '../pages/Onboarding/OnboardingCompletionPage'; import OnboardingPage from '../pages/Onboarding/OnboardingPage'; import EmailVerificationPage from '../pages/SignUp/EmailVerificationPage'; +import EmailVerificationCallbackPage from '../pages/SignUp/EmailVerificationCallbackPage'; import ResendVerificationPage from '../pages/SignUp/ResendVerificationPage'; import SignUpPage from '../pages/SignUp/SignUpPage'; +import { WidgetPage } from '../pages/Widget/WidgetPage'; +import OnboardinInitPage from '../pages/Onboarding/OnboardingInitPage'; + +// 인증이 필요한 페이지용 loader +const requireAuthLoader = async () => { + const accessToken = localStorage.getItem('accessToken'); + if (!accessToken) { + return redirect('/'); + } + + try { + await api.get('/users/me'); + return null; + } catch (error) { + localStorage.clear(); + return redirect('/'); + } +}; + +// 로그인 페이지용 loader (토큰이 있으면 메인으로 리다이렉트) +const loginPageLoader = async () => { + const accessToken = localStorage.getItem('accessToken'); + if (!accessToken) { + return null; + } + + try { + await api.get('/users/me'); + return redirect('/main'); + } catch (error) { + localStorage.clear(); + return null; + } +}; export const router = createBrowserRouter([ { - element: , - path: '/', - children: [{ path: '', element: }], - }, - { - element: , path: '/main', - children: [{ path: '', element: }], + loader: requireAuthLoader, + element: , }, { element: , path: '/auth', children: [ - { path: 'login', element: }, + { + path: 'login', + loader: loginPageLoader, + element: , + }, { path: 'signup', element: }, { path: 'verify', element: }, + { path: 'verify-callback', element: }, { path: 'resend', element: }, ], }, + { + element: , + path: '/', + children: [ + { + path: '', + loader: loginPageLoader, + element: , + }, + ], + }, { element: , path: '/onboarding', @@ -37,6 +84,11 @@ export const router = createBrowserRouter([ { path: '', element: }, { path: 'calibration', element: }, { path: 'completion', element: }, + { path: 'init', element: }, ], }, + { + path: '/widget', + children: [{ path: '', element: }], + }, ]); diff --git a/src/renderer/src/store/useCameraStore.ts b/src/renderer/src/store/useCameraStore.ts new file mode 100644 index 0000000..d287f2e --- /dev/null +++ b/src/renderer/src/store/useCameraStore.ts @@ -0,0 +1,26 @@ +import { create } from 'zustand'; +import { persist, createJSONStorage } from 'zustand/middleware'; + +type CameraState = 'show' | 'hide' | 'exit'; + +interface CameraStore { + cameraState: CameraState; + setShow: () => void; + setHide: () => void; + setExit: () => void; +} + +export const useCameraStore = create()( + persist( + (set) => ({ + cameraState: 'hide', + setShow: () => set({ cameraState: 'show' }), + setHide: () => set({ cameraState: 'hide' }), + setExit: () => set({ cameraState: 'exit' }), + }), + { + name: 'camera-state-storage', + storage: createJSONStorage(() => localStorage), + }, + ), +); diff --git a/src/renderer/src/store/useNotificationStore.ts b/src/renderer/src/store/useNotificationStore.ts new file mode 100644 index 0000000..5380d81 --- /dev/null +++ b/src/renderer/src/store/useNotificationStore.ts @@ -0,0 +1,67 @@ +import { create } from 'zustand'; +import { persist, createJSONStorage } from 'zustand/middleware'; + +export interface NotificationSettings { + isAllow: boolean; + stretching: { + isEnabled: boolean; + interval: number; // 분 단위 + }; + turtleNeck: { + isEnabled: boolean; + interval: number; // 분 단위 + }; +} + +interface NotificationStore extends NotificationSettings { + setIsAllow: (isAllow: boolean) => void; + setStretchingEnabled: (isEnabled: boolean) => void; + setStretchingInterval: (interval: number) => void; + setTurtleNeckEnabled: (isEnabled: boolean) => void; + setTurtleNeckInterval: (interval: number) => void; + setSettings: (settings: NotificationSettings) => void; +} + +export const useNotificationStore = create()( + persist( + (set) => ({ + isAllow: false, + stretching: { + isEnabled: false, + interval: 30, + }, + turtleNeck: { + isEnabled: false, + interval: 10, + }, + + setIsAllow: (isAllow) => set({ isAllow }), + + setStretchingEnabled: (isEnabled) => + set((state) => ({ + stretching: { ...state.stretching, isEnabled }, + })), + + setStretchingInterval: (interval) => + set((state) => ({ + stretching: { ...state.stretching, interval }, + })), + + setTurtleNeckEnabled: (isEnabled) => + set((state) => ({ + turtleNeck: { ...state.turtleNeck, isEnabled }, + })), + + setTurtleNeckInterval: (interval) => + set((state) => ({ + turtleNeck: { ...state.turtleNeck, interval }, + })), + + setSettings: (settings) => set(settings), + }), + { + name: 'notification-settings-storage', + storage: createJSONStorage(() => sessionStorage), + }, + ), +); diff --git a/src/renderer/src/store/usePostureStore.ts b/src/renderer/src/store/usePostureStore.ts new file mode 100644 index 0000000..643f7a6 --- /dev/null +++ b/src/renderer/src/store/usePostureStore.ts @@ -0,0 +1,23 @@ +import { create } from 'zustand'; +import { createJSONStorage, persist } from 'zustand/middleware'; + +interface PostureState { + postureClass: 1 | 2 | 3 | 4 | 5 | 6 | 0; + score: number; + setStatus: (postureClass: 1 | 2 | 3 | 4 | 5 | 6 | 0, score?: number) => void; +} + +/* 자세 상태 저장소 localstorage 동기화 추가 */ +export const usePostureStore = create()( + persist( + (set) => ({ + postureClass: 0, + score: 0, + setStatus: (postureClass, score = 0) => set({ postureClass, score }), + }), + { + name: 'posture-state-storage', // localStorage 키 + storage: createJSONStorage(() => localStorage), + }, + ), +); diff --git a/src/renderer/src/styles/base.css b/src/renderer/src/styles/base.css index 867b991..30c68bc 100644 --- a/src/renderer/src/styles/base.css +++ b/src/renderer/src/styles/base.css @@ -27,3 +27,31 @@ font-family: 'Pretendard', system-ui, sans-serif; } } + +/* 커스텀 스크롤바 스타일 */ +@layer utilities { + /* 웹킷 브라우저용 (Chrome, Safari, Edge) */ + .custom-scrollbar::-webkit-scrollbar { + width: 8px; + } + + .custom-scrollbar::-webkit-scrollbar-track { + background: transparent; + border-radius: 999px; + } + + .custom-scrollbar::-webkit-scrollbar-thumb { + background: var(--color-grey-50); + border-radius: 999px; + } + + .custom-scrollbar::-webkit-scrollbar-thumb:hover { + background: var(--color-grey-100); + } + + /* Firefox용 */ + .custom-scrollbar { + scrollbar-width: thin; + scrollbar-color: var(--color-grey-50) transparent; + } +} diff --git a/src/renderer/src/styles/breakpoint.css b/src/renderer/src/styles/breakpoint.css index d844589..aa7940f 100644 --- a/src/renderer/src/styles/breakpoint.css +++ b/src/renderer/src/styles/breakpoint.css @@ -8,16 +8,24 @@ --breakpoint-2xl: 96rem; /* 1536px - 초대형 */ /* 커스텀 Breakpoints */ - --breakpoint-hbp: 57.5rem; /* 920px - 하이브리드 */ + --breakpoint-minimum: 128rem; /* 2048px - 하이퍼 대형 */ + --breakpoint-mini: 18rem; + --breakpoint-hbp: 160rem; /* 2560px - 하이브리드 */ --breakpoint-mobile: 30rem; /* 480px - 모바일 최적화 */ --breakpoint-tablet: 56rem; /* 896px - 태블릿 최적화 */ + + --breakpoint-minimum: 1280px; + --breakpoint-labtop: 1440px; + --breakpoint-desktop: 1920px; } /* 미디어 쿼리 헬퍼 */ @custom-media --mobile (max-width: 30rem); @custom-media --tablet (min-width: 30rem) and (max-width: 56rem); -@custom-media --desktop (min-width: 56rem); @custom-media --large (min-width: 80rem); +@custom-media --minimum (min-width: 1280px); +@custom-media --labtop (min-width: 1440px); +@custom-media --desktop (min-width: 1920px); /* 컨테이너 최대 너비 */ .container { diff --git a/src/renderer/src/styles/colors.css b/src/renderer/src/styles/colors.css index 96e1f74..e473b36 100644 --- a/src/renderer/src/styles/colors.css +++ b/src/renderer/src/styles/colors.css @@ -16,13 +16,15 @@ --color-yellow-100: #ffebb0; --color-yellow-200: #ffe28a; --color-yellow-300: #ffd454; - --color-yellow-400: #ffcc33; + --color-yellow-400: #ffcb31; --color-yellow-500: #ffbf00; --color-yellow-600: #e8ae00; --color-yellow-700: #d29a00; --color-yellow-800: #bd8700; --color-yellow-900: #a67100; + --color-sementic-brand-primary: #ffbf00; + /* Grey 컬러 팔레트 */ --color-grey-0: #ffffff; --color-grey-25: #f9f8f7; @@ -45,8 +47,43 @@ #ffbf00 50%, #ffae00 100% ); - --color-error: #ff3232; - --color-success: #00bf29; + + /* notification colors*/ + --color-error: #ff351f; + --color-success: #67b000; + --color-bg-line: var(--color-grey-50); + --color-point-red: #ff6647; + --color-point-green: #a1b100; + + --color-dot: #fff; + --color-icon-stroke: #a8a7a4; + --color-check-stroke: #ffffff; + --color-check-fill: #c6c5c3; + --color-logo-fill: #3c3b3a; + --color-sun-stroke: #191917; + --color-moon-stroke: #6a6966; + + /* widget-color*/ + --color-olive-green: #a1b100; + --color-coral-red: #ff6647; + + --color-widget-gradient: linear-gradient( + 180deg, + var(--color-olive-green) 0.18%, + var(--color-success) 99.7% + ); + --color-widget-red: linear-gradient( + 180deg, + var(--color-coral-red) 0%, + var(--color-error) 100% + ); + + /* 모달 컬러 */ + --color-surface-modal: #ffffff; + --color-surface-modal-container: #f9f8f7; + --color-modal-button: #f9f8f7; + --color-modal-disabled: #e3e1df; + --color-global-yellow-100: #ffebb0; } @theme inline { @@ -76,21 +113,59 @@ --color-grey-900: var(--color-grey-900); --color-grey-950: var(--color-grey-950); --color-grey-1000: var(--color-grey-1000); + + /* notification colors*/ + --color-error: var(--color-error); + --color-success: var(--color-success); + + --color-point-red: var(--color-point-red); + --color-point-green: var(--color-point-green); + --color-bg-line: var(--color-grey-50); + /* icon-color*/ + --color-dot: var(--color-dot); + --color-icon-stroke: var(--color-icon-stroke); + --color-check-stroke: var(--color-check-stroke); + --color-check-fill: var(--color-check-fill); + --color-logo-fill: var(--color-logo-fill); + --color-sun-stroke: var(--color-sun-stroke); + --color-moon-stroke: var(--color-moon-stroke); + + /* widget-color*/ + --color-olive-green: var(--color-olive-green); + --color-coral-red: var(--color-coral-red); + + /* main page color */ + --color-average-score: linear-gradient( + 130deg, + var(--color-yellow-500) -9.87%, + var(--color-yellow-400) 25.52%, + var(--color-yellow-200) 97.31% + ); + + /* 모달 컬러 */ + --color-surface-modal: var(--color-surface-modal); + --color-surface-modal-container: var(--color-surface-modal-container); + --color-modal-button: var(--color-modal-button); + --color-modal-disabled: var(--color-modal-disabled); + --color-sementic-brand-primary: var(--color-sementic-brand-primary); + --color-global-yellow-100: var(--color-global-yellow-100); } /* Dark mode colors */ .dark { /* Dark mode Yellow (더 어두운 톤) */ - --color-yellow-50: #624d0b; - --color-yellow-100: #806310; - --color-yellow-200: #9d7b13; - --color-yellow-300: #c59a18; - --color-yellow-400: #e0ae1c; - --color-yellow-500: #e7bd3e; - --color-yellow-600: #e9c34f; - --color-yellow-700: #edcd73; - --color-yellow-800: #f2da9b; - --color-yellow-900: #f7e5c0; + --color-yellow-50: #493704; + --color-yellow-100: #795706; + --color-yellow-200: #a57909; + --color-yellow-300: #cb980b; + --color-yellow-400: #e9b20c; + --color-yellow-500: #f5c73d; + --color-yellow-600: #f7d364; + --color-yellow-700: #f9da86; + --color-yellow-800: #fae19e; + --color-yellow-900: #fbe7bb; + + --color-sementic-brand-primary: #e9b20c; /* Dark mode Grey (역전된 스케일) */ --color-grey-0: #191917; @@ -107,4 +182,39 @@ --color-grey-900: #f9f8f7; --color-grey-950: #fcfcfc; --color-grey-1000: #ffffff; + + /* Dark mode notification colors*/ + --color-error: #c92504; + --color-success: #839400; + + --color-point-red: #f15232; + --color-point-green: #839400; + + /* icon-color*/ + --color-icon-stroke: #6a6966; + --color-check-stroke: #191917; + --color-check-fill: #3c3b3a; + --color-logo-fill: #c6c5c3; + --color-sun-stroke: #6a6966; + --color-moon-stroke: #191917; + + /* widget-color*/ + --color-olive-green: #477d00; + --color-coral-red: #f15232; + + /* main page color */ + --color-average-score: linear-gradient( + 130deg, + var(--color-yellow-500) -9.87%, + var(--color-yellow-400) 25.52%, + var(--color-yellow-200) 97.31% + ); + + /* 모달 컬러 */ + --color-bg-line: var(--color-grey-50); + --color-surface-modal: #131312; + --color-surface-modal-container: #191917; + --color-modal-button: #232323; + --color-modal-disabled: #2c2c2c; + --color-global-yellow-100: rgba(73, 55, 4, 0.5); } diff --git a/src/renderer/src/styles/fonts.css b/src/renderer/src/styles/fonts.css index 41b5857..21cf68a 100644 --- a/src/renderer/src/styles/fonts.css +++ b/src/renderer/src/styles/fonts.css @@ -1,8 +1,7 @@ /* 폰트 관련 스타일 */ @font-face { font-family: 'Pretendard'; - src: url('../../../../assets/fonts/PretendardVariable.woff2') - format('woff2-variations'); + src: url('/fonts/PretendardVariable.woff2') format('woff2-variations'); font-weight: 100 900; font-style: normal; font-display: swap; diff --git a/src/renderer/src/styles/globals.css b/src/renderer/src/styles/globals.css index 2f553f9..c806a2a 100644 --- a/src/renderer/src/styles/globals.css +++ b/src/renderer/src/styles/globals.css @@ -6,3 +6,48 @@ @import './breakpoint.css'; @custom-variant dark (&:where(.dark, .dark *)); + +/* 슬라이드 애니메이션 */ +@keyframes slide-next { + from { + opacity: 0; + transform: translateX(30px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slide-prev { + from { + opacity: 0; + transform: translateX(-30px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.animate-slide-next { + animation: slide-next 0.3s ease-out; +} + +.animate-slide-prev { + animation: slide-prev 0.3s ease-out; +} + +/* 페이드인 애니메이션 */ +@keyframes fade-in { + from { + opacity: 0.6; + } + to { + opacity: 1; + } +} + +.animate-fade-in { + animation: fade-in 0.4s ease-out; +} diff --git a/src/renderer/src/styles/typography.css b/src/renderer/src/styles/typography.css index 988c293..2663dc1 100644 --- a/src/renderer/src/styles/typography.css +++ b/src/renderer/src/styles/typography.css @@ -24,6 +24,11 @@ font-weight: 600; } +@utility text-headline-3xl-bold { + font-size: 24px; + font-weight: 700; +} + @utility text-headline-2xl-regular { font-size: 22px; font-weight: 400; @@ -98,3 +103,23 @@ font-size: 14px; font-weight: 600; } + +@utility text-caption-xs-meidum { + font-size: 12px; + font-weight: 500; +} + +@utility text-caption-xs-regular { + font-size: 12px; + font-weight: 400; +} + +@utility text-caption-2xs-regular { + font-size: 10px; + font-weight: 400; +} + +@utility text-caption-2xs-medium { + font-size: 10px; + font-weight: 500; +} diff --git a/src/renderer/src/types/dashboard/averageScore.ts b/src/renderer/src/types/dashboard/averageScore.ts new file mode 100644 index 0000000..4a0c67c --- /dev/null +++ b/src/renderer/src/types/dashboard/averageScore.ts @@ -0,0 +1,11 @@ +export interface AverageScoreData { + score: number; +} + +export interface AverageScoreResponse { + timestamp: string; + success: boolean; + data: AverageScoreData; + code: string; + message: string | null; +} diff --git a/src/renderer/src/types/dashboard/level.ts b/src/renderer/src/types/dashboard/level.ts new file mode 100644 index 0000000..9c4e91e --- /dev/null +++ b/src/renderer/src/types/dashboard/level.ts @@ -0,0 +1,13 @@ +export interface LevelData { + level: number; + current: number; + required: number; +} + +export interface LevelResponse { + timestamp: string; + success: boolean; + data: LevelData; + code: string; + message: string | null; +} diff --git a/src/renderer/src/types/dashboard/postureGraph.ts b/src/renderer/src/types/dashboard/postureGraph.ts new file mode 100644 index 0000000..b793259 --- /dev/null +++ b/src/renderer/src/types/dashboard/postureGraph.ts @@ -0,0 +1,11 @@ +export interface PostureGraphData { + points: Record; +} + +export interface PostureGraphResponse { + timestamp: string; + success: boolean; + data: PostureGraphData; + code: string; + message: string | null; +} diff --git a/src/renderer/src/types/main/session.ts b/src/renderer/src/types/main/session.ts new file mode 100644 index 0000000..eab36d8 --- /dev/null +++ b/src/renderer/src/types/main/session.ts @@ -0,0 +1,54 @@ +/* 세션 생성 API 타입 */ +export interface CreateSessionResponse { + timestamp: string; + success: boolean; + data: { + sessionId: string; + }; + code: string; + message: string; +} + +/* 세션 중단/일시정지 공통 응답 타입 */ +export interface SessionActionResponse { + timestamp: string; + success: boolean; + code: string; + message: string; +} + +/* 세션 메트릭 데이터 타입 */ +export interface MetricData { + score: number; + timestamp: string; +} + +/* 세션 메트릭 저장 요청 타입 */ +export interface SaveMetricsRequest { + sessionId: string; + metrics: MetricData[]; +} + +/* 세션 메트릭 저장 응답 타입 */ +export interface SaveMetricsResponse { + timestamp: string; + success: boolean; + code: string; + message: string; +} + +/* 세션 리포트 데이터 타입 */ +export interface SessionReportData { + totalSeconds: number; // 전체 세션 시간 (초) + goodSeconds: number; // 좋은 자세 유지 시간 (초) + score: number; // 세션 점수 +} + +/* 세션 리포트 응답 타입 */ +export interface SessionReportResponse { + timestamp: string; + success: boolean; + data: SessionReportData; + code: string; + message: string; +} diff --git a/src/renderer/src/types/vite-env.d.ts b/src/renderer/src/types/vite-env.d.ts index 11f02fe..b1f45c7 100644 --- a/src/renderer/src/types/vite-env.d.ts +++ b/src/renderer/src/types/vite-env.d.ts @@ -1 +1,2 @@ /// +/// diff --git a/src/renderer/src/utils/getColor.ts b/src/renderer/src/utils/getColor.ts new file mode 100644 index 0000000..7633417 --- /dev/null +++ b/src/renderer/src/utils/getColor.ts @@ -0,0 +1,8 @@ +// CSS 변수에서 색상 가져오기 +export const getColor = (cssVar: string, fallback: string) => { + return ( + getComputedStyle(document.documentElement) + .getPropertyValue(cssVar) + .trim() || fallback + ); +}; diff --git a/src/renderer/src/utils/getScoreLevel.ts b/src/renderer/src/utils/getScoreLevel.ts new file mode 100644 index 0000000..0dd6fea --- /dev/null +++ b/src/renderer/src/utils/getScoreLevel.ts @@ -0,0 +1,111 @@ +/** + * 점수를 6단계 레벨로 분류합니다. + * + * @param score - 분류할 점수 + * @returns 레벨 (1-6)과 레벨 정보 + */ +export type ScoreLevel = 1 | 2 | 3 | 4 | 5 | 6; + +export interface ScoreLevelInfo { + level: ScoreLevel; + label: string; + name: string; // 레벨 이름 (angel-rini, pm-rini, rini, bugi, stone-bugi, tire-bugi) + percentile: string; + minScore: number; + maxScore: number | null; // null이면 무한대 +} + +const LEVEL_DEFINITIONS: Record = { + 1: { + level: 1, + label: 'L1', + name: 'angel-rini', + percentile: '하위 5%', + minScore: Number.NEGATIVE_INFINITY, + maxScore: -7.0, + }, + 2: { + level: 2, + label: 'L2', + name: 'pm-rini', + percentile: '25%', + minScore: -7.0, + maxScore: -3.6, + }, + 3: { + level: 3, + label: 'L3', + name: 'rini', + percentile: '45% (고정)', + minScore: -3.6, + maxScore: 1.2, + }, + 4: { + level: 4, + label: 'L4', + name: 'bugi', + percentile: '70%', + minScore: 1.2, + maxScore: 6.0, + }, + 5: { + level: 5, + label: 'L5', + name: 'stone-bugi', + percentile: '95%', + minScore: 6.0, + maxScore: 12.5, + }, + 6: { + level: 6, + label: 'L6', + name: 'tire-bugi', + percentile: '상위 5%', + minScore: 12.5, + maxScore: Number.POSITIVE_INFINITY, + }, +}; + +/** + * 점수를 기반으로 레벨을 반환합니다. + * + * @param score - 분류할 점수 + * @returns 레벨 정보 + */ +export function getScoreLevel(score: number): ScoreLevelInfo { + // L1: score ≤ -7.0 + if (score <= -7.0) { + return LEVEL_DEFINITIONS[1]; + } + + // L2: -7.0 < score ≤ -3.6 + if (score > -7.0 && score <= -3.6) { + return LEVEL_DEFINITIONS[2]; + } + + // L3: -3.6 < score ≤ 1.2 + if (score > -3.6 && score <= 1.2) { + return LEVEL_DEFINITIONS[3]; + } + + // L4: 1.2 < score ≤ 6.0 + if (score > 1.2 && score <= 6.0) { + return LEVEL_DEFINITIONS[4]; + } + + // L5: 6.0 < score ≤ 12.5 + if (score > 6.0 && score <= 12.5) { + return LEVEL_DEFINITIONS[5]; + } + + // L6: score > 12.5 + return LEVEL_DEFINITIONS[6]; +} + +/** + * 모든 레벨 정의를 반환합니다. + */ +export function getAllLevelDefinitions(): ScoreLevelInfo[] { + return Object.values(LEVEL_DEFINITIONS); +} + diff --git a/src/renderer/tsconfig.json b/src/renderer/tsconfig.json index 13e9a25..6d8b6fe 100644 --- a/src/renderer/tsconfig.json +++ b/src/renderer/tsconfig.json @@ -13,6 +13,7 @@ "preserveWatchOutput": true, "skipLibCheck": true, "strict": true, + "resolveJsonModule": true, "lib": ["ES2015", "DOM"], "module": "ESNext", "target": "ES6", @@ -21,14 +22,17 @@ "noEmit": true, "baseUrl": ".", "paths": { - "@ui/*": ["./src/packages/ui/components/*"], - "@assets/*": ["./src/assets/*"] + "@ui/*": ["./src/components/*"], + "@assets/*": ["./src/assets/*"], + "@api/*": ["./src/api/*"], + "@utils/*": ["./src/utils/*"] } }, "include": [ "src/**/*.ts", "src/**/*.tsx", - "../preload/exposedInMainWorld.d.ts" + "../preload/exposedInMainWorld.d.ts", + "src/types/*.d.ts" ], - "exclude": ["node_modules"] + "exclude": ["node_modules", "dist"] } diff --git a/vite.config.mts b/vite.config.mts index cdc49de..39b3464 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -10,15 +10,19 @@ const __dirname = path.dirname(__filename); // https://vitejs.dev/config/ export default defineConfig({ - base: './', + base: '/', root: 'src/renderer', - plugins: [react(), tailwindcss(), svgr()], + plugins: [svgr(), react(), tailwindcss()], resolve: { alias: { '@ui/': path.resolve(__dirname, 'src/renderer/src/components') + '/', '@ui': path.resolve(__dirname, 'src/renderer/src/components'), '@assets/': path.resolve(__dirname, 'src/renderer/src/assets') + '/', '@assets': path.resolve(__dirname, 'src/renderer/src/assets'), + '@api/': path.resolve(__dirname, 'src/renderer/src/api') + '/', + '@api': path.resolve(__dirname, 'src/renderer/src/api'), + '@utils/': path.resolve(__dirname, 'src/renderer/src/utils') + '/', + '@utils': path.resolve(__dirname, 'src/renderer/src/utils'), ui: path.resolve(__dirname, 'src/renderer/src/components'), }, }, @@ -27,7 +31,7 @@ export default defineConfig({ host: 'localhost', }, build: { - outDir: '../dist/renderer', + outDir: path.resolve(__dirname, 'dist/renderer'), sourcemap: true, emptyOutDir: true, },