diff --git a/.eslintrc.json b/.eslintrc.json index eb413c0..1b0773e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,6 +5,17 @@ "ecmaVersion": 2020, "sourceType": "module" }, + "ignorePatterns": [ + "tests/**/*", + "**/*.test.ts", + "**/*.test.tsx", + "**/test-mocks/**/*", + "**/dist/**/*", + "**/node_modules/**/*", + "**/coverage/**/*", + "**/*.config.js", + "**/*.config.ts" + ], "rules": { "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], "@typescript-eslint/explicit-function-return-type": "off" @@ -15,7 +26,10 @@ "rules": { "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/ban-types": "off", - "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }] + "@typescript-eslint/no-unused-vars": [ + "error", + { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" } + ] } }, { diff --git a/.github/pre-commit-hook.sh b/.github/pre-commit-hook.sh new file mode 100755 index 0000000..2f53c43 --- /dev/null +++ b/.github/pre-commit-hook.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Pre-commit hook for CodeLink +# This script runs linting, type checking, and formatting checks before allowing commits +# +# To install this hook, run: +# cp .github/pre-commit-hook.sh .git/hooks/pre-commit +# chmod +x .git/hooks/pre-commit + +set -e + +echo "🔍 Running pre-commit checks..." +echo "" + +# Run ESLint +echo "📝 Running ESLint..." +npm run lint +echo "✅ ESLint passed" +echo "" + +# Run TypeScript checks +echo "🔧 Running TypeScript checks..." +npm run typecheck +echo "✅ TypeScript checks passed" +echo "" + +# Check code formatting +echo "💅 Checking code formatting..." +npm run format:check +echo "✅ Code formatting is correct" +echo "" + +echo "✨ All pre-commit checks passed! Proceeding with commit..." diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..5a70f60 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,53 @@ +name: Lint and Type Check + +on: + push: + branches: + - '**' + pull_request: + branches: + - main + +jobs: + lint: + name: Lint and Type Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run ESLint + run: npm run lint + continue-on-error: false + + - name: Check code formatting + run: npm run format:check + continue-on-error: false + + - name: TypeScript check - Protocol + run: | + cd packages/protocol + npx tsc --noEmit + continue-on-error: false + + - name: TypeScript check - Relay Server + run: | + cd packages/relay-server + npx tsc --noEmit + continue-on-error: false + + - name: TypeScript check - VSCode Extension + run: | + cd packages/vscode-extension + npx tsc --noEmit + continue-on-error: false diff --git a/.gitignore b/.gitignore index 6eb8faf..f826ec1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,35 @@ dist/ .DS_Store .vscode-test/ *.vsix +.vscode .kiro -.vscode \ No newline at end of file + +# Test directory (centralized testing infrastructure) +tests/ +coverage/ + +docs/ +MANUAL_TESTING_EDITOR_ADAPTERS.md +QUICK_START_TESTING.md + +# ANDORID TESTING MANUALS +ANDROID_TESTING_GUIDE.md +ANDROID_TESTING_NOTES.md +ANDROID_TESTING_VERIFICATION.md +QUICK_START_ANDROID_TESTING.md +README_ANDROID_TESTING.md + +# IOS TESING MANUAL +IOS_TESTING_GUIDE.md +IOS_TESTING_VERIFICATION.md +QUICK_START_IOS_TESTING.md +PROJECT_ANALYSIS.md +TESTING_SPEC_SUMMARY.md +CI_CD_SETUP.md +COVERAGE_VERIFICATION.md +STITCH_UI_DESIGN_PROMPT.md +QUICK_REFERENCE.md +CI_CD_IMPROVEMENTS_SUMMARY.md + +# DESIGN FILES +design/ \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..2ad1625 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,20 @@ +# Test directories and files +tests/ +**/*.test.ts +**/*.test.tsx +**/test-mocks/ + +# Build outputs +dist/ +build/ +coverage/ + +# Dependencies +node_modules/ + +# Configuration files +*.config.js +*.config.ts + +# Generated files +*.d.ts diff --git a/MANUAL_TESTING_GUIDE.md b/MANUAL_TESTING_GUIDE.md deleted file mode 100644 index 58c0bf4..0000000 --- a/MANUAL_TESTING_GUIDE.md +++ /dev/null @@ -1,351 +0,0 @@ -# Manual Testing Guide: Git Integration & File Diffing - -This guide walks you through manually testing the Git Integration & File Diffing feature end-to-end. - -## Prerequisites - -- Node.js 20.x or higher -- VS Code installed -- A Git repository (this CodeLink project works perfectly) -- Three terminal windows - -## Setup (One-Time) - -1. **Build all packages**: - ```bash - npm run build - ``` - -2. **Verify the build succeeded**: - ```bash - ls packages/protocol/dist - ls packages/relay-server/dist - ls packages/vscode-extension/dist - ls packages/mobile-client/dist - ``` - -## Manual Testing Steps - -### Step 1: Start the Relay Server - -**Terminal 1:** -```bash -cd packages/relay-server -npm start -``` - -**Expected Output:** -``` -[RelayServer] CodeLink Relay Server listening on port 8080 -``` - -**Troubleshooting:** -- If you see "Address already in use", another process is using port 8080 -- Change the port: `PORT=3000 npm start` -- Remember to update the mobile client URL in Step 2 - ---- - -### Step 2: Start the Mobile Client - -**Terminal 2:** -```bash -cd packages/mobile-client -npm run dev -``` - -**Expected Output:** -``` -VITE v5.x.x ready in XXX ms - -➜ Local: http://localhost:5173/ -➜ Network: use --host to expose -``` - -**Open in Browser:** -1. Open http://localhost:5173/ in your browser (or the URL shown) -2. Open browser DevTools (F12) and go to Console tab - -**Expected Behavior:** -- You should see "Connected" status (green indicator) -- Console should show: - ``` - [WebSocketClient] Connected to relay server - [WebSocketClient] Sending ping to register as mobile client - [WebSocketClient] Received message: {type: "pong", ...} - ``` - -**Troubleshooting:** -- If you see "Disconnected" (red), check that relay server is running -- If relay server is on a different port, update the URL in `packages/mobile-client/src/App.tsx` - ---- - -### Step 3: Start VS Code Extension - -**Terminal 3:** -```bash -# Make sure you're in the root directory -code . -``` - -**In VS Code:** -1. Press **F5** to launch Extension Development Host -2. A new VS Code window will open (titled "[Extension Development Host]") -3. In the new window, open this CodeLink project folder - -**Expected Output in Debug Console:** -``` -CodeLink extension activating... -Workspace root: /path/to/CodeLink -Git integration initialized successfully -Diff generator initialized -WebSocket client connecting to http://localhost:3000 -File watcher initialized -CodeLink extension activated successfully -``` - -**Troubleshooting:** -- If you don't see the debug console, go to View → Debug Console -- If Git integration fails, make sure you're in a Git repository -- If WebSocket fails, check the relay server URL in `packages/vscode-extension/src/extension.ts` (line 52) - ---- - -### Step 4: Test File Change Detection - -**In the Extension Development Host window:** - -1. **Open a file** in the CodeLink project (e.g., `README.md`) -2. **Make a change** - add a line or modify existing text -3. **Wait 1 second** (debounce period) - -**Expected Behavior:** - -**In VS Code Debug Console:** -``` -[INFO] File changed: /path/to/CodeLink/README.md -[PERF] Git operation: XXms (HEAD content: XXX bytes) -[PERF] Diff generation: XXms (README.md, isDirty: true) -[PERF] WebSocket send: XXms (message id: ...) -[PERF] Total pipeline: XXXms -``` - -**In Relay Server Terminal:** -``` -[RelayServer] Received message type: SYNC_FULL_CONTEXT from [socket-id] -[RelayServer] Routing SYNC_FULL_CONTEXT message to 1 mobile clients -[RelayServer] Broadcast complete: 1 successful, 0 errors, 1 total mobile clients -``` - -**In Mobile Client Browser:** -- The diff viewer should update automatically -- You should see: - - File name: `README.md` - - Orange dot (dirty indicator) next to the file name - - Timestamp showing when the diff was generated - - Unified diff showing your changes: - - Red lines (deletions) with `-` prefix - - Green lines (additions) with `+` prefix - -**Troubleshooting:** -- If nothing happens, check the VS Code Debug Console for errors -- If you see errors about Git, make sure the file is tracked by Git -- If the mobile client doesn't update, check browser console for errors - ---- - -### Step 5: Test Different Scenarios - -#### Scenario A: Untracked File (New File) - -1. **Create a new file** in the Extension Development Host: - ```bash - # In Terminal 3 - echo "console.log('new file');" > newfile.ts - ``` - -2. **Open the file** in VS Code - -3. **Expected Result:** - - Mobile client shows the entire file as additions (all green lines) - - No orange dot (isDirty: false) - - originalFile is empty - -#### Scenario B: No Changes - -1. **Open a file** that hasn't been modified since last commit -2. **Expected Result:** - - Mobile client shows "No changes" or identical content - - No orange dot (isDirty: false) - -#### Scenario C: Save File - -1. **Make changes** to a file -2. **Wait for diff** to appear on mobile (with orange dot) -3. **Save the file** (Ctrl+S / Cmd+S) -4. **Wait 1 second** -5. **Expected Result:** - - Orange dot should disappear (isDirty: false) - - Diff still shows changes compared to HEAD - -#### Scenario D: Multiple Rapid Changes - -1. **Open a file** -2. **Type rapidly** without stopping for 1 second -3. **Expected Result:** - - Only ONE diff should be sent after you stop typing - - Check Debug Console - should see only one pipeline execution - -#### Scenario E: Large File - -1. **Open a large file** (>1000 lines) -2. **Make a change** -3. **Expected Result:** - - Should still complete within 2 seconds - - Check Debug Console for performance metrics - - If file is >50KB, you should see compression logs - ---- - -### Step 6: Test Multiple Mobile Clients - -1. **Open a second browser tab** to http://localhost:5173/ -2. **Make a change** in VS Code -3. **Expected Result:** - - BOTH browser tabs should receive the diff simultaneously - - Check relay server logs - should show "Routing to 2 mobile clients" - ---- - -### Step 7: Test Error Handling - -#### Test A: Disconnect Mobile Client - -1. **Close the mobile client browser tab** -2. **Make a change** in VS Code -3. **Expected Result:** - - VS Code should queue the message - - Relay server should show "0 mobile clients" - - No errors in VS Code Debug Console - -#### Test B: Disconnect Relay Server - -1. **Stop the relay server** (Ctrl+C in Terminal 1) -2. **Make a change** in VS Code -3. **Expected Result:** - - VS Code should queue messages - - Mobile client should show "Disconnected" (red) -4. **Restart relay server** -5. **Expected Result:** - - Mobile client reconnects automatically - - Queued messages are sent - -#### Test C: Binary File - -1. **Open a binary file** (e.g., an image) -2. **Expected Result:** - - Should handle gracefully (may skip or show as binary) - ---- - -## Performance Verification - -### Check Total Pipeline Time - -1. **Make a change** to a file -2. **Check VS Code Debug Console** for the line: - ``` - [PERF] Total pipeline: XXXms - ``` -3. **Expected:** Should be under 2000ms (typically 100-500ms) - -### Check Individual Stages - -Look for these performance logs: -- `[PERF] Git operation: XXms` - Should be <500ms -- `[PERF] Diff generation: XXms` - Should be <200ms -- `[PERF] WebSocket send: XXms` - Should be <100ms - ---- - -## Cleanup - -When you're done testing: - -1. **Close Extension Development Host** window -2. **Stop relay server** (Ctrl+C in Terminal 1) -3. **Stop mobile client** (Ctrl+C in Terminal 2) -4. **Close browser tabs** - ---- - -## Common Issues and Solutions - -### Issue: "Git repository not found" -**Solution:** Make sure you're testing in a Git repository. Run `git init` if needed. - -### Issue: "WebSocket connection failed" -**Solution:** -- Check relay server is running -- Verify port numbers match (default: 8080 for relay, 3000 for extension) -- Check firewall settings - -### Issue: "No diff appears on mobile" -**Solution:** -- Check browser console for errors -- Verify mobile client is connected (green status) -- Check relay server logs to see if message was routed - -### Issue: "Extension not activating" -**Solution:** -- Check VS Code Debug Console for errors -- Rebuild packages: `npm run build` -- Restart Extension Development Host (F5) - -### Issue: "Diff shows but is incorrect" -**Solution:** -- Verify file is tracked by Git: `git ls-files | grep filename` -- Check if file has been committed: `git status` -- Try committing changes and testing again - ---- - -## Success Criteria - -You've successfully tested the feature if: - -- ✅ File changes in VS Code appear on mobile within 1-2 seconds -- ✅ Diffs show correct additions (green) and deletions (red) -- ✅ Dirty indicator (orange dot) appears for unsaved files -- ✅ Untracked files show as all additions -- ✅ Multiple mobile clients receive updates simultaneously -- ✅ System handles disconnections gracefully -- ✅ Performance is under 2000ms end-to-end - ---- - -## Next Steps - -After manual testing, you can: - -1. **Run automated tests**: `npm test` -2. **Run property-based tests**: `npm test -- --grep "properties"` -3. **Run performance tests**: `npm test -- --grep "performance"` -4. **Check code coverage**: `npm test -- --coverage` - ---- - -## Feedback and Issues - -If you encounter issues not covered in this guide: - -1. Check the VS Code Debug Console for detailed error messages -2. Check the relay server terminal for connection issues -3. Check the browser console for mobile client errors -4. Review the logs for performance bottlenecks - -Happy testing! 🚀 - - -It is the test run of my project called 'CodeLink', I hope it must work. \ No newline at end of file diff --git a/README.md b/README.md index 8c4685f..c3b4aa6 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,14 @@ CodeLink consists of three main components: A Visual Studio Code extension that integrates with your local development environment. It communicates with the relay server to receive code change requests from the mobile client. **Git Integration Components**: + - **File Watcher**: Monitors active editor changes with 1000ms debouncing - **Git Integration Module**: Fetches HEAD versions from local Git repository using simple-git - **Diff Generator**: Compares HEAD vs current file state and generates FileContextPayload - **WebSocket Client**: Transmits SYNC_FULL_CONTEXT messages to relay server **Editor Adapter System**: + - **Editor Registry**: Manages and detects available AI code editors (Continue, Kiro, Cursor, Antigravity) - **Capability-Driven Architecture**: Adapts behavior based on what each editor supports - **Prompt Injection**: Sends prompts from mobile to AI editor chat panels using public VS Code commands @@ -101,6 +103,7 @@ External Dependencies: ``` **Data Flow**: + 1. User edits file in VS Code 2. File Watcher detects change (after 1000ms debounce) 3. Git Integration Module fetches HEAD version from Git repository @@ -125,12 +128,12 @@ CodeLink integrates with multiple AI code editors through a capability-driven ad #### Supported Editors -| Editor | Prompt Injection | Chat History | Token Streaming | Diff Artifacts | Sync Level | -|--------|-----------------|--------------|-----------------|----------------|------------| -| **Continue** | ✅ | ✅ | ✅ | ✅ | Full | -| **Kiro** | ✅ | ✅ | ✅ | ✅ | Partial | -| **Cursor** | ✅ | ❌ | ❌ | ❌ | Control-Only | -| **Antigravity** | ✅ | ❌ | ❌ | ❌ | Control-Only | +| Editor | Prompt Injection | Chat History | Token Streaming | Diff Artifacts | Sync Level | +| --------------- | ---------------- | ------------ | --------------- | -------------- | ------------ | +| **Continue** | ✅ | ✅ | ✅ | ✅ | Full | +| **Kiro** | ✅ | ✅ | ✅ | ✅ | Partial | +| **Cursor** | ✅ | ❌ | ❌ | ❌ | Control-Only | +| **Antigravity** | ✅ | ❌ | ❌ | ❌ | Control-Only | #### How It Works @@ -197,6 +200,7 @@ interface InjectPromptResponse { ``` **Message Flow**: + 1. Mobile client sends `INJECT_PROMPT` message to relay server 2. Relay server routes message to VS Code extension 3. Extension queries Editor Registry for best available adapter @@ -216,23 +220,27 @@ The Editor Adapter System follows these design principles: #### Troubleshooting **Prompt injection not working**: + - Verify an AI editor is installed in VS Code - Check VS Code Output panel for CodeLink extension logs - Ensure the editor's extension is activated (open its chat panel once) - Review the error message in the mobile client response **No editor detected**: + - Install at least one supported AI editor (Continue, Kiro, Cursor, or Antigravity) - Restart VS Code after installing an editor - Check that the editor extension is enabled in VS Code - Run "Developer: Show Running Extensions" to verify the editor is active **Wrong editor selected**: + - The system automatically selects the editor with the highest sync level - Preference order: Continue (full) > Kiro (partial) > Cursor/Antigravity (control-only) - To force a specific editor, disable other AI editor extensions **Command execution fails**: + - Ensure the AI editor is fully initialized (may take a few seconds after VS Code starts) - Check that the editor's chat panel can be opened manually - Review VS Code extension logs for detailed error messages @@ -307,15 +315,16 @@ interface SyncFullContextMessage { } interface FileContextPayload { - fileName: string; // Workspace-relative path (e.g., "src/index.ts") - originalFile: string; // Content from Git HEAD (empty if untracked) - modifiedFile: string; // Current file content from disk - isDirty: boolean; // True if file has unsaved changes - timestamp: number; // Unix timestamp in milliseconds + fileName: string; // Workspace-relative path (e.g., "src/index.ts") + originalFile: string; // Content from Git HEAD (empty if untracked) + modifiedFile: string; // Current file content from disk + isDirty: boolean; // True if file has unsaved changes + timestamp: number; // Unix timestamp in milliseconds } ``` **Message Flow**: + 1. VS Code extension creates `SYNC_FULL_CONTEXT` message with `FileContextPayload` 2. Message is sent to relay server via WebSocket 3. Relay server broadcasts message to all connected mobile clients @@ -332,6 +341,7 @@ The Git Integration feature is designed for responsive real-time feedback: - **End-to-End Latency**: Total time from last keystroke to mobile display is under 2 seconds **Performance Tips**: + - Large files (>10,000 lines) may take longer to process - Binary files are automatically skipped - Network latency affects WebSocket transmission time @@ -340,6 +350,7 @@ The Git Integration feature is designed for responsive real-time feedback: #### Troubleshooting **Diffs not appearing on mobile**: + - Verify the relay server is running and accessible - Check that the mobile client shows "Connected" status - Ensure the file is within your VS Code workspace @@ -347,36 +358,42 @@ The Git Integration feature is designed for responsive real-time feedback: - Verify the file is a text file (binary files are skipped) **Empty diffs for tracked files**: + - Ensure the file is committed to Git (check `git status`) - Verify Git repository is initialized in your workspace - Check that the file path is correct and relative to workspace root - Review VS Code extension logs for Git operation errors **Performance issues**: + - Large files (>10,000 lines) may experience slower processing - Check network latency between VS Code and relay server - Verify Git operations are not timing out (check logs) - Consider closing unused files to reduce monitoring overhead **Git repository not found**: + - Ensure your workspace is within a Git repository - Run `git rev-parse --show-toplevel` to verify Git is initialized - Check that the VS Code workspace folder is correctly configured - Review extension logs for Git initialization errors **WebSocket connection issues**: + - Verify relay server is running on the expected port (default: 8080) - Check firewall settings allow WebSocket connections - Ensure no other service is using the relay server port - Review browser console for WebSocket connection errors **Unsaved changes not reflected**: + - The diff shows disk content, not unsaved editor content - Save the file (Ctrl+S / Cmd+S) to see unsaved changes in the diff - The orange dot indicator shows when changes are unsaved - isDirty flag tracks unsaved state separately from diff content **Untracked files showing as all additions**: + - This is expected behavior for files not committed to Git - The originalFile will be empty for untracked files - Commit the file to Git to see proper diffs @@ -514,6 +531,27 @@ To verify the entire system is working: ## Code Quality Scripts +### CI/CD Pipeline + +CodeLink uses GitHub Actions for continuous integration. The pipeline runs on every commit and includes: + +- **Linting**: ESLint checks for code quality +- **Type Checking**: TypeScript compilation for all packages +- **Formatting**: Prettier verification +- **Testing**: Comprehensive test suites with 80% coverage requirement + +See [CI/CD Setup Documentation](.github/CI_CD_SETUP.md) for detailed information. + +### Pre-Commit Hooks + +Install Git hooks to run checks before each commit: + +```bash +./scripts/setup-git-hooks.sh +``` + +This will automatically run linting, type checking, and formatting checks before allowing commits. + ### Linting Check code for linting errors: @@ -522,6 +560,29 @@ Check code for linting errors: npm run lint ``` +Auto-fix linting issues: + +```bash +npm run lint:fix +``` + +### Type Checking + +Check TypeScript compilation for all packages: + +```bash +npm run typecheck +``` + +Check individual packages: + +```bash +npm run typecheck:protocol # Protocol package +npm run typecheck:relay # Relay server +npm run typecheck:vscode # VS Code extension +npm run typecheck:mobile # Mobile client +``` + ### Formatting Format all code files: @@ -536,6 +597,14 @@ Check if code is properly formatted: npm run format:check ``` +### Pre-Commit Check + +Run all checks (lint + typecheck + format): + +```bash +npm run precommit +``` + ### Testing Run all tests: @@ -550,6 +619,71 @@ Run tests in watch mode: npm run test:watch ``` +Run tests with coverage: + +```bash +npm run test:coverage +``` + +## Development Workflow + +### Starting a New Feature + +1. Create a feature branch: + + ```bash + git checkout -b feature/your-feature-name + ``` + +2. Install pre-commit hooks (first time only): + + ```bash + ./scripts/setup-git-hooks.sh + ``` + +3. Make your changes and commit: + + ```bash + git add . + git commit -m "feat: your feature description" + ``` + + The pre-commit hook will automatically run linting, type checking, and formatting checks. + +4. Push your changes: + + ```bash + git push origin feature/your-feature-name + ``` + +5. Create a pull request on GitHub + - CI/CD pipeline will run automatically + - All checks must pass before merging + - At least one approval is required + +### Before Committing + +Always run these checks locally: + +```bash +# Run all pre-commit checks +npm run precommit + +# Or run individually +npm run lint +npm run typecheck +npm run format:check +npm test +``` + +### Bypassing Pre-Commit Hooks + +In rare cases where you need to bypass the pre-commit hook (not recommended): + +```bash +git commit --no-verify -m "your message" +``` + ## Project Structure ``` diff --git a/package-lock.json b/package-lock.json index f731ffb..5ecb6de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,31 +14,28 @@ "@types/node": "^20.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", + "@vitest/coverage-v8": "^4.1.0", + "@vitest/ui": "^4.1.0", + "babel-preset-expo": "^54.0.10", "eslint": "^8.0.0", - "fast-check": "^3.0.0", + "fast-check": "^4.6.0", "prettier": "^3.0.0", "typescript": "^5.0.0", - "vitest": "^1.0.0" + "vitest": "^4.1.0" } }, - "node_modules/@adobe/css-tools": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", - "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, + "node_modules/@0no-co/graphql.web": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.2.0.tgz", + "integrity": "sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==", "license": "MIT", - "engines": { - "node": ">=10" + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "graphql": { + "optional": true + } } }, "node_modules/@asamuzakjp/css-color": { @@ -62,22 +59,10 @@ "dev": true, "license": "ISC" }, - "node_modules/@asamuzakjp/dom-selector": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz", - "integrity": "sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bidi-js": "^1.0.3", - "css-tree": "^2.3.1", - "is-potential-custom-element-name": "^1.0.1" - } - }, "node_modules/@babel/code-frame": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -88,38 +73,30 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, "node_modules/@babel/compat-data": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", - "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", - "dev": true, + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", - "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", - "dev": true, + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -139,20 +116,19 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", - "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -161,11 +137,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -182,12 +169,83 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", + "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -197,6 +255,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", @@ -214,7 +285,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -228,16 +298,74 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -260,17 +388,29 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helpers": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -280,13 +420,99 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -295,14 +521,15 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.0.tgz", + "integrity": "sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-decorators": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -311,11 +538,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-source": { + "node_modules/@babel/plugin-proposal-export-default-from": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.27.1.tgz", + "integrity": "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -327,2182 +553,8393 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "license": "MIT", - "engines": { - "node": ">=6.9.0" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", - "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", - "debug": "^4.3.1" + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/types": { + "node_modules/@babel/plugin-syntax-decorators": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.28.6.tgz", + "integrity": "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@codelink/mobile-client": { - "resolved": "packages/mobile-client", - "link": true - }, - "node_modules/@codelink/protocol": { - "resolved": "packages/protocol", - "link": true - }, - "node_modules/@codelink/relay-server": { - "resolved": "packages/relay-server", - "link": true - }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.28.6.tgz", + "integrity": "sha512-Svlx1fjJFnNz0LZeUaybRukSxZI3KkpApUmIRzEdXC5k8ErTOz0OD0kNrICi5Vc3GlpP5ZCeRyRO+mfWTSz+iQ==", "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { - "node": ">=18" + "node": ">=6.9.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.28.6.tgz", + "integrity": "sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@emotion/babel-plugin": { - "version": "11.13.5", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", - "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/serialize": "^1.3.3", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "license": "MIT" - }, - "node_modules/@emotion/cache": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", - "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "license": "MIT", "dependencies": { - "@emotion/memoize": "^0.9.0", - "@emotion/sheet": "^1.4.0", - "@emotion/utils": "^1.4.2", - "@emotion/weak-memoize": "^0.4.0", - "stylis": "4.2.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@emotion/css": { - "version": "11.13.5", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.13.5.tgz", - "integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "license": "MIT", "dependencies": { - "@emotion/babel-plugin": "^11.13.5", - "@emotion/cache": "^11.13.5", - "@emotion/serialize": "^1.3.3", - "@emotion/sheet": "^1.4.0", - "@emotion/utils": "^1.4.2" + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@emotion/hash": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", - "license": "MIT" - }, - "node_modules/@emotion/memoize": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", - "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", - "license": "MIT" - }, - "node_modules/@emotion/serialize": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", - "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "license": "MIT", "dependencies": { - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.2", - "csstype": "^3.0.2" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@emotion/sheet": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", - "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", - "license": "MIT" - }, - "node_modules/@emotion/unitless": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", - "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", - "license": "MIT" - }, - "node_modules/@emotion/utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", - "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", - "license": "MIT" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", - "license": "MIT" + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.29.0" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", + "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-flow": "^7.27.1" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", "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" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/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, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/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", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { - "node": "*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { - "node": ">=10.10.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/config-array/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, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/config-array/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", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { - "node": "*" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, "engines": { - "node": ">=12.22" + "node": ">=6.9.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", "license": "MIT", "dependencies": { - "@sinclair/typebox": "^0.27.8" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@kwsites/file-exists": { + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.0.tgz", + "integrity": "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "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-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "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-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse--for-generate-function-map": { + "name": "@babel/traverse", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@callstack/react-theme-provider": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.9.tgz", + "integrity": "sha512-tTQ0uDSCL0ypeMa8T/E9wAZRGKWj8kXP7+6RYgPTfOPs9N07C9xM8P02GJ3feETap4Ux5S69D9nteq9mEj86NA==", + "license": "MIT", + "dependencies": { + "deepmerge": "^3.2.0", + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/@callstack/react-theme-provider/node_modules/deepmerge": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", + "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@codelink/mobile-client": { + "resolved": "packages/mobile-client", + "link": true + }, + "node_modules/@codelink/protocol": { + "resolved": "packages/protocol", + "link": true + }, + "node_modules/@codelink/relay-server": { + "resolved": "packages/relay-server", + "link": true + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", + "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", + "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "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.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "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", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "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.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@expo-google-fonts/inter": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/inter/-/inter-0.2.3.tgz", + "integrity": "sha512-iHK9FI+dnE45X5c2Z5hSFwNH4zUWethizpbv3XUn0FIGw5jwvzriENz0a6wCdkI4/d+1QkurnHo5XHti7TbNJA==", + "license": "MIT" + }, + "node_modules/@expo-google-fonts/manrope": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/manrope/-/manrope-0.2.3.tgz", + "integrity": "sha512-2M9hzi5ku97ZbheGMyzqIdiIEmve0/ihBk9nVWRy2lVIchWqR2k2yIQPS7jKC/Az/e43tW3POLNeU6gQJQL9hw==", + "license": "MIT" + }, + "node_modules/@expo-google-fonts/space-grotesk": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/space-grotesk/-/space-grotesk-0.2.3.tgz", + "integrity": "sha512-UYEMIrzegR02pauH7gVMI7j6cUroTtJug6dH/aQFjMNz0UwZe6GUcrEtJDmsUHJjEZdxbYgHhaiIwswWVo0CMA==", + "license": "MIT" + }, + "node_modules/@expo/code-signing-certificates": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.6.tgz", + "integrity": "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==", + "license": "MIT", + "dependencies": { + "node-forge": "^1.3.3" + } + }, + "node_modules/@expo/config": { + "version": "12.0.13", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", + "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "~7.10.4", + "@expo/config-plugins": "~54.0.4", + "@expo/config-types": "^54.0.10", + "@expo/json-file": "^10.0.8", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "require-from-string": "^2.0.2", + "resolve-from": "^5.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4", + "sucrase": "~3.35.1" + } + }, + "node_modules/@expo/config-plugins": { + "version": "54.0.4", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", + "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^54.0.10", + "@expo/json-file": "~10.0.8", + "@expo/plist": "^0.4.8", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slash": "^3.0.0", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/config-types": { + "version": "54.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", + "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", + "license": "MIT" + }, + "node_modules/@expo/config/node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@expo/devcert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz", + "integrity": "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==", + "license": "MIT", + "dependencies": { + "@expo/sudo-prompt": "^9.3.1", + "debug": "^3.1.0" + } + }, + "node_modules/@expo/devcert/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@expo/env": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.0.8.tgz", + "integrity": "sha512-5VQD6GT8HIMRaSaB5JFtOXuvfDVU80YtZIuUT/GDhUF782usIXY13Tn3IdDz1Tm/lqA9qnRZQ1BF4t7LlvdJPA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "getenv": "^2.0.0" + } + }, + "node_modules/@expo/image-utils": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.8.tgz", + "integrity": "sha512-HHHaG4J4nKjTtVa1GG9PCh763xlETScfEyNxxOvfTRr8IKPJckjTyqSLEtdJoFNJ1vqiABEjW7tqGhqGibZLeA==", + "license": "MIT", + "dependencies": { + "@expo/spawn-async": "^1.7.2", + "chalk": "^4.0.0", + "getenv": "^2.0.0", + "jimp-compact": "0.16.1", + "parse-png": "^2.1.0", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0", + "semver": "^7.6.0", + "temp-dir": "~2.0.0", + "unique-string": "~2.0.0" + } + }, + "node_modules/@expo/json-file": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", + "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/metro": { + "version": "54.2.0", + "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-54.2.0.tgz", + "integrity": "sha512-h68TNZPGsk6swMmLm9nRSnE2UXm48rWwgcbtAHVMikXvbxdS41NDHHeqg1rcQ9AbznDRp6SQVC2MVpDnsRKU1w==", + "license": "MIT", + "dependencies": { + "metro": "0.83.3", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-config": "0.83.3", + "metro-core": "0.83.3", + "metro-file-map": "0.83.3", + "metro-minify-terser": "0.83.3", + "metro-resolver": "0.83.3", + "metro-runtime": "0.83.3", + "metro-source-map": "0.83.3", + "metro-symbolicate": "0.83.3", + "metro-transform-plugins": "0.83.3", + "metro-transform-worker": "0.83.3" + } + }, + "node_modules/@expo/plist": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", + "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.2.3", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/@expo/prebuild-config": { + "version": "55.0.12-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-55.0.12-canary-20260328-2049187.tgz", + "integrity": "sha512-btOLRQh3a5bI1bKFWXd3JWfUFDp2TdNjy5crXJh1uBa0uXnw83ZDrcqrLZY0mMA1ocUN3ES61DamjwSMukDhGg==", + "license": "MIT", + "dependencies": { + "@expo/config": "55.0.12-canary-20260328-2049187", + "@expo/config-plugins": "55.0.8-canary-20260328-2049187", + "@expo/config-types": "55.0.6-canary-20260328-2049187", + "@expo/image-utils": "0.8.13-canary-20260328-2049187", + "@expo/json-file": "10.0.13-canary-20260328-2049187", + "@react-native/normalize-colors": "0.83.4", + "debug": "^4.3.1", + "resolve-from": "^5.0.0", + "semver": "^7.6.0", + "xml2js": "0.6.0" + }, + "peerDependencies": { + "expo": "55.0.10-canary-20260328-2049187" + } + }, + "node_modules/@expo/prebuild-config/node_modules/@expo/config": { + "version": "55.0.12-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-55.0.12-canary-20260328-2049187.tgz", + "integrity": "sha512-PV5QVwrxNBQ8vb3/wecKMLIuiU+Yx8pNRdDHU+5EAaykKIfvkLh6aHEJQCDwG3tMOHGgtTYs5jjtEoJoWWMQ+g==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "55.0.8-canary-20260328-2049187", + "@expo/config-types": "55.0.6-canary-20260328-2049187", + "@expo/json-file": "10.0.13-canary-20260328-2049187", + "@expo/require-utils": "55.0.4-canary-20260328-2049187", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4" + } + }, + "node_modules/@expo/prebuild-config/node_modules/@expo/config-plugins": { + "version": "55.0.8-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-55.0.8-canary-20260328-2049187.tgz", + "integrity": "sha512-FJ81ylIzcIXEIt2VHTr23YixsqVWOErwwYhpf0+mGv4Rrnqkae97fTROUjeQEcKlB2uIkfe/gqwA5grwSF0c5A==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "55.0.6-canary-20260328-2049187", + "@expo/json-file": "10.0.13-canary-20260328-2049187", + "@expo/plist": "0.5.3-canary-20260328-2049187", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/prebuild-config/node_modules/@expo/config-types": { + "version": "55.0.6-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-55.0.6-canary-20260328-2049187.tgz", + "integrity": "sha512-Pc+bPfbyHGrvcg70XnkHY1ffemjDcBzFn+y6/nsS5aZCrhehtSRX6jrxujyJSa0zRnPxXTBO646NVa/kGZ5UrQ==", + "license": "MIT" + }, + "node_modules/@expo/prebuild-config/node_modules/@expo/image-utils": { + "version": "0.8.13-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.13-canary-20260328-2049187.tgz", + "integrity": "sha512-p3AyR5fgcOOBRglKh7akw94IeY9DHrY2oPfhTMsNxlTsk1ShDlnpkOozlubwC9XXdPewG0RTuIhLmeyQ9kw77A==", + "license": "MIT", + "dependencies": { + "@expo/spawn-async": "^1.7.2", + "chalk": "^4.0.0", + "getenv": "^2.0.0", + "jimp-compact": "0.16.1", + "parse-png": "^2.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + } + }, + "node_modules/@expo/prebuild-config/node_modules/@expo/json-file": { + "version": "10.0.13-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.13-canary-20260328-2049187.tgz", + "integrity": "sha512-a1lKlVUu5QnKzC0RVCH9Fwwbx4W1g9g9Uw63gah3V+D+PGiXkOpIH3rMTMEnj3wesBcMj5JouBAoxFWnh5PLSw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/prebuild-config/node_modules/@expo/plist": { + "version": "0.5.3-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.5.3-canary-20260328-2049187.tgz", + "integrity": "sha512-2lyc4DpjRwz9yNcJn82pfC3AKarzJUt7fjPl/4qrn8KROPmq9xb4A2DBk7tgYCPKPUlBocEViVQ+zB4l9t2YFQ==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/@expo/prebuild-config/node_modules/@react-native/normalize-colors": { + "version": "0.83.4", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.83.4.tgz", + "integrity": "sha512-9ezxaHjxqTkTOLg62SGg7YhFaE+fxa/jlrWP0nwf7eGFHlGOiTAaRR2KUfiN3K05e+EMbEhgcH/c7bgaXeGyJw==", + "license": "MIT" + }, + "node_modules/@expo/require-utils": { + "version": "55.0.4-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-55.0.4-canary-20260328-2049187.tgz", + "integrity": "sha512-xjShWGciKtN5mOiiDABPrwaXlmfmhn7H5OSnoWN1D5u2SzfJomazGdez4KkBf65QjVCL3HY/oC6ErGqjzVKH+Q==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@expo/sdk-runtime-versions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz", + "integrity": "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==", + "license": "MIT" + }, + "node_modules/@expo/spawn-async": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz", + "integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@expo/sudo-prompt": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@expo/sudo-prompt/-/sudo-prompt-9.3.2.tgz", + "integrity": "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==", + "license": "MIT" + }, + "node_modules/@expo/vector-icons": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-15.1.1.tgz", + "integrity": "sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==", + "license": "MIT", + "peerDependencies": { + "expo-font": ">=14.0.4", + "react": "*", + "react-native": "*" + } + }, + "node_modules/@expo/ws-tunnel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-1.0.6.tgz", + "integrity": "sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q==", + "license": "MIT" + }, + "node_modules/@expo/xcpretty": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.1.tgz", + "integrity": "sha512-KZNxZvnGCtiM2aYYZ6Wz0Ix5r47dAvpNLApFtZWnSoERzAdOMzVBOPysBoM0JlF6FKWZ8GPqgn6qt3dV/8Zlpg==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "chalk": "^4.1.0", + "js-yaml": "^4.1.0" + }, + "bin": { + "excpretty": "build/cli.js" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "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", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "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.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz", + "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.120.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.120.0.tgz", + "integrity": "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/assets-registry": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz", + "integrity": "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w==", + "license": "MIT", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.81.5.tgz", + "integrity": "sha512-oF71cIH6je3fSLi6VPjjC3Sgyyn57JLHXs+mHWc9MoCiJJcM4nqsS5J38zv1XQ8d3zOW2JtHro+LF0tagj2bfQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@react-native/codegen": "0.81.5" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/babel-preset": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.81.5.tgz", + "integrity": "sha512-UoI/x/5tCmi+pZ3c1+Ypr1DaRMDLI3y+Q70pVLLVgrnC3DHsHRIbHcCHIeG/IJvoeFqFM2sTdhSOLJrf8lOPrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/template": "^7.25.0", + "@react-native/babel-plugin-codegen": "0.81.5", + "babel-plugin-syntax-hermes-parser": "0.29.1", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/babel-preset/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.81.5.tgz", + "integrity": "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.25.3", + "glob": "^7.1.1", + "hermes-parser": "0.29.1", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen/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==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@react-native/codegen/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", + "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/@react-native/codegen/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/@react-native/codegen/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "node_modules/@react-native/codegen/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.81.5.tgz", + "integrity": "sha512-yWRlmEOtcyvSZ4+OvqPabt+NS36vg0K/WADTQLhrYrm9qdZSuXmq8PmdJWz/68wAqKQ+4KTILiq2kjRQwnyhQw==", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.81.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.83.1", + "metro-config": "^0.83.1", + "metro-core": "^0.83.1", + "semver": "^7.1.3" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "*" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.81.5.tgz", + "integrity": "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.81.5.tgz", + "integrity": "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA==", + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.81.5", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^6.2.3" + }, + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.81.5.tgz", + "integrity": "sha512-hORRlNBj+ReNMLo9jme3yQ6JQf4GZpVEBLxmTXGGlIL78MAezDZr5/uq9dwElSbcGmLEgeiax6e174Fie6qPLg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.81.5.tgz", + "integrity": "sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w==", + "license": "MIT", + "engines": { + "node": ">= 20.19.4" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.74.89", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.89.tgz", + "integrity": "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==", + "license": "MIT" + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.81.5.tgz", + "integrity": "sha512-UVXgV/db25OPIvwZySeToXD/9sKKhOdkcWmmf4Jh8iBZuyfML+/5CasaZ1E7Lqg6g3uqVQq75NqIwkYmORJMPw==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@types/react": "^19.1.0", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.15.9", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.15.9.tgz", + "integrity": "sha512-Ou28A1aZLj5wiFQ3F93aIsrI4NCwn3IJzkkjNo9KLFXsc0Yks+UqrVaFlffHFLsrbajuGRG/OQpnMA1ljayY5Q==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.9.14", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0" + }, + "peerDependencies": { + "@react-navigation/native": "^7.2.2", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/bottom-tabs/node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/@react-navigation/core": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.17.2.tgz", + "integrity": "sha512-Rt2OZwcgOmjv401uLGAKaRM6xo0fiBce/A7LfRHI1oe5FV+KooWcgAoZ2XOtgKj6UzVMuQWt3b2e6rxo/mDJRA==", + "license": "MIT", + "dependencies": { + "@react-navigation/routers": "^7.5.3", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "query-string": "^7.1.3", + "react-is": "^19.1.0", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "react": ">= 18.2.0" + } + }, + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz", + "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==", + "license": "MIT" + }, + "node_modules/@react-navigation/elements": { + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.14.tgz", + "integrity": "sha512-lKqzu+su2pI/YIZmR7L7xdOs4UL+rVXKJAMpRMBrwInEy96SjIFst6QDGpE89Dunnu3VjVpjWfByo9f2GWBHDQ==", + "license": "MIT", + "dependencies": { + "color": "^4.2.3", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.2.2", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/elements/node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/@react-navigation/native": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.2.2.tgz", + "integrity": "sha512-kem1Ko2BcbAjmbQIv66dNmr6EtfDut3QU0qjsVhMnLLhktwyXb6FzZYp8gTrUb6AvkAbaJoi+BF5Pl55pAUa5w==", + "license": "MIT", + "dependencies": { + "@react-navigation/core": "^7.17.2", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "use-latest-callback": "^0.2.4" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*" + } + }, + "node_modules/@react-navigation/routers": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz", + "integrity": "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==", + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.10.tgz", + "integrity": "sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.10.tgz", + "integrity": "sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.10.tgz", + "integrity": "sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.10.tgz", + "integrity": "sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.10.tgz", + "integrity": "sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.10.tgz", + "integrity": "sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.10.tgz", + "integrity": "sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.10.tgz", + "integrity": "sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.10.tgz", + "integrity": "sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.10.tgz", + "integrity": "sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.10.tgz", + "integrity": "sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.10.tgz", + "integrity": "sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/commons/node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react-native": { + "version": "13.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-13.3.3.tgz", + "integrity": "sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-matcher-utils": "^30.0.5", + "picocolors": "^1.1.1", + "pretty-format": "^30.0.5", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "jest": ">=29.0.0", + "react": ">=18.2.0", + "react-native": ">=0.71", + "react-test-renderer": ">=18.2.0" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/chai/node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT" + }, + "node_modules/@types/vscode": { + "version": "1.108.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.108.1.tgz", + "integrity": "sha512-DerV0BbSzt87TbrqmZ7lRDIYaMiqvP8tmJTzW2p49ZBVtGUnGAu2RGQd1Wv4XMzEVUpaHbsemVM5nfuQJj7H6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@urql/core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz", + "integrity": "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.13", + "wonka": "^6.3.2" + } + }, + "node_modules/@urql/exchange-retry": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@urql/exchange-retry/-/exchange-retry-1.3.2.tgz", + "integrity": "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg==", + "license": "MIT", + "dependencies": { + "@urql/core": "^5.1.2", + "wonka": "^6.3.2" + }, + "peerDependencies": { + "@urql/core": "^5.0.0" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.0.tgz", + "integrity": "sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.0", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.0", + "vitest": "4.1.0" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/coverage-v8/node_modules/std-env": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", + "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.0.tgz", + "integrity": "sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.0", + "@vitest/utils": "4.1.0", + "chai": "^6.2.2", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.0.tgz", + "integrity": "sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.0", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.0.tgz", + "integrity": "sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.0", + "@vitest/utils": "4.1.0", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz", + "integrity": "sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.0.tgz", + "integrity": "sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.0.tgz", + "integrity": "sha512-sTSDtVM1GOevRGsCNhp1mBUHKo9Qlc55+HCreFT4fe99AHxl1QQNXSL3uj4Pkjh5yEuWZIx8E2tVC94nnBZECQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.0", + "fflate": "^0.8.2", + "flatted": "3.4.0", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.1.0" + } + }, + "node_modules/@vitest/ui/node_modules/flatted": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.0.tgz", + "integrity": "sha512-kC6Bb+ooptOIvWj5B63EQWkF0FEnNjV2ZNkLMLZRDDduIiWeFF4iKnslwhiWxjAdbg4NzTNo6h0qLuvFrcx+Sw==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitest/utils": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.0.tgz", + "integrity": "sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.0", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz", + "integrity": "sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", + "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "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/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", + "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", + "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.6", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", + "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.6" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/babel-plugin-react-native-web": { + "version": "0.19.13", + "resolved": "https://registry.npmjs.org/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.19.13.tgz", + "integrity": "sha512-4hHoto6xaN23LCyZgL9LJZc3olmAxd7b6jDzlZnKXAh4rRAbZRKNBJoOOdp46OBqgy+K0t0guTj5/mhA8inymQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.29.1.tgz", + "integrity": "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA==", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.29.1" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", + "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-expo": { + "version": "54.0.10", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-54.0.10.tgz", + "integrity": "sha512-wTt7POavLFypLcPW/uC5v8y+mtQKDJiyGLzYCjqr9tx0Qc3vCXcDKk1iCFIj/++Iy5CWhhTflEa7VvVPNWeCfw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/preset-react": "^7.22.15", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-preset": "0.81.5", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.0", + "babel-plugin-syntax-hermes-parser": "^0.29.1", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + } + } + }, + "node_modules/babel-preset-expo/node_modules/babel-plugin-react-native-web": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.21.2.tgz", + "integrity": "sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==", + "license": "MIT" + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/better-opn/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bplist-creator": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", + "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", + "license": "MIT", + "dependencies": { + "stream-buffers": "2.2.x" + } + }, + "node_modules/bplist-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", + "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "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.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001780", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz", + "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==", + "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/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", + "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/codelink-extension": { + "resolved": "packages/vscode-extension", + "link": true + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-js-compat": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", + "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-in-js-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", + "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==", + "license": "MIT", + "dependencies": { + "hyphenate-style-name": "^1.0.3" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.283", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.283.tgz", + "integrity": "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz", + "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-editor": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", + "integrity": "sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "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-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "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", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "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/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/expo-constants": { + "version": "18.0.13", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz", + "integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==", + "license": "MIT", + "dependencies": { + "@expo/config": "~12.0.13", + "@expo/env": "~2.0.8" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-linear-gradient": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-13.0.2.tgz", + "integrity": "sha512-EDcILUjRKu4P1rtWcwciN6CSyGtH7Bq4ll3oTRV7h3h8oSzSilH1g6z7kTAMlacPBKvMnkkWOGzW6KtgMKEiTg==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-modules-core": { + "version": "3.0.29", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.29.tgz", + "integrity": "sha512-LzipcjGqk8gvkrOUf7O2mejNWugPkf3lmd9GkqL9WuNyeN2fRwU0Dn77e3ZUKI3k6sI+DNwjkq4Nu9fNN9WS7Q==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-splash-screen": { + "version": "55.0.14-canary-20260328-2049187", + "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-55.0.14-canary-20260328-2049187.tgz", + "integrity": "sha512-p3XlISAt4lUZDD28J8ctYVw0ThD3Nze3XD1I2pr8HrUb90io43xT7Yj0cJaqHcax93dYLxUrNh+PCC122dCL4Q==", + "license": "MIT", + "dependencies": { + "@expo/prebuild-config": "55.0.12-canary-20260328-2049187" + }, + "peerDependencies": { + "expo": "55.0.10-canary-20260328-2049187" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "license": "Apache-2.0" + }, + "node_modules/fast-check": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.6.0.tgz", + "integrity": "sha512-h7H6Dm0Fy+H4ciQYFxFjXnXkzR2kr9Fb22c0UBpHnm59K2zpr2t13aPTHlltFiNT6zuxp6HMPAVVvgur4BLdpA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^8.0.0" + }, + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fbjs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", + "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", + "license": "MIT", + "dependencies": { + "cross-fetch": "^3.1.5", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^1.0.35" + } + }, + "node_modules/fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "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.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT" + }, + "node_modules/fontfaceobserver": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", + "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==", + "license": "BSD-2-Clause" + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/freeport-async": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz", + "integrity": "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/getenv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", + "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", + "license": "BSD-3-Clause" + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/inline-style-prefixer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz", + "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==", + "license": "MIT", + "dependencies": { + "css-in-js-utils": "^3.1.0" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "license": "MIT", "dependencies": { - "debug": "^4.1.1" + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "node_modules/jimp-compact": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz", + "integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==", "license": "MIT" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "argparse": "^2.0.1" }, - "engines": { - "node": ">= 8" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD" + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dev": true, "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, "engines": { - "node": ">= 8" + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.2.tgz", - "integrity": "sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==", - "cpu": [ - "arm" - ], + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.2.tgz", - "integrity": "sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.2.tgz", - "integrity": "sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==", - "cpu": [ - "arm64" - ], + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "json-buffer": "3.0.1" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.2.tgz", - "integrity": "sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "engines": { + "node": ">=6" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.2.tgz", - "integrity": "sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": ">=6" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.2.tgz", - "integrity": "sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==", - "cpu": [ - "x64" - ], + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.2.tgz", - "integrity": "sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.2.tgz", - "integrity": "sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "ms": "2.0.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.2.tgz", - "integrity": "sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.2.tgz", - "integrity": "sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", "cpu": [ "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.2.tgz", - "integrity": "sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.2.tgz", - "integrity": "sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==", - "cpu": [ - "loong64" + "android" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.2.tgz", - "integrity": "sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", "cpu": [ - "ppc64" + "arm64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" - ] + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.2.tgz", - "integrity": "sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==", + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", "cpu": [ - "ppc64" + "x64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" - ] + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.2.tgz", - "integrity": "sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==", + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", "cpu": [ - "riscv64" + "x64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" - ] + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.2.tgz", - "integrity": "sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", "cpu": [ - "riscv64" + "arm" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.2.tgz", - "integrity": "sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", "cpu": [ - "s390x" + "arm64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.2.tgz", - "integrity": "sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", "cpu": [ - "x64" + "arm64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.2.tgz", - "integrity": "sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", "cpu": [ "x64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.2.tgz", - "integrity": "sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", "cpu": [ "x64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.2.tgz", - "integrity": "sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==", - "cpu": [ - "arm64" + "linux" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.2.tgz", - "integrity": "sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", "cpu": [ "arm64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.2.tgz", - "integrity": "sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==", - "cpu": [ - "ia32" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.2.tgz", - "integrity": "sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", "cpu": [ "x64" ], - "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.2.tgz", - "integrity": "sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==", - "cpu": [ - "x64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" + "p-locate": "^5.0.0" }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@testing-library/dom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT", - "peer": true + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" }, - "node_modules/@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "picocolors": "^1.1.1", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - } + "license": "MIT" }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", "license": "MIT" }, - "node_modules/@testing-library/react": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", - "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", - "dev": true, + "node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0 || ^19.0.0", - "@types/react-dom": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "chalk": "^2.0.1" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, + "node_modules/log-symbols/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "node_modules/log-symbols/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "license": "MIT", "dependencies": { - "@types/node": "*" + "color-name": "1.1.3" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "license": "MIT" }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" + "node_modules/log-symbols/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, - "node_modules/@types/node": { - "version": "20.19.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", - "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "node_modules/log-symbols/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "license": "MIT" + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } }, - "node_modules/@types/react": { - "version": "18.3.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "node_modules/magicast": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", "dev": true, "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/vscode": { - "version": "1.108.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.108.1.tgz", - "integrity": "sha512-DerV0BbSzt87TbrqmZ7lRDIYaMiqvP8tmJTzW2p49ZBVtGUnGAu2RGQd1Wv4XMzEVUpaHbsemVM5nfuQJj7H6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "semver": "^7.5.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "tmpl": "1.0.5" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "license": "Apache-2.0" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 0.4" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dev": true, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "is-plain-obj": "^2.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 8" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/metro": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz", + "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" + "@babel/code-frame": "^7.24.7", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "@babel/types": "^7.25.2", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.32.0", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-config": "0.83.3", + "metro-core": "0.83.3", + "metro-file-map": "0.83.3", + "metro-resolver": "0.83.3", + "metro-runtime": "0.83.3", + "metro-source-map": "0.83.3", + "metro-symbolicate": "0.83.3", + "metro-transform-plugins": "0.83.3", + "metro-transform-worker": "0.83.3", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "bin": { + "metro": "src/cli.js" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz", + "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.32.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" } }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", - "dev": true, + "node_modules/metro-cache": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz", + "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==", "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.83.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=20.19.4" + } + }, + "node_modules/metro-cache-key": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.3.tgz", + "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "engines": { + "node": ">=20.19.4" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dev": true, + "node_modules/metro-config": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.3.tgz", + "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.83.3", + "metro-cache": "0.83.3", + "metro-core": "0.83.3", + "metro-runtime": "0.83.3", + "yaml": "^2.6.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=20.19.4" + } + }, + "node_modules/metro-config/node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/eemeli" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, + "node_modules/metro-core": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.3.tgz", + "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==", "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" + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.83.3" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "node": ">=20.19.4" } }, - "node_modules/@vitest/expect": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", - "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", - "dev": true, + "node_modules/metro-file-map": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.3.tgz", + "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==", "license": "MIT", "dependencies": { - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "chai": "^4.3.10" + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.19.4" } }, - "node_modules/@vitest/runner": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", - "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", - "dev": true, + "node_modules/metro-minify-terser": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz", + "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==", "license": "MIT", "dependencies": { - "@vitest/utils": "1.6.1", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.19.4" } }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", - "dev": true, + "node_modules/metro-resolver": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.3.tgz", + "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==", "license": "MIT", "dependencies": { - "yocto-queue": "^1.0.0" + "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=20.19.4" } }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "dev": true, + "node_modules/metro-runtime": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.3.tgz", + "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==", "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, "engines": { - "node": ">=12.20" + "node": ">=20.19.4" + } + }, + "node_modules/metro-source-map": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.3.tgz", + "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.83.3", + "nullthrows": "^1.1.1", + "ob1": "0.83.3", + "source-map": "^0.5.6", + "vlq": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=20.19.4" } }, - "node_modules/@vitest/snapshot": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", - "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", - "dev": true, + "node_modules/metro-symbolicate": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz", + "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==", "license": "MIT", "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.83.3", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=20.19.4" } }, - "node_modules/@vitest/spy": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", - "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", - "dev": true, + "node_modules/metro-transform-plugins": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz", + "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==", "license": "MIT", "dependencies": { - "tinyspy": "^2.2.0" + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.19.4" } }, - "node_modules/@vitest/ui": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-1.6.1.tgz", - "integrity": "sha512-xa57bCPGuzEFqGjPs3vVLyqareG8DX0uMkr5U/v5vLv5/ZUrBrPL7gzxzTJedEyZxFMfsozwTIbbYfEQVo3kgg==", - "dev": true, + "node_modules/metro-transform-worker": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz", + "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==", "license": "MIT", "dependencies": { - "@vitest/utils": "1.6.1", - "fast-glob": "^3.3.2", - "fflate": "^0.8.1", - "flatted": "^3.2.9", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "sirv": "^2.0.4" + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "metro": "0.83.3", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-minify-terser": "0.83.3", + "metro-source-map": "0.83.3", + "metro-transform-plugins": "0.83.3", + "nullthrows": "^1.1.1" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/metro/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" }, "peerDependencies": { - "vitest": "1.6.1" + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/@vitest/utils": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", - "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", - "dev": true, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=0.4.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "license": "MIT", "dependencies": { - "acorn": "^8.11.0" + "minipass": "^7.1.2" }, "engines": { - "node": ">=0.4.0" + "node": ">= 18" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, "engines": { - "node": ">= 14" + "node": ">=10" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "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" + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/nested-error-stacks": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz", + "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "whatwg-url": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "4.x || >=6.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-forge": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { - "node": ">= 8" + "node": ">= 6.13.0" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "license": "MIT" }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" - } + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, + "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==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "license": "MIT", + "node_modules/npm-package-arg": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, "engines": { - "node": "*" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", "license": "MIT" }, - "node_modules/autoprefixer": { - "version": "10.4.23", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", - "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", "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" + }, + "node_modules/ob1": { + "version": "0.83.3", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.3.tgz", + "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==", "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" + "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=20.19.4" } }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, "engines": { - "node": ">=10", - "npm": ">=6" + "node": ">=0.10.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT" }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": "^4.5.0 || >= 5.9" + "node": ">= 0.8" } }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.16", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.16.tgz", - "integrity": "sha512-KeUZdBuxngy825i8xvzaK1Ncnkx0tBmb3k8DkEuqjKRkmtvNTjey2ZsNeh8Dw4lfKvbCOu9oeNx2TKm2vHqcRw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "node_modules/bidi-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", - "dev": true, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", "license": "MIT", "dependencies": { - "require-from-string": "^2.0.2" + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, "engines": { "node": ">=8" }, @@ -2510,1254 +8947,1173 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "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/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, + "node_modules/ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/ora/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=6" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, + "node_modules/ora/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, + "node_modules/ora/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">= 0.4" + "node": ">=4" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/ora/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "color-name": "1.1.3" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/ora/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=0.8.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001765", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", - "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, + "node_modules/ora/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, "engines": { "node": ">=4" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/ora/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-regex": "^4.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=6" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, + "node_modules/ora/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "license": "MIT", "dependencies": { - "get-func-name": "^2.0.2" + "has-flag": "^3.0.0" }, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">= 8.10.0" + "node": ">=10" }, "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "license": "MIT" - }, - "node_modules/codelink-extension": { - "resolved": "packages/vscode-extension", - "link": true + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "callsites": "^3.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=6" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, + "node_modules/parse-png": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-png/-/parse-png-2.1.0.tgz", + "integrity": "sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==", "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "pngjs": "^3.3.0" }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 6" + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "license": "MIT", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "license": "MIT", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "license": "BlueOak-1.0.0", "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=4" + "node": "20 || >=22" } }, - "node_modules/cssstyle": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/cssstyle/node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dev": true, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", "engines": { - "node": ">=18" + "node": ">= 6" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=10.4.0" } }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" + "node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "type-detect": "^4.0.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=6" + "node": "^10 || ^12 || >=14" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">= 0.8.0" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, "engines": { - "node": ">=6" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/diff": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", - "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { - "path-type": "^4.0.0" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT", - "peer": true + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=0.4.0" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, - "license": "ISC" - }, - "node_modules/engine.io": { - "version": "6.6.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz", - "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==", + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "license": "MIT", "dependencies": { - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.7.2", - "cors": "~2.8.5", - "debug": "~4.4.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.18.3" - }, - "engines": { - "node": ">=10.2.0" + "asap": "~2.0.3" } }, - "node_modules/engine.io-client": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", - "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "license": "MIT", "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.18.3", - "xmlhttprequest-ssl": "~2.1.1" + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=6" } }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "node_modules/pure-rand": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.3.0.tgz", + "integrity": "sha512-1ws1Ab8fnsf4bvpL+SujgBnr3KFs5abgCLVzavBp+f2n8Ld5YTOZlkv/ccYPhu3X9s+MEeqPRMqKlJz/kWDK8A==", "dev": true, - "license": "BSD-2-Clause", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qrcode-terminal": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", + "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/query-string": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, "engines": { - "node": ">=0.12" + "node": ">=6" }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", "license": "MIT", "dependencies": { - "is-arrayish": "^0.2.1" + "inherits": "~2.0.3" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } + "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/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">= 0.6" } }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { - "es-errors": "^1.3.0" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, - "engines": { - "node": ">= 0.4" + "bin": { + "rc": "cli.js" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "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": ">=0.10.0" } }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "loose-envify": "^1.1.0" }, "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": ">=0.10.0" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, + "node_modules/react-devtools-core": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", + "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/react-devtools-core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8.3.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { - "@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" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "react": "^18.3.1" } }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { - "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" + "loose-envify": "^1.1.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", + "node_modules/react-freeze": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", + "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==", + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "react": ">=17.0.0" } }, - "node_modules/eslint/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", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" }, - "node_modules/eslint/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", - "dependencies": { - "brace-expansion": "^1.1.7" + "node_modules/react-native": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz", + "integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==", + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.7.0", + "@react-native/assets-registry": "0.81.5", + "@react-native/codegen": "0.81.5", + "@react-native/community-cli-plugin": "0.81.5", + "@react-native/gradle-plugin": "0.81.5", + "@react-native/js-polyfills": "0.81.5", + "@react-native/normalize-colors": "0.81.5", + "@react-native/virtualized-lists": "0.81.5", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-jest": "^29.7.0", + "babel-plugin-syntax-hermes-parser": "0.29.1", + "base64-js": "^1.5.1", + "commander": "^12.0.0", + "flow-enums-runtime": "^0.0.6", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jest-environment-node": "^29.7.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.83.1", + "metro-source-map": "^0.83.1", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.5", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.26.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.3", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" }, "engines": { - "node": "*" + "node": ">= 20.19.4" + }, + "peerDependencies": { + "@types/react": "^19.1.0", + "react": "^19.1.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/react-native-screens": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.24.0.tgz", + "integrity": "sha512-SyoiGaDofiyGPFrUkn1oGsAzkRuX1JUvTD9YQQK3G1JGQ5VWkvHgYSsc1K9OrLsDQxN7NmV71O0sHCAh8cBetA==", + "license": "MIT", "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" + "react-freeze": "^1.0.0", + "warn-once": "^0.1.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "react": "*", + "react-native": "*" } }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/react-native-web": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz", + "integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==", + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "@babel/runtime": "^7.18.6", + "@react-native/normalize-colors": "^0.74.1", + "fbjs": "^3.0.4", + "inline-style-prefixer": "^7.0.1", + "memoize-one": "^6.0.0", + "nullthrows": "^1.1.1", + "postcss-value-parser": "^4.2.0", + "styleq": "^0.1.3" }, - "engines": { - "node": ">=0.10" + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/react-native/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=4.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/react-native/node_modules/@react-native/normalize-colors": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", + "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", + "license": "MIT" + }, + "node_modules/react-native/node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT" + }, + "node_modules/react-native/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", "engines": { - "node": ">=4.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, + }, + "node_modules/react-native/node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/react-native/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", + "node_modules/react-native/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" + "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": ">=16.17" + "node": "*" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fast-check": { - "version": "3.23.2", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", - "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", + "node_modules/react-native/node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, + "node_modules/react-native/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", "dependencies": { - "pure-rand": "^6.1.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8.0.0" + "node": "*" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, + "node_modules/react-native/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "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" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=8.6.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", + "node_modules/react-native/node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" + "asap": "~2.0.6" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" + "node_modules/react-native/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" + "node_modules/react-native/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "reusify": "^1.0.4" + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "node_modules/react-test-renderer": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/react-test-renderer/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "loose-envify": "^1.1.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "license": "MIT" }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "regenerate": "^1.4.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=4" } }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "license": "MIT", + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "license": "BSD-2-Clause", "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" + "jsesc": "~3.1.0" }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" + "node": ">=0.10.0" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" + "node_modules/requireg": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/requireg/-/requireg-0.2.2.tgz", + "integrity": "sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==", + "dependencies": { + "nested-error-stacks": "~2.0.1", + "rc": "~1.2.7", + "resolve": "~1.7.1" + }, + "engines": { + "node": ">= 4.0.0" + } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, + "node_modules/requireg/node_modules/resolve": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", + "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "dependencies": { + "path-parse": "^1.0.5" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, + "node_modules/resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", "license": "MIT", + "dependencies": { + "global-dirs": "^0.1.1" + }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, + "node_modules/resolve-workspace-root": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/resolve-workspace-root/-/resolve-workspace-root-2.0.1.tgz", + "integrity": "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==", + "license": "MIT" + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "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": ">=10" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=4" } }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob": { + "node_modules/rimraf/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==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -3774,35 +10130,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/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", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/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, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -3811,270 +10142,339 @@ "node": "*" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/rolldown": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.10.tgz", + "integrity": "sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==", "dev": true, "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "@oxc-project/types": "=0.120.0", + "@rolldown/pluginutils": "1.0.0-rc.10" + }, + "bin": { + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.10", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.10", + "@rolldown/binding-darwin-x64": "1.0.0-rc.10", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.10", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.10", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.10", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.10", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.10", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.10", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.10", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.10", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.10" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.10.tgz", + "integrity": "sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg==", + "dev": true, + "license": "MIT" }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "@types/estree": "1.0.8" }, - "engines": { - "node": ">=10" + "bin": { + "rollup": "dist/bin/rollup" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "dev": true, "license": "MIT" }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=11.0.0" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "has-symbols": "^1.0.3" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=v12.22.7" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.4" + "node": ">=10" } }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "license": "MIT", "dependencies": { - "whatwg-encoding": "^3.1.1" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" }, "engines": { - "node": ">=18" + "node": ">= 0.8.0" } }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" + "ms": "2.0.0" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", + "node_modules/send/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { - "node": ">=16.17.0" + "node": ">= 0.8" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, + "node_modules/send/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { - "node": ">= 4" + "node": ">= 0.8" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, "engines": { - "node": ">=0.8.19" + "node": ">= 0.8.0" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" + "node_modules/sf-symbols-typescript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz", + "integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, "engines": { "node": ">= 0.4" }, @@ -4082,924 +10482,919 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/simple-git": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.33.0.tgz", + "integrity": "sha512-D4V/tGC2sjsoNhoMybKyGoE+v8A60hRawKQ1iFRA1zwuDgGZCBJ4ByOzZ5J8joBbi4Oam0qiPH+GhzmSBwbJng==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "node_modules/simple-plist": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", + "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" + "bplist-creator": "0.1.0", + "bplist-parser": "0.3.1", + "plist": "^3.0.5" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", "license": "MIT", - "engines": { - "node": ">=0.12.0" + "dependencies": { + "is-arrayish": "^0.3.1" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "dev": true, "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, - "node_modules/is-stream": { + "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "node_modules/socket.io": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=10.2.0" } }, - "node_modules/jsdom": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.2.0.tgz", - "integrity": "sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==", - "dev": true, + "node_modules/socket.io-adapter": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz", + "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.18.3" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", - "dependencies": { - "@asamuzakjp/dom-selector": "^2.0.1", - "cssstyle": "^4.0.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.4.3", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "is-potential-custom-element-name": "^1.0.1", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.3", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0", - "ws": "^8.16.0", - "xml-name-validator": "^5.0.0" - }, "engines": { - "node": ">=18" + "node": ">=10.0.0" }, "peerDependencies": { - "canvas": "^2.11.2" + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { - "canvas": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { "optional": true } } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/socket.io-client": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" }, "engines": { - "node": ">=6" + "node": ">=10.0.0" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, + "node_modules/socket.io-parser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz", + "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" }, "engines": { - "node": ">=6" + "node": ">=10.0.0" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", "license": "MIT", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" + "node": ">=6" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" }, - "node_modules/local-pkg": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", - "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", - "dev": true, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "license": "MIT", "dependencies": { - "mlly": "^1.7.3", - "pkg-types": "^1.2.1" + "escape-string-regexp": "^2.0.0" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "node": ">=10" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, "license": "MIT" }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", "license": "MIT", "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" + "type-fest": "^0.7.1" }, - "bin": { - "loose-envify": "cli.js" + "engines": { + "node": ">=6" } }, - "node_modules/loose-envify/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" + "engines": { + "node": ">= 0.6" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" + "license": "MIT" + }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", "license": "MIT", - "peer": true, - "bin": { - "lz-string": "bin/bin.js" + "engines": { + "node": ">=4" } }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", - "license": "MIT" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, + "node_modules/structured-headers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz", + "integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==", + "license": "MIT" + }, + "node_modules/styleq": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz", + "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==", + "license": "MIT" + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "license": "MIT", "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=8.6" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true, + "license": "MIT" + }, + "node_modules/tar": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", + "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", - "dev": true, - "license": "MIT", + "node_modules/terser": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "license": "BSD-2-Clause", "dependencies": { + "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.1" + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" } }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "dev": true, - "license": "MIT", + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, + "node_modules/test-exclude/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==", "license": "MIT", "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "node_modules/test-exclude/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", + "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": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">= 0.6" + "node": "*" } }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, "license": "MIT" }, - "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, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "any-promise": "^1.0.0" } }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "license": "MIT", "dependencies": { - "path-key": "^4.0.0" + "thenify": ">= 3.1.0 < 4" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8" } }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT" }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" + "node": ">=18" } }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "license": "MIT", "dependencies": { - "mimic-fn": "^4.0.0" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=12" + "node": ">=12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", "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": ">=14.0.0" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" + "tldts-core": "^6.1.86" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "tldts": "bin/cli.js" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", "dev": true, + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "is-number": "^7.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.0" } }, - "node_modules/parent-module": { + "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">=0.6" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "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": ">=6" } }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "entities": "^6.0.0" + "tldts": "^6.1.32" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=8" + "node": ">=16" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "dev": true, "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "license": "MIT", - "engines": { - "node": ">=8" - } + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, - "license": "MIT" + "license": "0BSD", + "optional": true }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, "engines": { - "node": "*" + "node": ">= 0.8.0" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "MIT", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=8.6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" + "node": ">=14.17" } }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, + "node_modules/ua-parser-js": { + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", + "integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==", "funding": [ { "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://opencollective.com/ua-parser-js" }, { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "type": "paypal", + "url": "https://paypal.me/faisalman" }, { "type": "github", - "url": "https://github.com/sponsors/ai" + "url": "https://github.com/sponsors/faisalman" } ], "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/undici": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=4" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" + "node": ">=4" } }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", "license": "MIT", "dependencies": { - "camelcase-css": "^2.0.1" + "crypto-random-string": "^2.0.0" }, "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" + "node": ">=8" } }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" }, { "type": "github", @@ -5008,812 +11403,1244 @@ ], "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.1.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, - "engines": { - "node": ">=12.0" + "bin": { + "update-browserslist-db": "cli.js" }, "peerDependencies": { - "postcss": "^8.2.14" + "browserslist": ">= 4.21.0" } }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "punycode": "^2.1.0" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" + "node_modules/use-latest-callback": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz", + "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4.0" } }, - "node_modules/prettier": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.0.tgz", - "integrity": "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==", - "dev": true, + "node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", "license": "MIT", "bin": { - "prettier": "bin/prettier.cjs" - }, + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "license": "ISC", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 0.8" } }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", + "node_modules/vitest": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.0.tgz", + "integrity": "sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.0", + "@vitest/mocker": "4.1.0", + "@vitest/pretty-format": "4.1.0", + "@vitest/runner": "4.1.0", + "@vitest/snapshot": "4.1.0", + "@vitest/spy": "4.1.0", + "@vitest/utils": "4.1.0", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, "engines": { - "node": ">=10" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.0", + "@vitest/browser-preview": "4.1.0", + "@vitest/browser-webdriverio": "4.1.0", + "@vitest/ui": "4.1.0", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } } }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.0.tgz", + "integrity": "sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==", "dev": true, "license": "MIT", "dependencies": { - "punycode": "^2.3.1" + "@vitest/spy": "4.1.0", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" }, "funding": { - "url": "https://github.com/sponsors/lupomontero" + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/vitest/node_modules/@vitest/pretty-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz", + "integrity": "sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "node_modules/vitest/node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], "license": "MIT" }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "node_modules/vitest/node_modules/std-env": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", + "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", "dev": true, "license": "MIT" }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "node_modules/vitest/node_modules/vite": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.1.tgz", + "integrity": "sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.10", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "sass": { + "optional": true }, - { - "type": "consulting", - "url": "https://feross.org/support" + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } - ], + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", "license": "MIT" }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0" + "xml-name-validator": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/react-diff-viewer-continued": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/react-diff-viewer-continued/-/react-diff-viewer-continued-3.4.0.tgz", - "integrity": "sha512-kMZmUyb3Pv5L9vUtCfIGYsdOHs8mUojblGy1U1Sm0D7FhAOEsH9QhnngEIRo5hXWIPNGupNRJls1TJ6Eqx84eg==", - "license": "MIT", + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", "dependencies": { - "@emotion/css": "^11.11.2", - "classnames": "^2.3.2", - "diff": "^5.1.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">= 8" - }, - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + "makeerror": "1.0.12" } }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", + "license": "MIT" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" + "defaults": "^1.0.3" } }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, - "license": "MIT" + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", "dev": true, "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "license": "MIT", - "dependencies": { - "pify": "^2.3.0" + "engines": { + "node": ">=18" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", "dev": true, "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=8.10.0" + "node": ">=18" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, + "node_modules/whatwg-url-without-unicode": { + "version": "8.0.0-3", + "resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz", + "integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==", "license": "MIT", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "buffer": "^5.4.3", + "punycode": "^2.1.1", + "webidl-conversions": "^5.0.0" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/whatwg-url-without-unicode/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "license": "BSD-2-Clause", "engines": { "node": ">=8" } }, - "node_modules/require-from-string": { + "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "siginfo": "^2.0.0", + "stackback": "0.0.2" }, "bin": { - "resolve": "bin/resolve" + "why-is-node-running": "cli.js" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "license": "MIT", - "engines": { - "node": ">=4" - } + "node_modules/wonka": { + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.6.tgz", + "integrity": "sha512-MXH+6mDHAZ2GuMpgKS055FR6v0xVP3XwquxIMYXgiW+FejHQlMGlvVRZT4qMCxR+bEo/FCtIdKxwej9WV3YQag==", + "license": "MIT" }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { - "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/rollup": { - "version": "4.55.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.2.tgz", - "integrity": "sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==", - "dev": true, - "license": "MIT", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "license": "ISC", "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.2", - "@rollup/rollup-android-arm64": "4.55.2", - "@rollup/rollup-darwin-arm64": "4.55.2", - "@rollup/rollup-darwin-x64": "4.55.2", - "@rollup/rollup-freebsd-arm64": "4.55.2", - "@rollup/rollup-freebsd-x64": "4.55.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.2", - "@rollup/rollup-linux-arm-musleabihf": "4.55.2", - "@rollup/rollup-linux-arm64-gnu": "4.55.2", - "@rollup/rollup-linux-arm64-musl": "4.55.2", - "@rollup/rollup-linux-loong64-gnu": "4.55.2", - "@rollup/rollup-linux-loong64-musl": "4.55.2", - "@rollup/rollup-linux-ppc64-gnu": "4.55.2", - "@rollup/rollup-linux-ppc64-musl": "4.55.2", - "@rollup/rollup-linux-riscv64-gnu": "4.55.2", - "@rollup/rollup-linux-riscv64-musl": "4.55.2", - "@rollup/rollup-linux-s390x-gnu": "4.55.2", - "@rollup/rollup-linux-x64-gnu": "4.55.2", - "@rollup/rollup-linux-x64-musl": "4.55.2", - "@rollup/rollup-openbsd-x64": "4.55.2", - "@rollup/rollup-openharmony-arm64": "4.55.2", - "@rollup/rollup-win32-arm64-msvc": "4.55.2", - "@rollup/rollup-win32-ia32-msvc": "4.55.2", - "@rollup/rollup-win32-x64-gnu": "4.55.2", - "@rollup/rollup-win32-x64-msvc": "4.55.2", - "fsevents": "~2.3.2" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true }, - { - "type": "consulting", - "url": "https://feross.org/support" + "utf-8-validate": { + "optional": true } - ], - "license": "MIT", + } + }, + "node_modules/xcode": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", + "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", + "license": "Apache-2.0", "dependencies": { - "queue-microtask": "^1.2.2" + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + }, + "engines": { + "node": ">=10.0.0" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", + "node_modules/xml2js": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz", + "integrity": "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==", + "license": "MIT", "dependencies": { - "xmlchars": "^2.2.0" + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" }, "engines": { - "node": ">=v12.22.7" + "node": ">=4.0.0" } }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" + "engines": { + "node": ">=4.0" } }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, + "license": "MIT" + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, "engines": { "node": ">=10" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "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": ">=8" + "node": ">=12" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", "engines": { - "node": ">=14" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/simple-git": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.30.0.tgz", - "integrity": "sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==", - "license": "MIT", + "packages/mobile-client": { + "name": "@codelink/mobile-client", + "version": "0.1.0", "dependencies": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.4.0" + "@callstack/react-theme-provider": "^3.0.9", + "@codelink/protocol": "*", + "@expo-google-fonts/inter": "^0.2.3", + "@expo-google-fonts/manrope": "^0.2.3", + "@expo-google-fonts/space-grotesk": "^0.2.3", + "@expo/vector-icons": "^15.0.3", + "@react-native-async-storage/async-storage": "^2.1.0", + "@react-navigation/bottom-tabs": "^7.15.9", + "@react-navigation/native": "^7.2.2", + "color": "^3.2.1", + "expo": "~54.0.33", + "expo-asset": "^12.0.12", + "expo-constants": "^18.0.13", + "expo-font": "~12.0.10", + "expo-haptics": "~15.0.8", + "expo-linear-gradient": "~13.0.2", + "expo-modules-core": "^3.0.29", + "expo-splash-screen": "^55.0.14-canary-20260328-2049187", + "expo-status-bar": "~3.0.9", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-native": "0.81.5", + "react-native-paper": "^5.14.5", + "react-native-safe-area-context": "^5.6.2", + "react-native-screens": "^4.24.0", + "react-native-web": "^0.21.0", + "socket.io-client": "^4.8.1" }, - "funding": { - "type": "github", - "url": "https://github.com/steveukx/git-js?sponsor=1" + "devDependencies": { + "@testing-library/react-native": "^13.3.3", + "@types/react": "~18.3.1", + "babel-plugin-react-native-web": "^0.19.12", + "babel-preset-expo": "^54.0.10", + "fast-check": "^3.15.0", + "jsdom": "^25.0.1", + "react-test-renderer": "^18.3.1", + "typescript": "~5.9.2", + "vitest": "^4.1.0" } }, - "node_modules/sirv": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", - "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", - "dev": true, - "license": "MIT", + "packages/mobile-client-backup": { + "name": "@codelink/mobile-client-backup", + "version": "0.1.0", + "extraneous": true, "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" + "@codelink/protocol": "*", + "react": "^18.0.0", + "react-diff-viewer-continued": "^3.4.0", + "react-dom": "^18.0.0", + "socket.io-client": "^4.0.0" }, - "engines": { - "node": ">= 10" + "devDependencies": { + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@vitejs/plugin-react": "^4.0.0", + "@vitest/ui": "^1.0.0", + "autoprefixer": "^10.4.23", + "fast-check": "^3.15.0", + "jsdom": "^23.0.0", + "postcss": "^8.5.6", + "tailwindcss": "^3.4.19", + "typescript": "^5.0.0", + "vite": "^5.0.0", + "vitest": "^1.0.0" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, + "packages/mobile-client/node_modules/@expo/fingerprint": { + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.15.4.tgz", + "integrity": "sha512-eYlxcrGdR2/j2M6pEDXo9zU9KXXF1vhP+V+Tl+lyY+bU8lnzrN6c637mz6Ye3em2ANy8hhUR03Raf8VsT9Ogng==", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@expo/spawn-async": "^1.7.2", + "arg": "^5.0.2", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "ignore": "^5.3.1", + "minimatch": "^9.0.0", + "p-limit": "^3.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + }, + "bin": { + "fingerprint": "bin/cli.js" } }, - "node_modules/socket.io": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", - "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", + "packages/mobile-client/node_modules/@expo/osascript": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.4.2.tgz", + "integrity": "sha512-/XP7PSYF2hzOZzqfjgkoWtllyeTN8dW3aM4P6YgKcmmPikKL5FdoyQhti4eh6RK5a5VrUXJTOlTNIpIHsfB5Iw==", "license": "MIT", "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.4.1", - "engine.io": "~6.6.0", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" + "@expo/spawn-async": "^1.7.2" }, "engines": { - "node": ">=10.2.0" + "node": ">=12" } }, - "node_modules/socket.io-adapter": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz", - "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", + "packages/mobile-client/node_modules/@expo/package-manager": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.10.3.tgz", + "integrity": "sha512-ZuXiK/9fCrIuLjPSe1VYmfp0Sa85kCMwd8QQpgyi5ufppYKRtLBg14QOgUqj8ZMbJTxE0xqzd0XR7kOs3vAK9A==", "license": "MIT", "dependencies": { - "debug": "~4.4.1", - "ws": "~8.18.3" + "@expo/json-file": "^10.0.12", + "@expo/spawn-async": "^1.7.2", + "chalk": "^4.0.0", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "resolve-workspace-root": "^2.0.0" } }, - "node_modules/socket.io-client": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", - "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", + "packages/mobile-client/node_modules/@expo/schema-utils": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-0.1.8.tgz", + "integrity": "sha512-9I6ZqvnAvKKDiO+ZF8BpQQFYWXOJvTAL5L/227RUbWG1OVZDInFifzCBiqAZ3b67NRfeAgpgvbA7rejsqhY62A==", + "license": "MIT" + }, + "packages/mobile-client/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "license": "MIT", "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1", - "engine.io-client": "~6.6.1", - "socket.io-parser": "~4.2.4" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=10.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/socket.io-parser": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", - "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", + "packages/mobile-client/node_modules/@react-native-async-storage/async-storage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz", + "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==", "license": "MIT", "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1" + "merge-options": "^3.0.4" }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.65 <1.0" + } + }, + "packages/mobile-client/node_modules/@react-native/normalize-colors": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", + "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", + "license": "MIT" + }, + "packages/mobile-client/node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT" + }, + "packages/mobile-client/node_modules/@types/react": { + "version": "19.1.17", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "packages/mobile-client/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", + "packages/mobile-client/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", + "packages/mobile-client/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 10" + } + }, + "packages/mobile-client/node_modules/expo": { + "version": "54.0.33", + "resolved": "https://registry.npmjs.org/expo/-/expo-54.0.33.tgz", + "integrity": "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "@expo/cli": "54.0.23", + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/devtools": "0.1.8", + "@expo/fingerprint": "0.15.4", + "@expo/metro": "~54.2.0", + "@expo/metro-config": "54.0.14", + "@expo/vector-icons": "^15.0.3", + "@ungap/structured-clone": "^1.3.0", + "babel-preset-expo": "~54.0.10", + "expo-asset": "~12.0.12", + "expo-constants": "~18.0.13", + "expo-file-system": "~19.0.21", + "expo-font": "~14.0.11", + "expo-keep-awake": "~15.0.8", + "expo-modules-autolinking": "3.0.24", + "expo-modules-core": "3.0.29", + "pretty-format": "^29.7.0", + "react-refresh": "^0.14.2", + "whatwg-url-without-unicode": "8.0.0-3" + }, + "bin": { + "expo": "bin/cli", + "expo-modules-autolinking": "bin/autolinking", + "fingerprint": "bin/fingerprint" + }, + "peerDependencies": { + "@expo/dom-webview": "*", + "@expo/metro-runtime": "*", + "react": "*", + "react-native": "*", + "react-native-webview": "*" + }, + "peerDependenciesMeta": { + "@expo/dom-webview": { + "optional": true + }, + "@expo/metro-runtime": { + "optional": true + }, + "react-native-webview": { + "optional": true + } } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "packages/mobile-client/node_modules/expo-asset": { + "version": "12.0.12", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.12.tgz", + "integrity": "sha512-CsXFCQbx2fElSMn0lyTdRIyKlSXOal6ilLJd+yeZ6xaC7I9AICQgscY5nj0QcwgA+KYYCCEQEBndMsmj7drOWQ==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "@expo/image-utils": "^0.8.8", + "expo-constants": "~18.0.12" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" } }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, + "packages/mobile-client/node_modules/expo-font": { + "version": "12.0.10", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-12.0.10.tgz", + "integrity": "sha512-Q1i2NuYri3jy32zdnBaHHCya1wH1yMAsI+3CCmj9zlQzlhsS9Bdwcj2W3c5eU5FvH2hsNQy4O+O1NnM6o/pDaQ==", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "fontfaceobserver": "^2.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "expo": "*" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, + "packages/mobile-client/node_modules/expo-haptics": { + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/expo-haptics/-/expo-haptics-15.0.8.tgz", + "integrity": "sha512-lftutojy8Qs8zaDzzjwM3gKHFZ8bOOEZDCkmh2Ddpe95Ra6kt2izeOfOfKuP/QEh0MZ1j9TfqippyHdRd1ZM9g==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/mobile-client/node_modules/expo-modules-autolinking": { + "version": "3.0.24", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.24.tgz", + "integrity": "sha512-TP+6HTwhL7orDvsz2VzauyQlXJcAWyU3ANsZ7JGL4DQu8XaZv/A41ZchbtAYLfozNA2Ya1Hzmhx65hXryBMjaQ==", "license": "MIT", "dependencies": { - "min-indent": "^1.0.0" + "@expo/spawn-async": "^1.7.2", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "require-from-string": "^2.0.2", + "resolve-from": "^5.0.0" }, - "engines": { - "node": ">=8" + "bin": { + "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, + "packages/mobile-client/node_modules/expo-server": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-1.0.5.tgz", + "integrity": "sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA==", "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=20.16.0" } }, - "node_modules/strip-literal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", - "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", - "dev": true, + "packages/mobile-client/node_modules/expo-status-bar": { + "version": "3.0.9", "license": "MIT", "dependencies": { - "js-tokens": "^9.0.1" + "react-native-is-edge-to-edge": "^1.2.1" }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "packages/mobile-client/node_modules/expo/node_modules/@expo/cli": { + "version": "54.0.23", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.23.tgz", + "integrity": "sha512-km0h72SFfQCmVycH/JtPFTVy69w6Lx1cHNDmfLfQqgKFYeeHTjx7LVDP4POHCtNxFP2UeRazrygJhlh4zz498g==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.0.8", + "@expo/code-signing-certificates": "^0.0.6", + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/devcert": "^1.2.1", + "@expo/env": "~2.0.8", + "@expo/image-utils": "^0.8.8", + "@expo/json-file": "^10.0.8", + "@expo/metro": "~54.2.0", + "@expo/metro-config": "~54.0.14", + "@expo/osascript": "^2.3.8", + "@expo/package-manager": "^1.9.10", + "@expo/plist": "^0.4.8", + "@expo/prebuild-config": "^54.0.8", + "@expo/schema-utils": "^0.1.8", + "@expo/spawn-async": "^1.7.2", + "@expo/ws-tunnel": "^1.0.1", + "@expo/xcpretty": "^4.3.0", + "@react-native/dev-middleware": "0.81.5", + "@urql/core": "^5.0.6", + "@urql/exchange-retry": "^1.3.0", + "accepts": "^1.3.8", + "arg": "^5.0.2", + "better-opn": "~3.0.2", + "bplist-creator": "0.1.0", + "bplist-parser": "^0.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.3.0", + "compression": "^1.7.4", + "connect": "^3.7.0", + "debug": "^4.3.4", + "env-editor": "^0.4.1", + "expo-server": "^1.0.5", + "freeport-async": "^2.0.0", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "lan-network": "^0.1.6", + "minimatch": "^9.0.0", + "node-forge": "^1.3.3", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "picomatch": "^3.0.1", + "pretty-bytes": "^5.6.0", + "pretty-format": "^29.7.0", + "progress": "^2.0.3", + "prompts": "^2.3.2", + "qrcode-terminal": "0.11.0", + "require-from-string": "^2.0.2", + "requireg": "^0.2.2", + "resolve": "^1.22.2", + "resolve-from": "^5.0.0", + "resolve.exports": "^2.0.3", + "semver": "^7.6.0", + "send": "^0.19.0", + "slugify": "^1.3.4", + "source-map-support": "~0.5.21", + "stacktrace-parser": "^0.1.10", + "structured-headers": "^0.4.1", + "tar": "^7.5.2", + "terminal-link": "^2.1.1", + "undici": "^6.18.2", + "wrap-ansi": "^7.0.0", + "ws": "^8.12.1" + }, + "bin": { + "expo-internal": "build/bin/cli" + }, + "peerDependencies": { + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } } }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", - "license": "MIT" + "packages/mobile-client/node_modules/expo/node_modules/@expo/cli/node_modules/@expo/prebuild-config": { + "version": "54.0.8", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-54.0.8.tgz", + "integrity": "sha512-EA7N4dloty2t5Rde+HP0IEE+nkAQiu4A/+QGZGT9mFnZ5KKjPPkqSyYcRvP5bhQE10D+tvz6X0ngZpulbMdbsg==", + "license": "MIT", + "dependencies": { + "@expo/config": "~12.0.13", + "@expo/config-plugins": "~54.0.4", + "@expo/config-types": "^54.0.10", + "@expo/image-utils": "^0.8.8", + "@expo/json-file": "^10.0.8", + "@react-native/normalize-colors": "0.81.5", + "debug": "^4.3.1", + "resolve-from": "^5.0.0", + "semver": "^7.6.0", + "xml2js": "0.6.0" + }, + "peerDependencies": { + "expo": "*" + } }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, + "packages/mobile-client/node_modules/expo/node_modules/@expo/devtools": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-0.1.8.tgz", + "integrity": "sha512-SVLxbuanDjJPgc0sy3EfXUMLb/tXzp6XIHkhtPVmTWJAp+FOr6+5SeiCfJrCzZFet0Ifyke2vX3sFcKwEvCXwQ==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" + "chalk": "^4.1.2" }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" + "peerDependencies": { + "react": "*", + "react-native": "*" }, - "engines": { - "node": ">=16 || 14 >=14.17" + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-native": { + "optional": true + } } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "packages/mobile-client/node_modules/expo/node_modules/@expo/metro-config": { + "version": "54.0.14", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-54.0.14.tgz", + "integrity": "sha512-hxpLyDfOR4L23tJ9W1IbJJsG7k4lv2sotohBm/kTYyiG+pe1SYCAWsRmgk+H42o/wWf/HQjE5k45S5TomGLxNA==", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.5", + "@expo/config": "~12.0.13", + "@expo/env": "~2.0.8", + "@expo/json-file": "~10.0.8", + "@expo/metro": "~54.2.0", + "@expo/spawn-async": "^1.7.2", + "browserslist": "^4.25.0", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "hermes-parser": "^0.29.1", + "jsc-safe-url": "^0.2.4", + "lightningcss": "^1.30.1", + "minimatch": "^9.0.0", + "postcss": "~8.4.32", + "resolve-from": "^5.0.0" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "expo": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "packages/mobile-client/node_modules/expo/node_modules/expo-file-system": { + "version": "19.0.21", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.21.tgz", + "integrity": "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "packages/mobile-client/node_modules/expo/node_modules/expo-font": { + "version": "14.0.11", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz", + "integrity": "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==", + "license": "MIT", + "dependencies": { + "fontfaceobserver": "^2.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" + "packages/mobile-client/node_modules/expo/node_modules/expo-keep-awake": { + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.8.tgz", + "integrity": "sha512-YK9M1VrnoH1vLJiQzChZgzDvVimVoriibiDIFLbQMpjYBnvyfUeHJcin/Gx1a+XgupNXy92EQJLgI/9ZuXajYQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*" + } }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "packages/mobile-client/node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], "license": "MIT", "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" + "pure-rand": "^6.1.0" }, + "engines": { + "node": ">=8.0.0" + } + }, + "packages/mobile-client/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "packages/mobile-client/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "packages/mobile-client/node_modules/lan-network": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.1.7.tgz", + "integrity": "sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ==", + "license": "MIT", "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, + "lan-network": "dist/lan-network-cli.js" + } + }, + "packages/mobile-client/node_modules/picomatch": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.2.tgz", + "integrity": "sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==", + "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/tailwindcss/node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, + "packages/mobile-client/node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "funding": [ { "type": "opencollective", "url": "https://opencollective.com/postcss/" }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, { "type": "github", "url": "https://github.com/sponsors/ai" @@ -5821,745 +12648,825 @@ ], "license": "MIT", "dependencies": { - "lilconfig": "^3.1.1" + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" + "node": "^10 || ^12 || >=14" } }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, + "packages/mobile-client/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "license": "MIT", "dependencies": { - "thenify": ">= 3.1.0 < 4" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=0.8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "packages/mobile-client/node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], "license": "MIT" }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, + "packages/mobile-client/node_modules/react-native-is-edge-to-edge": { + "version": "1.2.1", "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "peerDependencies": { + "react": "*", + "react-native": "*" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, + "packages/mobile-client/node_modules/react-native-paper": { + "version": "5.14.5", "license": "MIT", - "engines": { - "node": ">=12.0.0" + "workspaces": [ + "example", + "docs" + ], + "dependencies": { + "@callstack/react-theme-provider": "^3.0.9", + "color": "^3.1.2", + "use-latest-callback": "^0.2.3" }, "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "react": "*", + "react-native": "*", + "react-native-safe-area-context": "*" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, + "packages/mobile-client/node_modules/react-native-safe-area-context": { + "version": "5.6.2", "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "react": "*", + "react-native": "*" } }, - "node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", - "dev": true, + "packages/mobile-client/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=0.10.0" } }, - "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" + "packages/protocol": { + "name": "@codelink/protocol", + "version": "0.1.0", + "devDependencies": { + "typescript": "^5.0.0", + "vitest": "^4.1.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", + "packages/relay-server": { + "name": "@codelink/relay-server", + "version": "0.1.0", "dependencies": { - "is-number": "^7.0.0" + "@codelink/protocol": "*", + "socket.io": "^4.0.0" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^5.0.0" + } + }, + "packages/vscode-extension": { + "name": "codelink-extension", + "version": "0.1.0", + "dependencies": { + "@codelink/protocol": "*", + "simple-git": "^3.25.0", + "socket.io-client": "^4.8.3" + }, + "devDependencies": { + "@types/node": "^25.3.0", + "@types/vscode": "^1.80.0", + "typescript": "^5.0.0", + "vitest": "^4.0.18" }, "engines": { - "node": ">=8.0" + "vscode": "^1.80.0" } }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "packages/vscode-extension/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "packages/vscode-extension/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "packages/vscode-extension/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { "node": ">=18" } }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "packages/vscode-extension/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" + "node": ">=18" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "packages/vscode-extension/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.8.0" + "node": ">=18" } }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "packages/vscode-extension/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "packages/vscode-extension/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "packages/vscode-extension/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=14.17" + "node": ">=18" } }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "packages/vscode-extension/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 4.0.0" + "node": ">=18" } }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "packages/vscode-extension/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], "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", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/vscode-extension/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" ], + "dev": true, "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "packages/vscode-extension/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "packages/vscode-extension/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "packages/vscode-extension/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.8" + "node": ">=18" } }, - "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "packages/vscode-extension/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, + "optional": true, + "os": [ + "linux" + ], "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": ">=18" } }, - "node_modules/vite-node": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", - "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", + "packages/vscode-extension/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "node": ">=18" } }, - "node_modules/vitest": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", - "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", + "packages/vscode-extension/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@vitest/expect": "1.6.1", - "@vitest/runner": "1.6.1", - "@vitest/snapshot": "1.6.1", - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.1", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.1", - "@vitest/ui": "1.6.1", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } + "node": ">=18" } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "packages/vscode-extension/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { "node": ">=18" } }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "packages/vscode-extension/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "packages/vscode-extension/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { "node": ">=18" } }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "packages/vscode-extension/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" } }, - "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "packages/vscode-extension/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, + "packages/vscode-extension/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "packages/vscode-extension/node_modules/@types/node": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", "dev": true, "license": "MIT", "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" + "undici-types": "~7.18.0" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "packages/vscode-extension/node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "packages/vscode-extension/node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", "dev": true, - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", - "engines": { - "node": ">=10.0.0" + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" }, "peerDependenciesMeta": { - "bufferutil": { + "msw": { "optional": true }, - "utf-8-validate": { + "vite": { "optional": true } } }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "packages/vscode-extension/node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "packages/vscode-extension/node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", "dev": true, - "license": "MIT" - }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", - "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", - "engines": { - "node": ">=0.4.0" + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "packages/vscode-extension/node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "license": "ISC", - "engines": { - "node": ">= 6" + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "packages/vscode-extension/node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, - "packages/mobile-client": { - "name": "@codelink/mobile-client", - "version": "0.1.0", - "dependencies": { - "@codelink/protocol": "*", - "react": "^18.0.0", - "react-diff-viewer-continued": "^3.4.0", - "react-dom": "^18.0.0", - "socket.io-client": "^4.0.0" + "packages/vscode-extension/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" }, - "devDependencies": { - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@vitejs/plugin-react": "^4.0.0", - "@vitest/ui": "^1.0.0", - "autoprefixer": "^10.4.23", - "fast-check": "^3.15.0", - "jsdom": "^23.0.0", - "postcss": "^8.5.6", - "tailwindcss": "^3.4.19", - "typescript": "^5.0.0", - "vite": "^5.0.0", - "vitest": "^1.0.0" - } - }, - "packages/protocol": { - "name": "@codelink/protocol", - "version": "0.1.0", - "devDependencies": { - "typescript": "^5.0.0" - } + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "packages/vscode-extension/node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" }, - "packages/relay-server": { - "name": "@codelink/relay-server", - "version": "0.1.0", + "packages/vscode-extension/node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", "dependencies": { - "@codelink/protocol": "*", - "socket.io": "^4.0.0" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, - "devDependencies": { - "@types/node": "^20.0.0", - "typescript": "^5.0.0" + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "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 + } } }, - "packages/vscode-extension": { - "name": "codelink-extension", - "version": "0.1.0", + "packages/vscode-extension/node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@codelink/protocol": "*", - "simple-git": "^3.25.0", - "socket.io-client": "^4.8.3" + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" }, - "devDependencies": { - "@types/vscode": "^1.80.0", - "typescript": "^5.0.0" + "bin": { + "vitest": "vitest.mjs" }, "engines": { - "vscode": "^1.80.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } } } diff --git a/package.json b/package.json index 3bea242..97d272c 100644 --- a/package.json +++ b/package.json @@ -9,19 +9,40 @@ "build": "npm run build --workspaces --if-present", "dev": "npm run dev --workspaces --if-present", "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "eslint . --ext .ts,.tsx --fix", "format": "prettier --write \"**/*.{ts,tsx,json,md}\"", "format:check": "prettier --check \"**/*.{ts,tsx,json,md}\"", + "typecheck": "npm run typecheck:protocol && npm run typecheck:relay && npm run typecheck:vscode", + "typecheck:protocol": "cd packages/protocol && tsc --noEmit", + "typecheck:relay": "cd packages/relay-server && tsc --noEmit", + "typecheck:vscode": "cd packages/vscode-extension && tsc --noEmit", + "typecheck:mobile": "cd packages/mobile-client && tsc --noEmit", "test": "vitest run", - "test:watch": "vitest" + "test:unit": "vitest run tests/unit", + "test:integration": "vitest run tests/integration", + "test:property": "vitest run tests/property", + "test:performance": "vitest run tests/performance", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", + "test:ci": "vitest run --coverage --reporter=verbose", + "verify:coverage": "node tests/setup/test-coverage-formats.js", + "precommit": "npm run lint && npm run typecheck && npm run format:check" }, "devDependencies": { + "@types/node": "^20.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", - "@types/node": "^20.0.0", + "@vitest/coverage-v8": "^4.1.0", + "@vitest/ui": "^4.1.0", + "babel-preset-expo": "^54.0.10", "eslint": "^8.0.0", - "fast-check": "^3.0.0", + "fast-check": "^4.6.0", "prettier": "^3.0.0", "typescript": "^5.0.0", - "vitest": "^1.0.0" + "vitest": "^4.1.0" + }, + "overrides": { + "react": "18.3.1", + "react-dom": "18.3.1" } } diff --git a/packages/mobile-client/.gitignore b/packages/mobile-client/.gitignore new file mode 100644 index 0000000..11f3469 --- /dev/null +++ b/packages/mobile-client/.gitignore @@ -0,0 +1,47 @@ +# Expo +.expo/ +dist/ +web-build/ + +# Native +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# Debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store +*.pem + +# Local env files +.env*.local +.env + +# Typescript +*.tsbuildinfo + +# Dependencies +node_modules/ + +# Testing +coverage/ +/src/design-system/components/*test* +/src/design-system/tokens/*.test.* +/src/design-system/theme/*.test.* +/src/design-system/typography/*.test.* + + +/src/design-system/components/*.example.* +/src/design-system/tokens/*.example.* +/src/design-system/theme/*.example.* +/src/design-system/typography/*.example.* \ No newline at end of file diff --git a/packages/mobile-client/.npmrc b/packages/mobile-client/.npmrc new file mode 100644 index 0000000..521a9f7 --- /dev/null +++ b/packages/mobile-client/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/packages/mobile-client/App.tsx b/packages/mobile-client/App.tsx new file mode 100644 index 0000000..f8cb828 --- /dev/null +++ b/packages/mobile-client/App.tsx @@ -0,0 +1,294 @@ +import React, { useState, useEffect } from 'react'; +import { StatusBar } from 'expo-status-bar'; +import { StyleSheet, View, SafeAreaView } from 'react-native'; +import { Provider as PaperProvider, BottomNavigation, Badge } from 'react-native-paper'; +import { MaterialCommunityIcons } from '@expo/vector-icons'; +import * as Haptics from 'expo-haptics'; +import type { InjectPromptResponse } from '@codelink/protocol'; + +// Components +import { + Dashboard, + PromptComposer, + PromptResponseDisplay, + DiffViewer, + ErrorBoundary, + EmptyState, + Settings, + AppLoading, +} from './src/components'; + +// Services +import { PromptManagerImpl, DiffMessageHandler } from './src/services'; +import type { DiffState } from './src/services'; + +// Hooks +import { + ConnectionStatusProvider, + useConnection, + ThemeProvider, + useTheme, + usePromptHistory, +} from './src/hooks'; + +// Config +import { getConfig } from './src/config'; + +// Design System +import { useCustomFonts } from './src/design-system/typography/fontLoading'; + +// Utils +import { isInjectPromptResponse, isSyncFullContextMessage } from './src/utils/messageValidation'; + +/** + * Main application content with navigation + */ +const AppContent: React.FC = () => { + const { status, socketManager, reconnect } = useConnection(); + const { theme, isDark } = useTheme(); + const { updateHistoryItem } = usePromptHistory(); + const [index, setIndex] = useState(0); + const [promptResponse, setPromptResponse] = useState(null); + const [isSubmitting, setIsSubmitting] = useState(false); + const [promptError, setPromptError] = useState(null); + const [currentPromptId, setCurrentPromptId] = useState(null); + const [diffState, setDiffState] = useState({ + currentDiff: null, + history: [], + selectedIndex: -1, + }); + + // Initialize PromptManager and DiffMessageHandler + const [promptManager] = useState(() => new PromptManagerImpl(socketManager)); + const [diffHandler] = useState(() => new DiffMessageHandler(50)); + + // Set up message routing from SocketManager to handlers + useEffect(() => { + // Handle incoming messages + const messageHandler = (message: unknown) => { + // Route INJECT_PROMPT_RESPONSE to PromptManager + if (isInjectPromptResponse(message)) { + promptManager.handleResponse(message); + } + + // Route SYNC_FULL_CONTEXT to DiffMessageHandler + if (isSyncFullContextMessage(message)) { + diffHandler.handleMessage(message); + } + }; + + socketManager.onMessage(messageHandler); + + // Set up PromptManager response callback + promptManager.onResponse((response) => { + setPromptResponse(response); + setIsSubmitting(false); + + // Update history with result + if (currentPromptId) { + updateHistoryItem(currentPromptId, { + success: response.payload.success, + editorUsed: response.payload.editorUsed, + }); + } + + // Haptic feedback + if (response.payload.success) { + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); + } else { + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); + } + + // Clear response after 4 seconds + setTimeout(() => { + setPromptResponse(null); + }, 4000); + }); + + // Set up DiffMessageHandler state change listener + diffHandler.onStateChange((state) => { + setDiffState(state); + }); + + // Set up DiffMessageHandler error listener + diffHandler.onError((error) => { + console.error('Diff handler error:', error); + }); + }, [socketManager, promptManager, diffHandler, currentPromptId, updateHistoryItem]); + + // Handle prompt submission + const handlePromptSubmit = (prompt: string) => { + try { + setIsSubmitting(true); + setPromptError(null); + const promptId = Date.now().toString(); + setCurrentPromptId(promptId); + promptManager.submitPrompt(prompt); + } catch (error) { + setIsSubmitting(false); + setPromptError(error instanceof Error ? error.message : 'Failed to submit prompt'); + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); + } + }; + + // Handle response dismissal + const handleResponseDismiss = () => { + setPromptResponse(null); + }; + + // Handle reconnection (currently unused but kept for future use) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _handleReconnect = async () => { + await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + reconnect(); + }; + + // Define navigation routes + const [routes] = useState([ + { + key: 'dashboard', + title: 'Dashboard', + focusedIcon: 'view-dashboard', + unfocusedIcon: 'view-dashboard-outline', + }, + { + key: 'prompt', + title: 'Prompt', + focusedIcon: 'message-text', + unfocusedIcon: 'message-text-outline', + }, + { key: 'diff', title: 'Diff', focusedIcon: 'file-compare', unfocusedIcon: 'file-compare' }, + { key: 'settings', title: 'Settings', focusedIcon: 'cog', unfocusedIcon: 'cog-outline' }, + ]); + + // Render scene based on route + const renderScene = BottomNavigation.SceneMap({ + dashboard: () => ( + + setIndex(1)} + onNavigateToDiffs={() => setIndex(2)} + onRefresh={async () => { + await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); + // Refresh logic can be added here if needed + }} + /> + + ), + prompt: () => ( + + + + + ), + diff: () => ( + + {diffState.currentDiff ? ( + + ) : ( + setIndex(0)} + /> + )} + + ), + settings: () => ( + + + + ), + }); + + // Render icon with badge + const renderIcon = ({ + route, + focused, + color, + }: { + route: { key: string; focusedIcon: string; unfocusedIcon: string }; + focused: boolean; + color: string; + }) => { + const icon = focused ? route.focusedIcon : route.unfocusedIcon; + + // Show badge on diff tab if there are new diffs + if (route.key === 'diff' && diffState.history.length > 0) { + return ( + + + + + ); + } + + return ; + }; + + return ( + + + + + ); +}; + +/** + * Root App component with providers + */ +export default function App() { + const config = getConfig(); + + // Load custom fonts + const { fontsLoaded, fontError } = useCustomFonts(); + + // Show loading screen while fonts are loading + if (!fontsLoaded) { + return ; + } + + // Log font loading error but continue with system fonts + if (fontError) { + console.error('Font loading failed, using system fonts:', fontError); + } + + return ( + + + + + + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + scene: { + flex: 1, + }, + badge: { + position: 'absolute', + top: 4, + right: 4, + }, +}); diff --git a/packages/mobile-client/app.json b/packages/mobile-client/app.json new file mode 100644 index 0000000..0755bdf --- /dev/null +++ b/packages/mobile-client/app.json @@ -0,0 +1,35 @@ +{ + "expo": { + "name": "CodeLink Mobile", + "slug": "codelink-mobile", + "version": "0.1.0", + "orientation": "default", + "icon": "./assets/icon.png", + "userInterfaceStyle": "light", + "newArchEnabled": true, + "splash": { + "image": "./assets/splash-icon.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "ios": { + "supportsTablet": true, + "bundleIdentifier": "com.codelink.mobile" + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#ffffff" + }, + "package": "com.codelink.mobile", + "edgeToEdgeEnabled": true, + "predictiveBackGestureEnabled": false + }, + "web": { + "favicon": "./assets/favicon.png" + }, + "extra": { + "relayServerUrl": "ws://localhost:3000" + } + } +} diff --git a/packages/mobile-client/assets/adaptive-icon.png b/packages/mobile-client/assets/adaptive-icon.png new file mode 100644 index 0000000..03d6f6b Binary files /dev/null and b/packages/mobile-client/assets/adaptive-icon.png differ diff --git a/packages/mobile-client/assets/favicon.png b/packages/mobile-client/assets/favicon.png new file mode 100644 index 0000000..e75f697 Binary files /dev/null and b/packages/mobile-client/assets/favicon.png differ diff --git a/packages/mobile-client/assets/icon.png b/packages/mobile-client/assets/icon.png new file mode 100644 index 0000000..a0b1526 Binary files /dev/null and b/packages/mobile-client/assets/icon.png differ diff --git a/packages/mobile-client/assets/splash-icon.png b/packages/mobile-client/assets/splash-icon.png new file mode 100644 index 0000000..03d6f6b Binary files /dev/null and b/packages/mobile-client/assets/splash-icon.png differ diff --git a/packages/mobile-client/babel.config.js b/packages/mobile-client/babel.config.js new file mode 100644 index 0000000..3023d5a --- /dev/null +++ b/packages/mobile-client/babel.config.js @@ -0,0 +1,11 @@ +module.exports = function (api) { + api.cache(true); + return { + presets: ['babel-preset-expo'], + env: { + production: { + plugins: ['react-native-paper/babel'], + }, + }, + }; +}; diff --git a/packages/mobile-client/fix-android-build.sh b/packages/mobile-client/fix-android-build.sh new file mode 100755 index 0000000..a3c69b2 --- /dev/null +++ b/packages/mobile-client/fix-android-build.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# Fix Android Build Issues +# This script cleans caches and reinstalls dependencies to fix React hooks errors + +set -e + +echo "======================================" +echo "Fixing Android Build Issues" +echo "======================================" +echo "" + +# Navigate to mobile-client directory +cd "$(dirname "$0")" + +echo "Step 1: Stopping any running Metro bundler..." +pkill -f "react-native" || true +pkill -f "expo" || true +echo "✓ Stopped" +echo "" + +echo "Step 2: Cleaning Expo cache..." +rm -rf .expo +echo "✓ Expo cache cleared" +echo "" + +echo "Step 3: Cleaning node_modules..." +rm -rf node_modules +echo "✓ node_modules removed" +echo "" + +echo "Step 4: Cleaning package-lock.json..." +rm -f package-lock.json +echo "✓ package-lock.json removed" +echo "" + +echo "Step 5: Installing dependencies..." +npm install +echo "✓ Dependencies installed" +echo "" + +echo "Step 6: Clearing Metro bundler cache..." +npx expo start --clear +echo "" + +echo "======================================" +echo "Build fix complete!" +echo "======================================" +echo "" +echo "Now run: npm run android" diff --git a/packages/mobile-client/index.html b/packages/mobile-client/index.html deleted file mode 100644 index 620c5fb..0000000 --- a/packages/mobile-client/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - CodeLink - - -
- - - diff --git a/packages/mobile-client/index.ts b/packages/mobile-client/index.ts new file mode 100644 index 0000000..1d6e981 --- /dev/null +++ b/packages/mobile-client/index.ts @@ -0,0 +1,8 @@ +import { registerRootComponent } from 'expo'; + +import App from './App'; + +// registerRootComponent calls AppRegistry.registerComponent('main', () => App); +// It also ensures that whether you load the app in Expo Go or in a native build, +// the environment is set up appropriately +registerRootComponent(App); diff --git a/packages/mobile-client/metro.config.js b/packages/mobile-client/metro.config.js new file mode 100644 index 0000000..a11779f --- /dev/null +++ b/packages/mobile-client/metro.config.js @@ -0,0 +1,21 @@ +const { getDefaultConfig } = require('expo/metro-config'); +const path = require('path'); + +const projectRoot = __dirname; +const workspaceRoot = path.resolve(projectRoot, '../..'); + +const config = getDefaultConfig(projectRoot); + +// 1. Watch all files within the monorepo +config.watchFolders = [workspaceRoot]; + +// 2. Let Metro know where to resolve packages and in what order +config.resolver.nodeModulesPaths = [ + path.resolve(projectRoot, 'node_modules'), + path.resolve(workspaceRoot, 'node_modules'), +]; + +// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths` +config.resolver.disableHierarchicalLookup = true; + +module.exports = config; diff --git a/packages/mobile-client/package.json b/packages/mobile-client/package.json index b34c860..5b1376c 100644 --- a/packages/mobile-client/package.json +++ b/packages/mobile-client/package.json @@ -1,36 +1,61 @@ { "name": "@codelink/mobile-client", "version": "0.1.0", - "type": "module", - "main": "./dist/index.js", + "main": "index.ts", "scripts": { - "build": "vite build", - "dev": "vite", - "preview": "vite preview", + "start": "expo start", + "android": "expo start --android", + "ios": "expo start --ios", + "web": "expo start --web", "test": "vitest --run", - "test:watch": "vitest" + "test:watch": "vitest", + "clean": "rm -rf node_modules .expo && npm install" }, "dependencies": { + "@callstack/react-theme-provider": "^3.0.9", "@codelink/protocol": "*", - "react": "^18.0.0", - "react-diff-viewer-continued": "^3.4.0", - "react-dom": "^18.0.0", - "socket.io-client": "^4.0.0" + "@expo-google-fonts/inter": "^0.2.3", + "@expo-google-fonts/manrope": "^0.2.3", + "@expo-google-fonts/space-grotesk": "^0.2.3", + "@expo/vector-icons": "^15.0.3", + "@react-native-async-storage/async-storage": "^2.1.0", + "@react-navigation/bottom-tabs": "^7.15.9", + "@react-navigation/native": "^7.2.2", + "color": "^3.2.1", + "expo": "~54.0.33", + "expo-asset": "^12.0.12", + "expo-blur": "~15.0.8", + "expo-constants": "^18.0.13", + "expo-font": "~12.0.10", + "expo-haptics": "~15.0.8", + "expo-linear-gradient": "~13.0.2", + "expo-modules-core": "^3.0.29", + "expo-splash-screen": "^55.0.14-canary-20260328-2049187", + "expo-status-bar": "~3.0.9", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-native": "0.81.5", + "react-native-paper": "^5.14.5", + "react-native-safe-area-context": "^5.6.2", + "react-native-screens": "^4.24.0", + "react-native-web": "^0.21.0", + "socket.io-client": "^4.8.1" }, "devDependencies": { - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@vitejs/plugin-react": "^4.0.0", - "@vitest/ui": "^1.0.0", - "autoprefixer": "^10.4.23", + "@testing-library/react-native": "^13.3.3", + "@types/react": "~18.3.1", + "babel-plugin-react-native-web": "^0.19.12", + "babel-preset-expo": "^54.0.10", "fast-check": "^3.15.0", - "jsdom": "^23.0.0", - "postcss": "^8.5.6", - "tailwindcss": "^3.4.19", - "typescript": "^5.0.0", - "vite": "^5.0.0", - "vitest": "^1.0.0" - } + "jsdom": "^25.0.1", + "react-test-renderer": "^18.3.1", + "typescript": "~5.9.2", + "vitest": "^4.1.0" + }, + "overrides": { + "react": "18.3.1", + "react-dom": "18.3.1", + "react-test-renderer": "18.3.1" + }, + "private": true } diff --git a/packages/mobile-client/postcss.config.js b/packages/mobile-client/postcss.config.js deleted file mode 100644 index 2e7af2b..0000000 --- a/packages/mobile-client/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/packages/mobile-client/public/manifest.json b/packages/mobile-client/public/manifest.json deleted file mode 100644 index cc3ee6e..0000000 --- a/packages/mobile-client/public/manifest.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "CodeLink", - "short_name": "CodeLink", - "description": "Mobile client for CodeLink - AI-assisted code editing", - "start_url": "/", - "display": "standalone", - "background_color": "#ffffff", - "theme_color": "#000000", - "icons": [ - { - "src": "/icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} diff --git a/packages/mobile-client/src/App.test.tsx b/packages/mobile-client/src/App.test.tsx deleted file mode 100644 index e3adb21..0000000 --- a/packages/mobile-client/src/App.test.tsx +++ /dev/null @@ -1,300 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { render, screen, waitFor } from '@testing-library/react'; -import App from './App'; -import { FileContextPayload } from '@codelink/protocol'; -import { WebSocketClient, ConnectionStatus } from './websocket/WebSocketClient'; - -// Mock the WebSocketClient -vi.mock('./websocket/WebSocketClient', () => { - let statusCallback: ((status: ConnectionStatus) => void) | null = null; - let payloadCallback: ((payload: FileContextPayload) => void) | null = null; - - return { - ConnectionStatus: {}, - WebSocketClient: vi.fn().mockImplementation(() => ({ - connect: vi.fn(), - disconnect: vi.fn(), - onStatusChange: vi.fn((callback) => { - statusCallback = callback; - }), - onPayload: vi.fn((callback) => { - payloadCallback = callback; - }), - // Expose methods to trigger callbacks in tests - _triggerStatusChange: (status: ConnectionStatus) => { - if (statusCallback) statusCallback(status); - }, - _triggerPayload: (payload: FileContextPayload) => { - if (payloadCallback) payloadCallback(payload); - }, - })), - }; -}); - -// Mock DiffViewer component -vi.mock('./components/DiffViewer', () => ({ - default: ({ payload }: { payload: FileContextPayload }) => ( -
-
{payload.fileName}
-
{payload.isDirty ? 'dirty' : 'clean'}
-
- ), -})); - -describe('App Component Integration', () => { - let mockClient: any; - - beforeEach(() => { - // Clear all mocks before each test - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - it('should render App component', () => { - render(); - expect(screen.getByText('CodeLink')).toBeInTheDocument(); - }); - - describe('Connection Status Display', () => { - it('should display "Disconnected" status initially', () => { - render(); - expect(screen.getByText('DISCONNECTED')).toBeInTheDocument(); - }); - - it('should display "Connecting" status when connecting', async () => { - render(); - - // Get the mock client instance - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - // Trigger status change to connecting - mockClient._triggerStatusChange('connecting'); - - await waitFor(() => { - expect(screen.getByText('CONNECTING')).toBeInTheDocument(); - }); - }); - - it('should display "Connected" status when connected', async () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - // Trigger status change to connected - mockClient._triggerStatusChange('connected'); - - await waitFor(() => { - expect(screen.getByText('CONNECTED')).toBeInTheDocument(); - }); - }); - }); - - describe('Welcome Message', () => { - it('should show welcome message when no payload is present', () => { - render(); - // The new UI shows a dashboard instead of a simple welcome message - expect(screen.getByText('CodeLink')).toBeInTheDocument(); - }); - - it('should show "Connecting" message when disconnected', () => { - render(); - // The new UI shows status in the dashboard - expect(screen.getByText('DISCONNECTED')).toBeInTheDocument(); - }); - - it('should show "Waiting for file changes" message when connected', async () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - // Trigger status change to connected - mockClient._triggerStatusChange('connected'); - - await waitFor(() => { - // The new UI shows "No file selected" in the dashboard - expect(screen.getByText('No file selected')).toBeInTheDocument(); - }); - }); - }); - - describe('DiffViewer Rendering', () => { - it('should stay on Dashboard when payload is received', async () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - const testPayload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'original content', - modifiedFile: 'modified content', - isDirty: true, - timestamp: Date.now(), - }; - - // Trigger payload - mockClient._triggerPayload(testPayload); - - await waitFor(() => { - // Should stay on Dashboard and show the active file - expect(screen.getByText('src/test.ts')).toBeInTheDocument(); - expect(screen.getByText('REFRESH')).toBeInTheDocument(); - }); - }); - - it('should show active file in Dashboard when payload is present', async () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - const testPayload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'original content', - modifiedFile: 'modified content', - isDirty: false, - timestamp: Date.now(), - }; - - // Trigger payload - mockClient._triggerPayload(testPayload); - - await waitFor(() => { - // The new UI stays on dashboard and shows the active file - expect(screen.getByText('src/test.ts')).toBeInTheDocument(); - expect(screen.getByText('REFRESH')).toBeInTheDocument(); - }); - }); - }); - - describe('State Updates on Message Receipt', () => { - it('should update active file when new payload is received', async () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - const firstPayload: FileContextPayload = { - fileName: 'src/first.ts', - originalFile: 'first original', - modifiedFile: 'first modified', - isDirty: true, - timestamp: Date.now(), - }; - - // Trigger first payload - mockClient._triggerPayload(firstPayload); - - await waitFor(() => { - expect(screen.getByText('src/first.ts')).toBeInTheDocument(); - }); - - const secondPayload: FileContextPayload = { - fileName: 'src/second.ts', - originalFile: 'second original', - modifiedFile: 'second modified', - isDirty: false, - timestamp: Date.now(), - }; - - // Trigger second payload - mockClient._triggerPayload(secondPayload); - - await waitFor(() => { - expect(screen.getByText('src/second.ts')).toBeInTheDocument(); - }); - }); - - it('should update connection status independently of payload', async () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - // Start with connected status - mockClient._triggerStatusChange('connected'); - - await waitFor(() => { - expect(screen.getByText('CONNECTED')).toBeInTheDocument(); - }); - - // Send a payload - const testPayload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'content', - modifiedFile: 'content', - isDirty: false, - timestamp: Date.now(), - }; - - mockClient._triggerPayload(testPayload); - - await waitFor(() => { - // Should stay on Dashboard and show the active file - expect(screen.getByText('src/test.ts')).toBeInTheDocument(); - expect(screen.getByText('CONNECTED')).toBeInTheDocument(); - }); - - // Change status to disconnected - mockClient._triggerStatusChange('disconnected'); - - await waitFor(() => { - // Dashboard should show disconnected status - expect(screen.getByText('DISCONNECTED')).toBeInTheDocument(); - }); - }); - }); - - describe('WebSocket Client Integration', () => { - it('should initialize WebSocketClient on mount', () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - expect(MockedWebSocketClient).toHaveBeenCalledWith({ url: 'http://localhost:8080' }); - }); - - it('should register status change callback', () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - expect(mockClient.onStatusChange).toHaveBeenCalled(); - }); - - it('should register payload callback', () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - expect(mockClient.onPayload).toHaveBeenCalled(); - }); - - it('should call connect on mount', () => { - render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - expect(mockClient.connect).toHaveBeenCalled(); - }); - - it('should call disconnect on unmount', () => { - const { unmount } = render(); - - const MockedWebSocketClient = vi.mocked(WebSocketClient); - mockClient = MockedWebSocketClient.mock.results[0].value; - - unmount(); - - expect(mockClient.disconnect).toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/mobile-client/src/App.tsx b/packages/mobile-client/src/App.tsx deleted file mode 100644 index 6483b1f..0000000 --- a/packages/mobile-client/src/App.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { useState, useEffect } from 'react'; -import { FileContextPayload } from '@codelink/protocol'; -import { WebSocketClient, ConnectionStatus } from './websocket/WebSocketClient'; -import DiffViewer from './components/DiffViewer'; -import Dashboard from './components/Dashboard'; -import ErrorBoundary from './components/ErrorBoundary'; - -const RELAY_URL = 'http://localhost:8080'; - -function App() { - const [status, setStatus] = useState('disconnected'); - const [payload, setPayload] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const [showDashboard, setShowDashboard] = useState(true); - const [lastSyncTime, setLastSyncTime] = useState(null); - const [latency, setLatency] = useState(24); - - useEffect(() => { - const client = new WebSocketClient({ url: RELAY_URL }); - - // Register status change callback - client.onStatusChange((newStatus) => { - setStatus(newStatus); - if (newStatus === 'connecting') { - setIsLoading(true); - } else { - setIsLoading(false); - } - }); - - // Register payload callback - client.onPayload((newPayload) => { - setPayload(newPayload); - setLastSyncTime(new Date()); - }); - - // Connect to relay server - client.connect(); - - // Simulate latency updates - const latencyInterval = setInterval(() => { - setLatency(Math.floor(Math.random() * 30) + 15); - }, 5000); - - return () => { - client.disconnect(); - clearInterval(latencyInterval); - }; - }, []); - - const handleRefresh = () => { - setIsLoading(true); - setTimeout(() => { - setIsLoading(false); - setLastSyncTime(new Date()); - }, 500); - }; - - const handleDisconnect = () => { - // Implement disconnect logic - setStatus('disconnected'); - }; - - const handleSettings = () => { - console.log('Settings button clicked'); - alert('Settings functionality not yet implemented'); - }; - - const handleBackToDashboard = () => { - setShowDashboard(true); - }; - - return ( - -
- {showDashboard ? ( - setShowDashboard(false)} - hasPayload={!!payload} - /> - ) : payload ? ( - - ) : null} -
-
- ); -} - -export default App; diff --git a/packages/mobile-client/src/components/AppLoading.tsx b/packages/mobile-client/src/components/AppLoading.tsx new file mode 100644 index 0000000..671d052 --- /dev/null +++ b/packages/mobile-client/src/components/AppLoading.tsx @@ -0,0 +1,44 @@ +/** + * AppLoading Component + * + * Displays a loading screen while the app initializes (e.g., loading fonts). + * + * Requirements: 2.5 + */ + +import React from 'react'; +import { View, ActivityIndicator, StyleSheet, Text } from 'react-native'; + +export interface AppLoadingProps { + message?: string; +} + +/** + * Loading screen component + * + * Shows a centered activity indicator with optional message + * while the app is initializing. + */ +export const AppLoading: React.FC = ({ message = 'Loading...' }) => { + return ( + + + {message} + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#131313', // surface color from design system + }, + message: { + marginTop: 16, + fontSize: 16, + color: '#e0e0e0', // onSurface color + fontFamily: 'System', + }, +}); diff --git a/packages/mobile-client/src/components/Dashboard.tsx b/packages/mobile-client/src/components/Dashboard.tsx index 837661d..29135ac 100644 --- a/packages/mobile-client/src/components/Dashboard.tsx +++ b/packages/mobile-client/src/components/Dashboard.tsx @@ -1,322 +1,523 @@ -import { ConnectionStatus } from '../websocket/WebSocketClient'; +import React, { useState, useEffect } from 'react'; +import { View, StyleSheet, ScrollView, FlatList, Dimensions, RefreshControl } from 'react-native'; +import { useDesignSystem } from '../design-system'; +import { Text } from '../design-system/typography/Text'; +import { Card } from '../design-system/components/Card'; +import { Icon } from '../design-system/components/Icon'; +import { ProgressBar } from '../design-system/components/ProgressBar'; +import { StatusIndicator, ConnectionStatus } from '../design-system/components/StatusIndicator'; +import { TopAppBar } from '../navigation/TopAppBar'; -interface DashboardProps { - status: ConnectionStatus; - activeFile: string | null; - lastSyncTime: Date | null; +/** + * System metrics interface + */ +export interface SystemMetrics { + uptime: number; latency: number; - onRefresh: () => void; - onDisconnect: () => void; - onSettings: () => void; - onViewDiff: () => void; - hasPayload: boolean; + load: number; + region: string; + trafficSent: number; + trafficReceived: number; } -function Dashboard({ - status, - activeFile, - lastSyncTime, - latency, +/** + * Activity item interface + */ +export interface ActivityItem { + id: string; + type: 'commit' | 'sync' | 'build' | 'deploy'; + message: string; + timestamp: Date; + metadata?: Record; +} + +/** + * Dashboard component props + */ +export interface DashboardProps { + connectionStatus: ConnectionStatus; + metrics?: SystemMetrics; + recentActivity?: ActivityItem[]; + onNavigateToDiffs: () => void; + onNavigateToCompose: () => void; + onRefresh?: () => Promise; +} + +/** + * Dashboard component displays system overview with bento grid layout + * + * Features: + * - TopAppBar with connection status + * - System Overview section with bento grid layout + * - System Health section with status cards + * - Shortcuts section with navigation cards + * - Recent Activity section with activity feed + * - Responsive grid (2 columns on large screens, 1 on small) + * - Asymmetrical spacing and card sizes for bento pattern + * + * Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 13.5, 13.6, 15.3 + */ +export const Dashboard: React.FC = ({ + connectionStatus, + metrics = { + uptime: 99.8, + latency: 45, + load: 0.65, + region: 'us-west-2', + trafficSent: 2.5, + trafficReceived: 8.3, + }, + recentActivity = [], + onNavigateToDiffs, + onNavigateToCompose, onRefresh, - onDisconnect, - onSettings, - onViewDiff, - hasPayload, -}: DashboardProps) { - const getTimeAgo = (date: Date | null): string => { - if (!date) return 'Never'; - const seconds = Math.floor((new Date().getTime() - date.getTime()) / 1000); - if (seconds < 60) return `${seconds}s ago`; - const minutes = Math.floor(seconds / 60); +}) => { + const { theme } = useDesignSystem(); + const [isLargeScreen, setIsLargeScreen] = useState(false); + const [refreshing, setRefreshing] = useState(false); + + // Detect screen size for responsive layout (Requirement 13.5) + useEffect(() => { + const updateLayout = () => { + const { width } = Dimensions.get('window'); + setIsLargeScreen(width >= 768); + }; + + updateLayout(); + const subscription = Dimensions.addEventListener('change', updateLayout); + return () => subscription?.remove(); + }, []); + + /** + * Handle refresh (Requirement 3.1) + */ + const handleRefresh = async () => { + if (!onRefresh) return; + setRefreshing(true); + try { + await onRefresh(); + } finally { + setRefreshing(false); + } + }; + + /** + * Format uptime percentage (Requirement 3.3) + */ + const formatUptime = (uptime: number): string => { + return `${uptime.toFixed(1)}%`; + }; + + /** + * Format traffic volume (Requirement 3.4) + */ + const formatTraffic = (traffic: number): string => { + return `${traffic.toFixed(1)} GB`; + }; + + /** + * Format activity timestamp (Requirement 3.7) + */ + const formatActivityTime = (date: Date): string => { + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const minutes = Math.floor(diff / 60000); + if (minutes < 1) return 'Just now'; if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); - return `${hours}h ago`; + if (hours < 24) return `${hours}h ago`; + return `${Math.floor(hours / 24)}d ago`; }; - const getBranchName = (): string => { - // Extract branch from file path or use default - return 'feature/auth-module'; + /** + * Get activity type icon (Requirement 3.7) + */ + const getActivityIcon = (type: string): string => { + switch (type) { + case 'commit': + return 'check-circle'; + case 'sync': + return 'sync'; + case 'build': + return 'build'; + case 'deploy': + return 'cloud-upload'; + default: + return 'info'; + } }; + /** + * Render activity feed item (Requirement 3.7, 15.3) + */ + const renderActivityItem = ({ item }: { item: ActivityItem }) => ( + + + + + {item.message} + + + {formatActivityTime(item.timestamp)} + + + + ); + return ( -
- {/* Header */} -
-
-
- - - -
-

CodeLink

-
- -
+ + {/* Top App Bar (Requirement 3.1) */} + - {/* Connection Status Card */} -
+ } > -
-
-
- - {status === 'connected' ? ( - - ) : ( - - )} - -
-
-
- {status === 'connected' - ? 'CONNECTED' - : status === 'connecting' - ? 'CONNECTING' - : 'DISCONNECTED'} -
-
-
-
- {status === 'connected' ? 'ONLINE' : 'OFFLINE'} -
-
-
- - {/* Active File Card */} -
-
-
- - - -
-
-
- ACTIVE FILE -
-
- {activeFile || 'No file selected'} -
-
-
-
+ {/* System Overview Section (Requirement 3.2) */} + + + System Overview + - {/* Last Synced Card */} -
-
-
- + {/* Large card: Uptime (Requirement 3.3) */} + - - -
-
-
- LAST SYNCED -
-
-
- {lastSyncTime ? 'Successfully synced' : 'Not synced yet'} -
-
{getTimeAgo(lastSyncTime)}
-
-
-
-
+ + Uptime + + + {formatUptime(metrics.uptime)} + + + System availability + + - {/* Environment Info */} -
-
- - - -
- ENVIRONMENT INFO -
-
+ {/* Small cards: Latency and Load (Requirement 3.3) */} + + + + Latency + + + {metrics.latency}ms + + -
- {/* Latency Card */} -
-
LATENCY
-
-
-
{latency}ms
-
-
+ + + Load + + + {(metrics.load * 100).toFixed(0)}% + + + + - {/* Branch Card */} -
-
BRANCH
-
- - + + Traffic Volume + + + + + Sent + + + + {formatTraffic(metrics.trafficSent)} + + + + + Received + + - -
- {getBranchName()} -
-
-
-
-
+ + {formatTraffic(metrics.trafficReceived)} + +
+
+ + + + {/* System Health Section (Requirement 3.5) */} + + + System Health + + + + + + + + + Relay Server + + + {connectionStatus === 'connected' + ? 'Connected' + : connectionStatus === 'connecting' + ? 'Connecting' + : 'Disconnected'} + + + + + + + + + + + API + + + Connected + + + + + + - {/* Action Buttons */} -
- - -
-
+ {/* Shortcuts Section (Requirement 3.6) */} + + + Shortcuts + + + + + + + Diff Viewer + + + Review code changes + + + + + + + Compose Prompt + + + Send AI prompt + + + + + + {/* Recent Activity Section (Requirement 3.7, 15.3) */} + {recentActivity.length > 0 && ( + + + Recent Activity + + + + item.id} + scrollEnabled={false} + ItemSeparatorComponent={() => ( + + )} + /> + + + )} + + ); -} +}; -export default Dashboard; +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + scrollView: { + flex: 1, + }, + scrollContent: { + paddingHorizontal: 16, + paddingVertical: 16, + paddingBottom: 100, // Space for bottom nav + }, + section: { + marginBottom: 32, + }, + sectionTitle: { + marginBottom: 16, + }, + bentoGrid: { + flexDirection: 'column', + gap: 12, + }, + bentoGridLarge: { + flexDirection: 'row', + }, + bentoCard: { + flex: 1, + }, + bentoCardLarge: { + flex: 2, + }, + bentoColumn: { + gap: 12, + }, + bentoColumnSmall: { + flex: 1, + }, + cardLabel: { + marginBottom: 8, + }, + cardDescription: { + marginTop: 8, + }, + largeMetric: { + marginVertical: 8, + }, + mediumMetric: { + marginVertical: 4, + }, + trafficCard: { + marginTop: 12, + }, + trafficRow: { + flexDirection: 'row', + gap: 16, + marginTop: 12, + }, + trafficColumn: { + flex: 1, + }, + trafficLabel: { + marginBottom: 8, + }, + trafficBar: { + marginVertical: 8, + }, + trafficValue: { + marginTop: 4, + }, + healthGrid: { + flexDirection: 'row', + gap: 12, + }, + healthCard: { + flex: 1, + }, + healthCardContent: { + flexDirection: 'row', + alignItems: 'center', + gap: 12, + }, + healthCardText: { + flex: 1, + }, + shortcutsGrid: { + flexDirection: 'row', + gap: 12, + }, + shortcutCard: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + minHeight: 140, + }, + shortcutIcon: { + marginBottom: 12, + }, + shortcutTitle: { + marginBottom: 4, + textAlign: 'center', + }, + activityCard: { + minHeight: 200, + }, + activityItem: { + flexDirection: 'row', + alignItems: 'flex-start', + gap: 12, + paddingVertical: 8, + }, + activityIcon: { + marginTop: 2, + }, + activityContent: { + flex: 1, + }, + activityTime: { + marginTop: 4, + }, + activityDivider: { + height: 1, + marginVertical: 8, + }, +}); diff --git a/packages/mobile-client/src/components/DiffViewer.properties.test.tsx b/packages/mobile-client/src/components/DiffViewer.properties.test.tsx deleted file mode 100644 index 079d4b6..0000000 --- a/packages/mobile-client/src/components/DiffViewer.properties.test.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { render } from '@testing-library/react'; -import * as fc from 'fast-check'; -import DiffViewer from './DiffViewer'; -import { FileContextPayload } from '@codelink/protocol'; - -// Feature: git-integration-diffing, Property 17: Diff rendering -describe('DiffViewer Property Tests', () => { - it('Property 17: Diff rendering - should render any valid FileContextPayload without crashing', () => { - fc.assert( - fc.property( - fc.record({ - fileName: fc.string({ minLength: 1, maxLength: 100 }), - originalFile: fc.string({ maxLength: 1000 }), - modifiedFile: fc.string({ maxLength: 1000 }), - isDirty: fc.boolean(), - timestamp: fc.integer({ min: 0, max: Date.now() }), - }), - (payload: FileContextPayload) => { - // The component should render without throwing errors - const { container } = render(); - - // Basic assertions that should hold for any valid payload - expect(container).toBeTruthy(); - - // The fileName (or at least part of it) should be displayed - // Handle edge cases like "/" or paths with only slashes - const parts = payload.fileName.split('/').filter(p => p.trim()); - const fileName = parts.length > 0 ? parts[parts.length - 1] : payload.fileName; - - // Only check if we have a meaningful filename - if (fileName.trim() && fileName !== '/') { - expect(container.textContent).toContain(fileName.trim()); - } else { - // For edge cases like "/" just verify the component rendered - expect(container.querySelector('.bg-\\[\\#161b22\\]')).toBeTruthy(); - } - - // If files are identical, "No changes" should be shown - if (payload.originalFile === payload.modifiedFile && payload.originalFile !== '') { - expect(container.textContent).toContain('No changes'); - } - } - ), - { numRuns: 20 } - ); - }); - - it('Property 17: Diff rendering - should handle edge cases correctly', () => { - fc.assert( - fc.property( - fc.oneof( - // Empty files - fc.constant({ - fileName: 'empty.txt', - originalFile: '', - modifiedFile: '', - isDirty: false, - timestamp: Date.now(), - }), - // Very long file names - fc.record({ - fileName: fc.string({ minLength: 50, maxLength: 200 }), - originalFile: fc.string({ maxLength: 100 }), - modifiedFile: fc.string({ maxLength: 100 }), - isDirty: fc.boolean(), - timestamp: fc.integer({ min: 0, max: Date.now() }), - }), - // Files with special characters - fc.record({ - fileName: fc.string({ minLength: 1, maxLength: 50 }), - originalFile: fc.stringOf(fc.constantFrom('\n', '\t', ' ', 'a', 'b', '1', '2')), - modifiedFile: fc.stringOf(fc.constantFrom('\n', '\t', ' ', 'a', 'b', '1', '2')), - isDirty: fc.boolean(), - timestamp: fc.integer({ min: 0, max: Date.now() }), - }), - // New files (empty original) - fc.record({ - fileName: fc.string({ minLength: 1, maxLength: 50 }), - originalFile: fc.constant(''), - modifiedFile: fc.string({ minLength: 1, maxLength: 500 }), - isDirty: fc.boolean(), - timestamp: fc.integer({ min: 0, max: Date.now() }), - }) - ), - (payload: FileContextPayload) => { - // Should render without errors for all edge cases - const { container } = render(); - expect(container).toBeTruthy(); - - // Just verify the component structure is present - // Don't check for specific filename content due to edge cases - expect(container.querySelector('.flex')).toBeTruthy(); - } - ), - { numRuns: 20 } - ); - }); - - it('Property 17: Diff rendering - should preserve content integrity', () => { - fc.assert( - fc.property( - fc.record({ - fileName: fc.string({ minLength: 1, maxLength: 50 }), - originalFile: fc.string({ minLength: 10, maxLength: 200 }), - modifiedFile: fc.string({ minLength: 10, maxLength: 200 }), - isDirty: fc.boolean(), - timestamp: fc.integer({ min: 0, max: Date.now() }), - }), - (payload: FileContextPayload) => { - // Render the component - const { container } = render(); - - // The component should not crash - expect(container).toBeTruthy(); - - // For non-identical files, the diff viewer should be rendered - // (not showing "No changes") - if (payload.originalFile !== payload.modifiedFile) { - expect(container.textContent).not.toContain('No changes'); - } - } - ), - { numRuns: 20 } - ); - }); -}); diff --git a/packages/mobile-client/src/components/DiffViewer.test.tsx b/packages/mobile-client/src/components/DiffViewer.test.tsx deleted file mode 100644 index 88ca994..0000000 --- a/packages/mobile-client/src/components/DiffViewer.test.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { render, screen } from '@testing-library/react'; -import DiffViewer from './DiffViewer'; -import { FileContextPayload } from '@codelink/protocol'; - -describe('DiffViewer Component', () => { - it('should render with valid payload', () => { - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'const x = 1;', - modifiedFile: 'const x = 2;', - isDirty: false, - timestamp: Date.now(), - }; - - const { container } = render(); - expect(container).toBeTruthy(); - }); - - it('should display fileName correctly in header', () => { - const payload: FileContextPayload = { - fileName: 'src/components/Button.tsx', - originalFile: 'old content', - modifiedFile: 'new content', - isDirty: false, - timestamp: Date.now(), - }; - - render(); - // The new UI shows the full path in the header - expect(screen.getByText('src/components/Button.tsx')).toBeTruthy(); - }); - - it('should show isDirty indicator when true', () => { - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: true, - timestamp: Date.now(), - }; - - const { container } = render(); - // The new UI doesn't show isDirty indicator in the diff viewer - // It's shown in the dashboard instead - expect(container).toBeTruthy(); - }); - - it('should not show isDirty indicator when false', () => { - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: false, - timestamp: Date.now(), - }; - - const { container } = render(); - const dirtyIndicator = container.querySelector('[title="Unsaved changes"]'); - expect(dirtyIndicator).toBeFalsy(); - }); - - it('should format timestamp correctly', () => { - const testTimestamp = new Date('2024-01-15T10:30:00').getTime(); - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: false, - timestamp: testTimestamp, - }; - - const { container } = render(); - // The new UI doesn't display timestamp in the diff viewer - // It's shown in the dashboard instead - expect(container).toBeTruthy(); - }); - - it('should show "No changes" message for identical files', () => { - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'const x = 1;', - modifiedFile: 'const x = 1;', - isDirty: false, - timestamp: Date.now(), - }; - - render(); - expect(screen.getByText('No changes')).toBeTruthy(); - }); - - it('should display new file (all additions) when originalFile is empty', () => { - const payload: FileContextPayload = { - fileName: 'src/newfile.ts', - originalFile: '', - modifiedFile: 'const x = 1;\nconst y = 2;', - isDirty: false, - timestamp: Date.now(), - }; - - const { container } = render(); - // Should not show "No changes" message - expect(screen.queryByText('No changes')).toBeFalsy(); - // Should render the diff viewer (check for overflow-auto class) - const diffContainer = container.querySelector('.overflow-auto'); - expect(diffContainer).toBeTruthy(); - }); - - it('should use unified view mode (splitView=false)', () => { - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'line 1\nline 2', - modifiedFile: 'line 1\nline 3', - isDirty: false, - timestamp: Date.now(), - }; - - const { container } = render(); - // Should not show "No changes" since files are different - expect(screen.queryByText('No changes')).toBeFalsy(); - // Verify the component renders (check for overflow-auto class) - const diffContainer = container.querySelector('.overflow-auto'); - expect(diffContainer).toBeTruthy(); - }); -}); diff --git a/packages/mobile-client/src/components/DiffViewer.tsx b/packages/mobile-client/src/components/DiffViewer.tsx index 91a4787..ee9a37e 100644 --- a/packages/mobile-client/src/components/DiffViewer.tsx +++ b/packages/mobile-client/src/components/DiffViewer.tsx @@ -1,12 +1,20 @@ -import { useState, useEffect, useMemo } from 'react'; +import React, { useState, useEffect, useMemo } from 'react'; +import { View, Text, StyleSheet, ScrollView } from 'react-native'; import { FileContextPayload } from '@codelink/protocol'; +import { useOrientation } from '../hooks'; -interface DiffViewerProps { +/** + * DiffViewer component props + */ +export interface DiffViewerProps { payload: FileContextPayload; isLoading?: boolean; onBack?: () => void; } +/** + * Represents a single line in the diff + */ interface DiffLine { type: 'added' | 'removed' | 'unchanged'; lineNumber: number; @@ -15,9 +23,18 @@ interface DiffLine { newLineNumber?: number; } -function DiffViewer({ payload, isLoading = false, onBack }: DiffViewerProps) { +/** + * DiffViewer component displays unified file diffs in React Native + * Supports both portrait and landscape orientations with responsive layout + * Provides horizontal and vertical scrolling for long content + * + * Requirements: 6.1, 7.2, 7.4, 7.5, 10.1, 10.2, 10.3, 10.4, 10.5 + */ +export const DiffViewer: React.FC = ({ payload, isLoading = false, onBack }) => { const { fileName, originalFile, modifiedFile } = payload; - const [isRendering, setIsRendering] = useState(true); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_isRendering, setIsRendering] = useState(true); + const { isLandscape } = useOrientation(); // Check if this is a new file (no original content) const isNewFile = originalFile === ''; @@ -25,16 +42,18 @@ function DiffViewer({ payload, isLoading = false, onBack }: DiffViewerProps) { // Check if there are no changes const noChanges = originalFile === modifiedFile; - // Calculate additions and deletions + /** + * Calculate additions and deletions statistics + */ const calculateStats = () => { if (noChanges) return { additions: 0, deletions: 0 }; - + const oldLines = originalFile.split('\n'); const newLines = modifiedFile.split('\n'); - + let additions = 0; let deletions = 0; - + // Simple line-based diff calculation const maxLines = Math.max(oldLines.length, newLines.length); for (let i = 0; i < maxLines; i++) { @@ -47,21 +66,24 @@ function DiffViewer({ payload, isLoading = false, onBack }: DiffViewerProps) { deletions++; } } - + return { additions, deletions }; }; const stats = calculateStats(); - // Generate simple line-by-line diff (memoized to recalculate when payload changes) + /** + * Generate simple line-by-line diff + * Memoized to recalculate only when payload changes + */ const diffLines = useMemo(() => { const generateDiff = (): DiffLine[] => { if (noChanges && !isNewFile) return []; - + const oldLines = originalFile.split('\n'); const newLines = modifiedFile.split('\n'); const diff: DiffLine[] = []; - + if (isNewFile) { // All lines are additions newLines.forEach((line, idx) => { @@ -77,7 +99,7 @@ function DiffViewer({ payload, isLoading = false, onBack }: DiffViewerProps) { const maxLines = Math.max(oldLines.length, newLines.length); let oldLineNum = 1; let newLineNum = 1; - + for (let i = 0; i < maxLines; i++) { if (i >= oldLines.length) { // Addition @@ -121,247 +143,291 @@ function DiffViewer({ payload, isLoading = false, onBack }: DiffViewerProps) { } } } - + return diff; }; return generateDiff(); }, [originalFile, modifiedFile, noChanges, isNewFile]); - // Get file path parts + /** + * Get file path parts for display + */ const getFilePath = () => { const parts = fileName.split('/'); return parts.slice(0, -1).join(' / '); }; - // Handle loading state transition + /** + * Handle loading state transition + */ useEffect(() => { setIsRendering(true); const timer = setTimeout(() => setIsRendering(false), 100); return () => clearTimeout(timer); }, [payload]); - const handleComment = () => { - console.log('Comment button clicked'); - alert('Comment functionality not yet implemented'); - }; + /** + * Render a single diff line with syntax highlighting + */ + const renderLine = (line: DiffLine, index: number) => { + const lineStyle = [ + styles.lineContainer, + line.type === 'added' && styles.addedLine, + line.type === 'removed' && styles.removedLine, + ]; + + return ( + + {/* Line numbers */} + + {line.oldLineNumber || ''} + + {line.newLineNumber || ''} + + - const handleApprove = () => { - console.log('Approve button clicked'); - alert('Approve functionality not yet implemented'); + {/* Diff indicator */} + + {line.type === 'added' && +} + {line.type === 'removed' && -} + + + {/* Code content */} + {line.content || ' '} + + ); }; if (isLoading) { return ( -
-
-
-
-
+ + + Loading... + + ); } return ( -
+ {/* Header */} -
-
-
- -
- - - -
-
{fileName}
-
-
-
-
-
- +{stats.additions} -
-
- -{stats.deletions} -
- -
-
+ + + + {onBack && ( + + ← Back + + )} + + + {fileName} + + + + + + +{stats.additions} + + + -{stats.deletions} + + + {/* File Path */} {getFilePath() && ( -
- - - - {getFilePath()} -
+ + + {getFilePath()} + + )} -
+
- {/* Diff Content */} -
+ {/* Diff Content with horizontal and vertical scrolling */} + {noChanges && !isNewFile ? ( -
-
-
- - - -
-
No changes
-
-
+ + + No changes + ) : ( -
- {diffLines.map((line, idx) => ( -
- {/* Line numbers */} -
-
- {line.oldLineNumber || ''} -
-
- {line.newLineNumber || ''} -
-
- - {/* Diff indicator */} -
- {line.type === 'added' ? ( - + - ) : line.type === 'removed' ? ( - - - ) : ( - '' - )} -
- - {/* Code content */} -
- {line.content || ' '} -
-
- ))} -
- )} -
- - {/* Action Bar */} -
-
- - -
-
-
+ {diffLines.map(renderLine)} + + + )} + + ); -} +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#0d1117', + }, + containerLandscape: { + // Landscape-specific adjustments handled by ScrollView + }, + loadingContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + loadingText: { + color: '#9ca3af', + fontSize: 16, + }, + header: { + backgroundColor: '#161b22', + borderBottomWidth: 1, + borderBottomColor: '#30363d', + paddingHorizontal: 16, + paddingVertical: 12, + }, + headerTop: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + }, + headerLeft: { + flexDirection: 'row', + alignItems: 'center', + flex: 1, + minWidth: 0, + }, + backButton: { + color: '#9ca3af', + fontSize: 16, + marginRight: 12, + }, + fileInfo: { + flex: 1, + minWidth: 0, + marginLeft: 8, + }, + fileName: { + color: '#ffffff', + fontSize: 16, + fontWeight: '600', + }, + statsContainer: { + flexDirection: 'row', + gap: 8, + marginLeft: 12, + }, + additionsBadge: { + backgroundColor: 'rgba(76, 175, 80, 0.2)', + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 4, + }, + additionsText: { + color: '#4CAF50', + fontSize: 12, + fontWeight: '600', + }, + deletionsBadge: { + backgroundColor: 'rgba(244, 67, 54, 0.2)', + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 4, + }, + deletionsText: { + color: '#F44336', + fontSize: 12, + fontWeight: '600', + }, + filePathContainer: { + marginTop: 8, + }, + filePath: { + color: '#6b7280', + fontSize: 12, + fontFamily: 'monospace', + }, + diffContainer: { + flex: 1, + }, + noChangesContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + noChangesIcon: { + fontSize: 48, + color: '#6b7280', + marginBottom: 16, + }, + noChangesText: { + color: '#9ca3af', + fontSize: 14, + }, + horizontalScrollContent: { + minWidth: '100%', + }, + verticalScroll: { + flex: 1, + }, + verticalScrollContent: { + paddingBottom: 16, + }, + lineContainer: { + flexDirection: 'row', + minHeight: 24, + paddingVertical: 2, + }, + addedLine: { + backgroundColor: 'rgba(76, 175, 80, 0.15)', + }, + removedLine: { + backgroundColor: 'rgba(244, 67, 54, 0.15)', + }, + lineNumbers: { + flexDirection: 'row', + minWidth: 96, + }, + lineNumber: { + width: 48, + textAlign: 'right', + paddingHorizontal: 8, + color: '#6b7280', + fontSize: 12, + fontFamily: 'monospace', + }, + lineNumberRight: { + borderRightWidth: 1, + borderRightColor: '#30363d', + }, + diffIndicator: { + width: 32, + justifyContent: 'center', + alignItems: 'center', + }, + addedIndicator: { + color: '#4CAF50', + fontSize: 14, + fontWeight: '600', + }, + removedIndicator: { + color: '#F44336', + fontSize: 14, + fontWeight: '600', + }, + lineContent: { + flex: 1, + paddingHorizontal: 8, + color: '#d1d5db', + fontSize: 12, + fontFamily: 'monospace', + }, +}); export default DiffViewer; diff --git a/packages/mobile-client/src/components/EmptyState.tsx b/packages/mobile-client/src/components/EmptyState.tsx new file mode 100644 index 0000000..5e1922e --- /dev/null +++ b/packages/mobile-client/src/components/EmptyState.tsx @@ -0,0 +1,65 @@ +/** + * Empty state component + * Displays helpful messages when no content is available + */ + +import React from 'react'; +import { View, StyleSheet } from 'react-native'; +import { Text, Button } from 'react-native-paper'; +import { MaterialCommunityIcons } from '@expo/vector-icons'; + +export interface EmptyStateProps { + icon: keyof typeof MaterialCommunityIcons.glyphMap; + title: string; + description: string; + actionLabel?: string; + onAction?: () => void; +} + +export const EmptyState: React.FC = ({ + icon, + title, + description, + actionLabel, + onAction, +}) => { + return ( + + + + {title} + + + {description} + + {actionLabel && onAction && ( + + )} + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + padding: 32, + }, + title: { + marginTop: 16, + marginBottom: 8, + textAlign: 'center', + fontWeight: '600', + }, + description: { + textAlign: 'center', + color: '#666', + marginBottom: 24, + }, + button: { + marginTop: 8, + }, +}); diff --git a/packages/mobile-client/src/components/ErrorBoundary.test.tsx b/packages/mobile-client/src/components/ErrorBoundary.test.tsx deleted file mode 100644 index f80d0a4..0000000 --- a/packages/mobile-client/src/components/ErrorBoundary.test.tsx +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @vitest-environment jsdom - */ -import { describe, it, expect, vi } from 'vitest'; -import { render, screen } from '@testing-library/react'; -import { Component, ReactNode } from 'react'; - -// Error Boundary component for testing -class ErrorBoundary extends Component< - { children: ReactNode; fallback?: ReactNode }, - { hasError: boolean; error: Error | null } -> { - constructor(props: { children: ReactNode; fallback?: ReactNode }) { - super(props); - this.state = { hasError: false, error: null }; - } - - static getDerivedStateFromError(error: Error) { - return { hasError: true, error }; - } - - componentDidCatch(error: Error, errorInfo: any) { - console.error('ErrorBoundary caught error:', error, errorInfo); - } - - render() { - if (this.state.hasError) { - return this.props.fallback ||
Something went wrong
; - } - - return this.props.children; - } -} - -// Component that throws an error -const ThrowError = ({ shouldThrow }: { shouldThrow: boolean }) => { - if (shouldThrow) { - throw new Error('Test error'); - } - return
No error
; -}; - -describe('React Error Boundary', () => { - it('should catch render errors', () => { - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - render( - - - - ); - - expect(screen.getByText('Something went wrong')).toBeTruthy(); - - consoleSpy.mockRestore(); - }); - - it('should render children when no error occurs', () => { - render( - - - - ); - - expect(screen.getByText('No error')).toBeTruthy(); - }); - - it('should render custom fallback UI', () => { - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - const customFallback =
Custom error message
; - - render( - - - - ); - - expect(screen.getByText('Custom error message')).toBeTruthy(); - - consoleSpy.mockRestore(); - }); - - it('should log error to console', () => { - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - render( - - - - ); - - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('ErrorBoundary caught error'), - expect.any(Error), - expect.any(Object) - ); - - consoleSpy.mockRestore(); - }); - - it('should prevent app crash on component error', () => { - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - // Should not throw, should render fallback instead - expect(() => { - render( - - - - ); - }).not.toThrow(); - - consoleSpy.mockRestore(); - }); -}); diff --git a/packages/mobile-client/src/components/ErrorBoundary.tsx b/packages/mobile-client/src/components/ErrorBoundary.tsx index 98ff6fe..ca2f94b 100644 --- a/packages/mobile-client/src/components/ErrorBoundary.tsx +++ b/packages/mobile-client/src/components/ErrorBoundary.tsx @@ -1,8 +1,9 @@ -import { Component, ReactNode } from 'react'; +import React, { Component, ReactNode } from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import { Button } from 'react-native-paper'; interface ErrorBoundaryProps { children: ReactNode; - fallback?: ReactNode; } interface ErrorBoundaryState { @@ -10,47 +11,45 @@ interface ErrorBoundaryState { error: Error | null; } -/** - * Error Boundary component to catch and handle React errors - * Prevents the entire app from crashing when a component error occurs - */ -class ErrorBoundary extends Component { +export class ErrorBoundary extends Component { constructor(props: ErrorBoundaryProps) { super(props); - this.state = { hasError: false, error: null }; + this.state = { + hasError: false, + error: null, + }; } static getDerivedStateFromError(error: Error): ErrorBoundaryState { - // Update state so the next render will show the fallback UI - return { hasError: true, error }; + return { + hasError: true, + error, + }; } - componentDidCatch(error: Error, errorInfo: any) { - // Log error details to console for debugging - console.error('ErrorBoundary caught error:', error, errorInfo); + componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void { + console.error('ErrorBoundary caught an error:', error, errorInfo); } - render() { - if (this.state.hasError) { - // Render custom fallback UI if provided, otherwise default error message - if (this.props.fallback) { - return this.props.fallback; - } + handleReset = (): void => { + this.setState({ + hasError: false, + error: null, + }); + }; + render(): ReactNode { + if (this.state.hasError) { return ( -
-
⚠️
-

Something went wrong

-

- An error occurred while rendering this component. -

- -
+ + Something went wrong + + {this.state.error?.message || 'An unexpected error occurred'} + + + ); } @@ -58,4 +57,27 @@ class ErrorBoundary extends Component { } } -export default ErrorBoundary; +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + padding: 20, + backgroundColor: '#fff', + }, + title: { + fontSize: 24, + fontWeight: 'bold', + marginBottom: 16, + color: '#d32f2f', + }, + message: { + fontSize: 16, + textAlign: 'center', + marginBottom: 24, + color: '#666', + }, + button: { + marginTop: 16, + }, +}); diff --git a/packages/mobile-client/src/components/PromptComposer.tsx b/packages/mobile-client/src/components/PromptComposer.tsx new file mode 100644 index 0000000..12cf598 --- /dev/null +++ b/packages/mobile-client/src/components/PromptComposer.tsx @@ -0,0 +1,391 @@ +import React, { useState, useEffect } from 'react'; +import { View, StyleSheet, ScrollView, Alert } from 'react-native'; +import { + TextInput, + Button, + Text, + HelperText, + IconButton, + Chip, + Portal, + Modal, +} from 'react-native-paper'; +import * as Haptics from 'expo-haptics'; +import { useOrientation } from '../hooks'; +import { useDraftPrompt } from '../hooks/useDraftPrompt'; +import { usePromptHistory } from '../hooks/usePromptHistory'; +import { PromptTemplates } from './PromptTemplates'; + +/** + * PromptComposer component props + */ +export interface PromptComposerProps { + onSubmit: (prompt: string) => void; + isLoading: boolean; + error: string | null; +} + +/** + * PromptComposer component for composing and submitting prompts + * Provides real-time character count, validation, and loading states + * Supports both portrait and landscape orientations with responsive layout + * + * Requirements: 1.1, 1.2, 1.4, 1.5, 10.1, 10.2, 10.4, 10.5 + */ +export const PromptComposer: React.FC = ({ onSubmit, isLoading, error }) => { + const { draft, setDraft, clearDraft, isSaving, lastSaved } = useDraftPrompt(); + const { history, addToHistory } = usePromptHistory(); + const [prompt, setPrompt] = useState(draft); + const [charCount, setCharCount] = useState(draft.length); + const [validationError, setValidationError] = useState(null); + const { isLandscape } = useOrientation(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_menuVisible, _setMenuVisible] = useState(false); + const [historyVisible, setHistoryVisible] = useState(false); + const [templatesVisible, setTemplatesVisible] = useState(false); + + const MAX_CHARS = 5000; + const WARNING_THRESHOLD = 0.8; + + // Sync with draft + useEffect(() => { + setDraft(prompt); + }, [prompt, setDraft]); + + /** + * Handle text input changes + * Updates prompt state and character count + * Requirement 1.2: Real-time character count feedback + */ + const handleTextChange = (text: string) => { + if (text.length <= MAX_CHARS) { + setPrompt(text); + setCharCount(text.length); + + // Clear validation error when user starts typing + if (validationError) { + setValidationError(null); + } + } + }; + + /** + * Validate prompt before submission + * Requirement 1.4: Reject empty/whitespace prompts + */ + const validatePrompt = (text: string): boolean => { + if (text.trim().length === 0) { + setValidationError('Prompt cannot be empty or contain only whitespace'); + return false; + } + return true; + }; + + /** + * Handle prompt submission + * Requirement 1.3: Create INJECT_PROMPT message + * Requirement 1.4: Prevent submission of empty prompts + */ + const handleSubmit = async () => { + if (!validatePrompt(prompt)) { + return; + } + + // Haptic feedback + await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + + // Add to history + await addToHistory({ + id: Date.now().toString(), + prompt, + timestamp: Date.now(), + }); + + onSubmit(prompt); + + // Clear draft after successful submission + await clearDraft(); + setPrompt(''); + setCharCount(0); + }; + + /** + * Handle template selection + */ + const handleSelectTemplate = (template: string) => { + setPrompt(template); + setCharCount(template.length); + setTemplatesVisible(false); + }; + + /** + * Handle history item selection + */ + const handleSelectHistory = (item: string) => { + setPrompt(item); + setCharCount(item.length); + setHistoryVisible(false); + }; + + /** + * Clear current prompt + */ + const handleClear = () => { + Alert.alert('Clear Prompt', 'Are you sure you want to clear the current prompt?', [ + { text: 'Cancel', style: 'cancel' }, + { + text: 'Clear', + style: 'destructive', + onPress: async () => { + setPrompt(''); + setCharCount(0); + await clearDraft(); + }, + }, + ]); + }; + + const isNearLimit = charCount >= MAX_CHARS * WARNING_THRESHOLD; + const isAtLimit = charCount >= MAX_CHARS; + + return ( + + {/* Toolbar */} + + + setHistoryVisible(true)} + disabled={history.length === 0} + /> + setTemplatesVisible(true)} + /> + + + {isSaving && Saving...} + {lastSaved && !isSaving && Saved} + + + + + {/* Multiline text input for prompt composition */} + {/* Requirement 1.1: Multi-line prompt input */} + {/* Requirement 10.4: Accessible in both orientations */} + + + {/* Character count display */} + {/* Requirement 1.2: Real-time character count feedback */} + + + {charCount} / {MAX_CHARS} characters + + {isNearLimit && !isAtLimit && ( + + Approaching limit + + )} + {isAtLimit && ( + + Character limit reached + + )} + + + {/* Validation error display */} + {/* Requirement 1.4: Display validation message */} + {validationError && ( + + {validationError} + + )} + + {/* External error display */} + {error && ( + + {error} + + )} + + {/* Submit button with loading state */} + {/* Requirement 1.5: Disable button and show loading indicator during submission */} + {/* Requirement 10.4: Accessible in both orientations */} + + + {/* History Modal */} + + setHistoryVisible(false)} + contentContainerStyle={styles.modalContent} + > + + Prompt History + + + {history.map((item) => ( + + ))} + + + + + + {/* Templates Modal */} + + setTemplatesVisible(false)} + contentContainerStyle={styles.modalContent} + > + + + + + + ); +}; + +const styles = StyleSheet.create({ + scrollView: { + flex: 1, + }, + container: { + padding: 16, + backgroundColor: '#fff', + flexGrow: 1, + }, + containerLandscape: { + paddingHorizontal: 32, + paddingVertical: 16, + }, + toolbar: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 8, + }, + toolbarLeft: { + flexDirection: 'row', + }, + toolbarRight: { + flexDirection: 'row', + alignItems: 'center', + }, + savingText: { + fontSize: 12, + color: '#666', + marginRight: 8, + }, + savedText: { + fontSize: 12, + color: '#4CAF50', + marginRight: 8, + }, + input: { + marginBottom: 8, + minHeight: 150, + }, + inputLandscape: { + minHeight: 100, + }, + charCountContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 8, + }, + charCount: { + fontSize: 12, + color: '#666', + }, + charCountWarning: { + color: '#FF9800', + fontWeight: '600', + }, + charCountError: { + color: '#F44336', + fontWeight: '600', + }, + warningChip: { + backgroundColor: '#FFF3E0', + }, + errorChip: { + backgroundColor: '#FFEBEE', + }, + submitButton: { + marginTop: 16, + }, + buttonContent: { + paddingVertical: 8, + }, + modalContent: { + backgroundColor: 'white', + padding: 20, + margin: 20, + borderRadius: 8, + maxHeight: '80%', + }, + modalTitle: { + marginBottom: 16, + fontWeight: '600', + }, + historyList: { + maxHeight: 400, + marginBottom: 16, + }, + historyItem: { + marginBottom: 8, + justifyContent: 'flex-start', + }, + closeButton: { + marginTop: 8, + }, +}); diff --git a/packages/mobile-client/src/components/PromptResponseDisplay.tsx b/packages/mobile-client/src/components/PromptResponseDisplay.tsx new file mode 100644 index 0000000..1078733 --- /dev/null +++ b/packages/mobile-client/src/components/PromptResponseDisplay.tsx @@ -0,0 +1,87 @@ +import React, { useEffect } from 'react'; +import { StyleSheet } from 'react-native'; +import { Snackbar } from 'react-native-paper'; +import { InjectPromptResponse } from '@codelink/protocol'; + +/** + * PromptResponseDisplay component props + */ +export interface PromptResponseDisplayProps { + response: InjectPromptResponse | null; + onDismiss: () => void; + duration?: number; +} + +/** + * PromptResponseDisplay component for displaying prompt submission results + * Shows success/error messages with editor identification + * Auto-dismisses after configured duration + * + * Requirements: 3.2, 3.3, 4.1, 4.3 + */ +export const PromptResponseDisplay: React.FC = ({ + response, + onDismiss, + duration = 4000, +}) => { + // Auto-dismiss after duration + useEffect(() => { + if (response) { + const timer = setTimeout(() => { + onDismiss(); + }, duration); + + return () => clearTimeout(timer); + } + }, [response, duration, onDismiss]); + + if (!response) { + return null; + } + + const { success, error, editorUsed } = response.payload; + + /** + * Format success message with editor name if available + * Requirement 3.2: Display success notification with editor name + * Requirement 4.1: Display editor name prominently + */ + const getSuccessMessage = (): string => { + if (editorUsed) { + return `✓ Prompt processed successfully by ${editorUsed}`; + } + return '✓ Prompt processed successfully'; + }; + + /** + * Format error message + * Requirement 3.3: Display error message from error field + */ + const getErrorMessage = (): string => { + return `✗ Error: ${error || 'Unknown error occurred'}`; + }; + + return ( + + {success ? getSuccessMessage() : getErrorMessage()} + + ); +}; + +const styles = StyleSheet.create({ + success: { + backgroundColor: '#4CAF50', // Green for success + }, + error: { + backgroundColor: '#F44336', // Red for error + }, +}); diff --git a/packages/mobile-client/src/components/PromptTemplates.tsx b/packages/mobile-client/src/components/PromptTemplates.tsx new file mode 100644 index 0000000..a566c93 --- /dev/null +++ b/packages/mobile-client/src/components/PromptTemplates.tsx @@ -0,0 +1,144 @@ +/** + * Prompt templates component + * Provides quick access to common prompt templates + */ + +import React from 'react'; +import { View, StyleSheet, ScrollView } from 'react-native'; +import { Card, Text, Chip } from 'react-native-paper'; + +export interface PromptTemplate { + id: string; + title: string; + description: string; + template: string; + category: string; +} + +const TEMPLATES: PromptTemplate[] = [ + { + id: '1', + title: 'Code Review', + description: 'Request a code review', + template: + 'Please review this code for:\n- Best practices\n- Performance issues\n- Security concerns\n- Code style', + category: 'Review', + }, + { + id: '2', + title: 'Bug Fix', + description: 'Report and fix a bug', + template: + 'I found a bug:\n\nSteps to reproduce:\n1. \n2. \n3. \n\nExpected behavior:\n\nActual behavior:\n\nPlease help fix this issue.', + category: 'Bug', + }, + { + id: '3', + title: 'Refactor', + description: 'Request code refactoring', + template: + 'Please refactor this code to:\n- Improve readability\n- Reduce complexity\n- Follow SOLID principles', + category: 'Refactor', + }, + { + id: '4', + title: 'Add Tests', + description: 'Generate unit tests', + template: + 'Please add comprehensive unit tests for this code, including:\n- Happy path scenarios\n- Edge cases\n- Error handling', + category: 'Testing', + }, + { + id: '5', + title: 'Documentation', + description: 'Add code documentation', + template: + 'Please add detailed documentation including:\n- Function/class descriptions\n- Parameter explanations\n- Return value descriptions\n- Usage examples', + category: 'Docs', + }, + { + id: '6', + title: 'Optimize Performance', + description: 'Improve code performance', + template: + 'Please optimize this code for better performance:\n- Reduce time complexity\n- Minimize memory usage\n- Improve algorithm efficiency', + category: 'Performance', + }, +]; + +export interface PromptTemplatesProps { + onSelectTemplate: (template: string) => void; +} + +export const PromptTemplates: React.FC = ({ onSelectTemplate }) => { + const categories = Array.from(new Set(TEMPLATES.map((t) => t.category))); + + return ( + + + Quick Templates + + + + {categories.map((category) => ( + + {category} + + ))} + + + + {TEMPLATES.map((template) => ( + onSelectTemplate(template.template)} + > + + + {template.title} + {template.category} + + + {template.description} + + + + ))} + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + }, + title: { + marginBottom: 12, + fontWeight: '600', + }, + categories: { + marginBottom: 16, + maxHeight: 40, + }, + categoryChip: { + marginRight: 8, + }, + templates: { + flex: 1, + }, + templateCard: { + marginBottom: 12, + }, + templateHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 8, + }, + description: { + color: '#666', + }, +}); diff --git a/packages/mobile-client/src/components/Settings.tsx b/packages/mobile-client/src/components/Settings.tsx new file mode 100644 index 0000000..ee9cd28 --- /dev/null +++ b/packages/mobile-client/src/components/Settings.tsx @@ -0,0 +1,162 @@ +/** + * Settings screen component + * Provides app configuration options + */ + +import React, { useState } from 'react'; +import { View, StyleSheet, ScrollView, Alert } from 'react-native'; +import { List, Button, Divider, RadioButton } from 'react-native-paper'; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { useTheme } from '../hooks/useTheme'; +import { usePromptHistory } from '../hooks/usePromptHistory'; +import { ThemeMode } from '../theme'; + +export const Settings: React.FC = () => { + const { themeMode, setThemeMode } = useTheme(); + const { clearHistory } = usePromptHistory(); + const [fontSize, setFontSize] = useState<'small' | 'medium' | 'large'>('medium'); + + const handleClearCache = async () => { + Alert.alert('Clear Cache', 'Are you sure you want to clear all cached data?', [ + { text: 'Cancel', style: 'cancel' }, + { + text: 'Clear', + style: 'destructive', + onPress: async () => { + try { + await AsyncStorage.clear(); + Alert.alert('Success', 'Cache cleared successfully'); + } catch (error) { + Alert.alert('Error', 'Failed to clear cache'); + } + }, + }, + ]); + }; + + const handleClearHistory = () => { + Alert.alert('Clear History', 'Are you sure you want to clear all prompt history?', [ + { text: 'Cancel', style: 'cancel' }, + { + text: 'Clear', + style: 'destructive', + onPress: async () => { + await clearHistory(); + Alert.alert('Success', 'History cleared successfully'); + }, + }, + ]); + }; + + return ( + + {/* Appearance Section */} + + Appearance + + } + /> + setThemeMode(value as ThemeMode)} + value={themeMode} + > + + + + + + + + + + } + /> + setFontSize(value as 'small' | 'medium' | 'large')} + value={fontSize} + > + + + + + + + + + + + {/* Data & Privacy Section */} + + Data & Privacy + + } + right={(_props) => ( + + )} + /> + + } + right={(_props) => ( + + )} + /> + + + + + {/* About Section */} + + About + + } + /> + + } + /> + + + + Made with ❤️ for developers + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + radioGroup: { + paddingLeft: 16, + }, + footer: { + padding: 32, + alignItems: 'center', + }, + footerText: { + fontSize: 12, + color: '#666', + }, +}); diff --git a/packages/mobile-client/src/components/index.ts b/packages/mobile-client/src/components/index.ts new file mode 100644 index 0000000..2f9dd97 --- /dev/null +++ b/packages/mobile-client/src/components/index.ts @@ -0,0 +1,19 @@ +// Component exports +// This file will export all React Native components + +export { Dashboard } from './Dashboard'; +export type { DashboardProps, SystemMetrics, ActivityItem } from './Dashboard'; +export { DiffViewer } from './DiffViewer'; +export type { DiffViewerProps } from './DiffViewer'; +export { PromptComposer } from './PromptComposer'; +export type { PromptComposerProps } from './PromptComposer'; +export { PromptResponseDisplay } from './PromptResponseDisplay'; +export type { PromptResponseDisplayProps } from './PromptResponseDisplay'; +export { ErrorBoundary } from './ErrorBoundary'; +export { EmptyState } from './EmptyState'; +export type { EmptyStateProps } from './EmptyState'; +export { Settings } from './Settings'; +export { PromptTemplates } from './PromptTemplates'; +export type { PromptTemplate, PromptTemplatesProps } from './PromptTemplates'; +export { AppLoading } from './AppLoading'; +export type { AppLoadingProps } from './AppLoading'; diff --git a/packages/mobile-client/src/config/README.md b/packages/mobile-client/src/config/README.md new file mode 100644 index 0000000..1760d25 --- /dev/null +++ b/packages/mobile-client/src/config/README.md @@ -0,0 +1,114 @@ +# Configuration Module + +This module provides centralized configuration management for the mobile client application. + +## Usage + +### Basic Usage + +```typescript +import { getConfig } from './config'; + +const config = getConfig(); +console.log(config.relayServerUrl); // ws://localhost:3000 +console.log(config.socketOptions.reconnectionAttempts); // 5 +``` + +### Environment Variables + +The relay server URL can be configured via: + +1. **Environment variable** (highest priority): + + ```bash + RELAY_SERVER_URL=ws://production-server:3000 npm start + ``` + +2. **app.json extra field** (medium priority): + + ```json + { + "expo": { + "extra": { + "relayServerUrl": "ws://staging-server:3000" + } + } + } + ``` + +3. **Default value** (lowest priority): + ``` + ws://localhost:3000 + ``` + +### Runtime Configuration Updates + +For testing or dynamic configuration: + +```typescript +import { updateConfig } from './config'; + +updateConfig({ + relayServerUrl: 'ws://test-server:4000', + socketOptions: { + reconnectionAttempts: 10, + }, +}); +``` + +## Configuration Reference + +### `relayServerUrl` + +- **Type**: `string` +- **Default**: `ws://localhost:3000` +- **Description**: WebSocket URL for the relay server +- **Requirements**: 2.1 + +### `socketOptions` + +#### `reconnection` + +- **Type**: `boolean` +- **Default**: `true` +- **Description**: Enable automatic reconnection +- **Requirements**: 8.4 + +#### `reconnectionAttempts` + +- **Type**: `number` +- **Default**: `5` +- **Description**: Maximum number of reconnection attempts +- **Requirements**: 8.4 + +#### `reconnectionDelay` + +- **Type**: `number` +- **Default**: `1000` (ms) +- **Description**: Delay between reconnection attempts + +#### `timeout` + +- **Type**: `number` +- **Default**: `20000` (ms) +- **Description**: Connection timeout + +### `ui` + +#### `maxPromptLength` + +- **Type**: `number` +- **Default**: `5000` +- **Description**: Maximum characters allowed in a prompt + +#### `diffHistoryLimit` + +- **Type**: `number` +- **Default**: `50` +- **Description**: Maximum number of diffs to keep in history + +#### `notificationDuration` + +- **Type**: `number` +- **Default**: `4000` (ms) +- **Description**: Duration to show notifications diff --git a/packages/mobile-client/src/config/index.ts b/packages/mobile-client/src/config/index.ts new file mode 100644 index 0000000..5b66b11 --- /dev/null +++ b/packages/mobile-client/src/config/index.ts @@ -0,0 +1,85 @@ +import Constants from 'expo-constants'; + +/** + * Application configuration interface + */ +export interface AppConfig { + relayServerUrl: string; + socketOptions: { + reconnection: boolean; + reconnectionAttempts: number; + reconnectionDelay: number; + timeout: number; + }; + ui: { + maxPromptLength: number; + diffHistoryLimit: number; + notificationDuration: number; + }; +} + +/** + * Get relay server URL from environment or configuration + * Priority: Environment variable > app.json extra > default + */ +const getRelayServerUrl = (): string => { + // Check for environment variable (for development/testing) + if (process.env.RELAY_SERVER_URL) { + return process.env.RELAY_SERVER_URL; + } + + // Check Expo Constants for app.json extra configuration + const expoConfig = Constants.expoConfig; + if (expoConfig?.extra?.relayServerUrl) { + return expoConfig.extra.relayServerUrl; + } + + // Fallback to default + return 'ws://localhost:8080'; +}; + +/** + * Default application configuration + * + * Configuration values: + * - relayServerUrl: WebSocket URL for the relay server + * - socketOptions.reconnection: Enable automatic reconnection + * - socketOptions.reconnectionAttempts: Maximum reconnection attempts (Requirement 8.4) + * - socketOptions.reconnectionDelay: Delay between reconnection attempts in ms + * - socketOptions.timeout: Connection timeout in ms + * - ui.maxPromptLength: Maximum characters allowed in a prompt + * - ui.diffHistoryLimit: Maximum number of diffs to keep in history + * - ui.notificationDuration: Duration to show notifications in ms + */ +export const defaultConfig: AppConfig = { + relayServerUrl: getRelayServerUrl(), + socketOptions: { + reconnection: true, + reconnectionAttempts: 5, + reconnectionDelay: 1000, + timeout: 20000, + }, + ui: { + maxPromptLength: 5000, + diffHistoryLimit: 50, + notificationDuration: 4000, + }, +}; + +/** + * Get the current application configuration + * @returns AppConfig object with all configuration values + */ +export const getConfig = (): AppConfig => { + return defaultConfig; +}; + +/** + * Update configuration at runtime (useful for testing) + * @param updates Partial configuration updates to apply + * @returns Updated AppConfig object + */ +export const updateConfig = (updates: Partial): AppConfig => { + Object.assign(defaultConfig, updates); + return defaultConfig; +}; diff --git a/packages/mobile-client/src/design-system/components/Button.tsx b/packages/mobile-client/src/design-system/components/Button.tsx new file mode 100644 index 0000000..e27f7c3 --- /dev/null +++ b/packages/mobile-client/src/design-system/components/Button.tsx @@ -0,0 +1,406 @@ +/** + * Button Component + * + * A versatile button component with multiple variants, sizes, and states. + * Supports icons, loading states, haptic feedback, and press animations. + * + * Requirements: 10.1, 12.3, 12.9 + */ + +import React, { useRef } from 'react'; +import { + TouchableOpacity, + View, + Text, + StyleSheet, + Animated, + ActivityIndicator, + StyleProp, + ViewStyle, + Platform, +} from 'react-native'; +import * as Haptics from 'expo-haptics'; +import { LinearGradient } from 'expo-linear-gradient'; +import { useDesignSystem } from '../theme/useDesignSystem'; + +/** + * Button variant types + * - primary: Gradient background (primary to primaryContainer) + * - secondary: Secondary color background + * - tertiary: Transparent with secondary text + * - ghost: Transparent with outline + */ +export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'ghost'; + +/** + * Button size variants + * - sm: Small button (32px height) + * - md: Medium button (44px height) - default + * - lg: Large button (56px height) + */ +export type ButtonSize = 'sm' | 'md' | 'lg'; + +/** + * Icon position within button + */ +export type IconPosition = 'left' | 'right'; + +/** + * Haptic feedback intensity + */ +export type HapticFeedback = 'light' | 'medium' | 'heavy'; + +export interface ButtonProps { + /** + * Button variant style + * @default 'primary' + */ + variant?: ButtonVariant; + + /** + * Button size + * @default 'md' + */ + size?: ButtonSize; + + /** + * Icon component to display (Material Symbols or custom) + */ + icon?: React.ReactNode; + + /** + * Position of icon relative to text + * @default 'left' + */ + iconPosition?: IconPosition; + + /** + * Disabled state + * @default false + */ + disabled?: boolean; + + /** + * Loading state - shows spinner and disables interaction + * @default false + */ + loading?: boolean; + + /** + * Make button full width of container + * @default false + */ + fullWidth?: boolean; + + /** + * Press handler + */ + onPress: () => void; + + /** + * Button label text + */ + children: React.ReactNode; + + /** + * Custom style overrides + */ + style?: StyleProp; + + /** + * Haptic feedback intensity on press + * @default 'light' + */ + hapticFeedback?: HapticFeedback; +} + +/** + * Button component with variants, sizes, and animations + */ +export const Button: React.FC = ({ + variant = 'primary', + size = 'md', + icon, + iconPosition = 'left', + disabled = false, + loading = false, + fullWidth = false, + onPress, + children, + style, + hapticFeedback = 'light', +}) => { + const { theme } = useDesignSystem(); + const scaleAnim = useRef(new Animated.Value(1)).current; + + // Determine if button is interactive + const isInteractive = !disabled && !loading; + + /** + * Handle press in - start scale animation + */ + const handlePressIn = () => { + if (!isInteractive) return; + + Animated.spring(scaleAnim, { + toValue: 0.95, + useNativeDriver: true, + tension: 300, + friction: 10, + }).start(); + }; + + /** + * Handle press out - reset scale animation + */ + const handlePressOut = () => { + if (!isInteractive) return; + + Animated.spring(scaleAnim, { + toValue: 1, + useNativeDriver: true, + tension: 300, + friction: 10, + }).start(); + }; + + /** + * Handle press - trigger haptic feedback and callback + */ + const handlePress = () => { + if (!isInteractive) return; + + // Trigger haptic feedback + if (Platform.OS === 'ios' || Platform.OS === 'android') { + switch (hapticFeedback) { + case 'light': + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); + break; + case 'medium': + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + break; + case 'heavy': + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy); + break; + } + } + + onPress(); + }; + + /** + * Get button height based on size + */ + const getHeight = (): number => { + switch (size) { + case 'sm': + return 32; + case 'md': + return 44; + case 'lg': + return 56; + } + }; + + /** + * Get horizontal padding based on size + */ + const getPaddingHorizontal = (): number => { + switch (size) { + case 'sm': + return theme.spacing.md; + case 'md': + return theme.spacing.lg; + case 'lg': + return theme.spacing.xl; + } + }; + + /** + * Get font size based on size + */ + const getFontSize = (): number => { + switch (size) { + case 'sm': + return theme.typography.sizes.labelMd; + case 'md': + return theme.typography.sizes.labelLg; + case 'lg': + return theme.typography.sizes.titleSm; + } + }; + + /** + * Get text color based on variant and state + */ + const getTextColor = (): string => { + if (disabled) { + return theme.colors.onSurfaceVariant; + } + + switch (variant) { + case 'primary': + return theme.colors.onPrimary; + case 'secondary': + return theme.colors.onSecondary; + case 'tertiary': + case 'ghost': + return theme.colors.secondary; + } + }; + + /** + * Render button content (icon + text + loading spinner) + */ + const renderContent = () => { + const textColor = getTextColor(); + const fontSize = getFontSize(); + + return ( + + {/* Left icon */} + {icon && iconPosition === 'left' && !loading && {icon}} + + {/* Loading spinner */} + {loading && } + + {/* Button text */} + + {children} + + + {/* Right icon */} + {icon && iconPosition === 'right' && !loading && ( + {icon} + )} + + ); + }; + + /** + * Render button based on variant + */ + const renderButton = () => { + const height = getHeight(); + const paddingHorizontal = getPaddingHorizontal(); + + const baseStyle = [ + styles.button, + { + height, + paddingHorizontal, + borderRadius: theme.borderRadius.lg, + opacity: disabled ? 0.5 : 1, + }, + fullWidth && styles.fullWidth, + style, + ]; + + // Primary variant with gradient + if (variant === 'primary') { + return ( + + {renderContent()} + + ); + } + + // Secondary variant with solid background + if (variant === 'secondary') { + return ( + + {renderContent()} + + ); + } + + // Tertiary variant with transparent background + if (variant === 'tertiary') { + return {renderContent()}; + } + + // Ghost variant with outline + if (variant === 'ghost') { + return ( + + {renderContent()} + + ); + } + }; + + return ( + + + {renderButton()} + + + ); +}; + +const styles = StyleSheet.create({ + button: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + overflow: 'hidden', + }, + fullWidth: { + width: '100%', + }, + contentContainer: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + text: { + textAlign: 'center', + textTransform: 'uppercase', + letterSpacing: 0.5, + }, + iconLeft: { + marginRight: 8, + }, + iconRight: { + marginLeft: 8, + }, + spinner: { + marginRight: 8, + }, +}); diff --git a/packages/mobile-client/src/design-system/components/Card.tsx b/packages/mobile-client/src/design-system/components/Card.tsx new file mode 100644 index 0000000..6a0d4eb --- /dev/null +++ b/packages/mobile-client/src/design-system/components/Card.tsx @@ -0,0 +1,150 @@ +/** + * Card Component + * + * A versatile card component with surface hierarchy variants for tonal layering. + * Supports custom padding, border radius, elevation, and optional press interaction. + * + * Requirements: 10.2 + */ + +import React from 'react'; +import { View, TouchableOpacity, StyleSheet, StyleProp, ViewStyle } from 'react-native'; +import { useDesignSystem } from '../theme/useDesignSystem'; +import type { SpacingTokens } from '../tokens/spacing'; +import type { BorderRadiusTokens } from '../tokens/borderRadius'; + +/** + * Card variant types mapping to surface hierarchy + * - lowest: surfaceContainerLowest (code blocks, deepest depth) + * - low: surfaceContainerLow (cards on surface) + * - default: surfaceContainer (standard containers) + * - high: surfaceContainerHigh (elevated elements) + * - highest: surfaceContainerHighest (inputs, inactive states) + */ +export type CardVariant = 'lowest' | 'low' | 'default' | 'high' | 'highest'; + +export interface CardProps { + /** + * Card variant mapping to surface hierarchy + * @default 'default' + */ + variant?: CardVariant; + + /** + * Padding size using spacing tokens + * @default 'lg' + */ + padding?: keyof SpacingTokens; + + /** + * Border radius size using border radius tokens + * @default 'lg' + */ + borderRadius?: keyof BorderRadiusTokens; + + /** + * Elevation level (shadow depth) + * Note: Tonal layering is preferred over elevation in Obsidian design + * @default 0 + */ + elevation?: number; + + /** + * Card content + */ + children: React.ReactNode; + + /** + * Custom style overrides + */ + style?: StyleProp; + + /** + * Optional press handler for interactive cards + * When provided, card becomes touchable with press feedback + */ + onPress?: () => void; +} + +/** + * Card component with surface hierarchy variants + */ +export const Card: React.FC = ({ + variant = 'default', + padding = 'lg', + borderRadius = 'lg', + elevation = 0, + children, + style, + onPress, +}) => { + const { theme } = useDesignSystem(); + + /** + * Get background color based on variant (surface hierarchy) + */ + const getBackgroundColor = (): string => { + switch (variant) { + case 'lowest': + return theme.colors.surfaceContainerLowest; + case 'low': + return theme.colors.surfaceContainerLow; + case 'default': + return theme.colors.surfaceContainer; + case 'high': + return theme.colors.surfaceContainerHigh; + case 'highest': + return theme.colors.surfaceContainerHighest; + } + }; + + /** + * Get padding value from spacing tokens + */ + const getPadding = (): number => { + return theme.spacing[padding]; + }; + + /** + * Get border radius value from border radius tokens + */ + const getBorderRadius = (): number => { + return theme.borderRadius[borderRadius]; + }; + + /** + * Build card style + */ + const cardStyle: StyleProp = [ + styles.card, + { + backgroundColor: getBackgroundColor(), + padding: getPadding(), + borderRadius: getBorderRadius(), + elevation, + }, + style, + ]; + + /** + * Render card as touchable if onPress is provided + */ + if (onPress) { + return ( + + {children} + + ); + } + + /** + * Render card as static view + */ + return {children}; +}; + +const styles = StyleSheet.create({ + card: { + overflow: 'hidden', + }, +}); diff --git a/packages/mobile-client/src/design-system/components/Chip.tsx b/packages/mobile-client/src/design-system/components/Chip.tsx new file mode 100644 index 0000000..0df7415 --- /dev/null +++ b/packages/mobile-client/src/design-system/components/Chip.tsx @@ -0,0 +1,313 @@ +/** + * Chip Component + * + * A compact, interactive chip component for tags, filters, and selections. + * Supports icons, selected states, variants, and haptic feedback. + * + * Requirements: 10.3, 5.11 + */ + +import React from 'react'; +import { + TouchableOpacity, + View, + Text, + StyleSheet, + StyleProp, + ViewStyle, + Platform, +} from 'react-native'; +import * as Haptics from 'expo-haptics'; +import { useDesignSystem } from '../theme/useDesignSystem'; + +/** + * Chip variant types + * - default: Standard chip with surface colors + * - success: Success state with secondary (green) color + * - error: Error state with error (red) color + * - warning: Warning state with tertiary (orange) color + */ +export type ChipVariant = 'default' | 'success' | 'error' | 'warning'; + +/** + * Chip size variants + * - sm: Small chip (24px height) + * - md: Medium chip (32px height) - default + */ +export type ChipSize = 'sm' | 'md'; + +export interface ChipProps { + /** + * Chip label text + */ + label: string; + + /** + * Optional icon component to display (Material Symbols or custom) + */ + icon?: React.ReactNode; + + /** + * Selected state - highlights chip with secondary color + * @default false + */ + selected?: boolean; + + /** + * Chip variant for different semantic states + * @default 'default' + */ + variant?: ChipVariant; + + /** + * Chip size + * @default 'md' + */ + size?: ChipSize; + + /** + * Optional press handler for interactive chips + */ + onPress?: () => void; + + /** + * Custom style overrides + */ + style?: StyleProp; +} + +/** + * Chip component for tags, filters, and selections + */ +export const Chip: React.FC = ({ + label, + icon, + selected = false, + variant = 'default', + size = 'md', + onPress, + style, +}) => { + const { theme } = useDesignSystem(); + + /** + * Handle press - trigger haptic feedback and callback + */ + const handlePress = () => { + if (!onPress) return; + + // Trigger haptic feedback on press + if (Platform.OS === 'ios' || Platform.OS === 'android') { + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); + } + + onPress(); + }; + + /** + * Get chip height based on size + */ + const getHeight = (): number => { + switch (size) { + case 'sm': + return 24; + case 'md': + return 32; + } + }; + + /** + * Get horizontal padding based on size + */ + const getPaddingHorizontal = (): number => { + switch (size) { + case 'sm': + return theme.spacing.sm; + case 'md': + return theme.spacing.md; + } + }; + + /** + * Get font size based on size + */ + const getFontSize = (): number => { + switch (size) { + case 'sm': + return theme.typography.sizes.labelSm; + case 'md': + return theme.typography.sizes.labelMd; + } + }; + + /** + * Get icon size based on chip size + */ + const getIconSize = (): number => { + switch (size) { + case 'sm': + return 14; + case 'md': + return 16; + } + }; + + /** + * Get background color based on variant and selected state + */ + const getBackgroundColor = (): string => { + // Selected state always uses secondary color + if (selected) { + return theme.colors.secondary; + } + + // Variant colors for unselected state + switch (variant) { + case 'default': + return theme.colors.surfaceContainerHigh; + case 'success': + return `${theme.colors.secondary}26`; // 15% opacity + case 'error': + return `${theme.colors.error}26`; // 15% opacity + case 'warning': + return `${theme.colors.tertiary}26`; // 15% opacity + } + }; + + /** + * Get text color based on variant and selected state + */ + const getTextColor = (): string => { + // Selected state uses onSecondary color + if (selected) { + return theme.colors.onSecondary; + } + + // Variant colors for unselected state + switch (variant) { + case 'default': + return theme.colors.onSurface; + case 'success': + return theme.colors.secondary; + case 'error': + return theme.colors.error; + case 'warning': + return theme.colors.tertiary; + } + }; + + /** + * Get border color based on variant and selected state + */ + const getBorderColor = (): string | undefined => { + // Selected state has no border + if (selected) { + return undefined; + } + + // Variant border colors for unselected state + switch (variant) { + case 'default': + return theme.colors.outline; + case 'success': + return theme.colors.secondary; + case 'error': + return theme.colors.error; + case 'warning': + return theme.colors.tertiary; + } + }; + + const height = getHeight(); + const paddingHorizontal = getPaddingHorizontal(); + const fontSize = getFontSize(); + const iconSize = getIconSize(); + const backgroundColor = getBackgroundColor(); + const textColor = getTextColor(); + const borderColor = getBorderColor(); + + const chipStyle: StyleProp = [ + styles.chip, + { + height, + paddingHorizontal, + backgroundColor, + borderRadius: theme.borderRadius.full, // rounded-full + borderWidth: borderColor ? 1 : 0, + borderColor, + }, + style, + ]; + + /** + * Render chip content (icon + label) + */ + const renderContent = () => ( + + {/* Icon */} + {icon && ( + {icon} + )} + + {/* Label */} + + {label} + + + ); + + /** + * Render chip as touchable if onPress is provided + */ + if (onPress) { + return ( + + {renderContent()} + + ); + } + + /** + * Render chip as static view + */ + return {renderContent()}; +}; + +const styles = StyleSheet.create({ + chip: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + alignSelf: 'flex-start', // Don't stretch to full width + }, + contentContainer: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + iconContainer: { + marginRight: 4, + alignItems: 'center', + justifyContent: 'center', + }, + label: { + textTransform: 'uppercase', + letterSpacing: 0.5, + }, +}); diff --git a/packages/mobile-client/src/design-system/components/Icon.tsx b/packages/mobile-client/src/design-system/components/Icon.tsx new file mode 100644 index 0000000..3116f9f --- /dev/null +++ b/packages/mobile-client/src/design-system/components/Icon.tsx @@ -0,0 +1,161 @@ +/** + * Icon Component + * + * A wrapper component for Material Icons with design system integration. + * Supports customization of size, color, fill, and weight. + * + * Requirements: 10.7, 18.11, 18.12 + */ + +import React from 'react'; +import { StyleProp, TextStyle } from 'react-native'; +import { MaterialIcons } from '@expo/vector-icons'; +import { useDesignSystem } from '../theme/useDesignSystem'; +import { ColorTokens } from '../tokens'; + +/** + * Icon weight variants (Material Icons supports limited weights) + */ +export type IconWeight = 100 | 200 | 300 | 400 | 500 | 600 | 700; + +/** + * Material Icons name type + */ +export type IconName = keyof typeof MaterialIcons.glyphMap; + +export interface IconProps { + /** + * Material Icons icon name + */ + name: IconName; + + /** + * Icon size in pixels + * @default 24 + */ + size?: number; + + /** + * Icon color - can be a design token key or hex color + * @default 'onSurface' + */ + color?: keyof ColorTokens | string; + + /** + * Fill style (Material Icons doesn't support variable fill, but we keep for API consistency) + * @default false + */ + fill?: boolean; + + /** + * Icon weight (Material Icons uses regular weight by default) + * @default 400 + */ + weight?: IconWeight; + + /** + * Custom style overrides + */ + style?: StyleProp; +} + +/** + * Icon component wrapping Material Icons with design system integration + */ +export const Icon: React.FC = ({ + name, + size = 24, + color = 'onSurface', + fill: _fill = false, + weight: _weight = 400, + style, +}) => { + const { theme } = useDesignSystem(); + + /** + * Resolve color from design token or use as-is + */ + const resolveColor = (): string => { + // Check if color is a design token key + if (color in theme.colors) { + return theme.colors[color as keyof ColorTokens]; + } + // Otherwise use as hex color + return color; + }; + + const iconColor = resolveColor(); + + /** + * Note: Material Icons from @expo/vector-icons doesn't support variable fill or weight + * like Material Symbols. These props are included for API consistency and future compatibility. + * For now, they don't affect the rendering but can be used for conditional logic if needed. + */ + + return ; +}; + +/** + * Common icon names used in the app + * This provides type-safe shortcuts for frequently used icons + */ +export const IconNames = { + // Navigation + home: 'home' as IconName, + settings: 'settings' as IconName, + + // Actions + send: 'send' as IconName, + close: 'close' as IconName, + check: 'check' as IconName, + add: 'add' as IconName, + remove: 'remove' as IconName, + edit: 'edit' as IconName, + delete: 'delete' as IconName, + refresh: 'refresh' as IconName, + search: 'search' as IconName, + + // Status + checkCircle: 'check-circle' as IconName, + error: 'error' as IconName, + warning: 'warning' as IconName, + info: 'info' as IconName, + + // Files and folders + folder: 'folder' as IconName, + folderOpen: 'folder-open' as IconName, + insertDriveFile: 'insert-drive-file' as IconName, + + // Code and development + code: 'code' as IconName, + terminal: 'terminal' as IconName, + + // Time + schedule: 'schedule' as IconName, + + // UI elements + arrowBack: 'arrow-back' as IconName, + arrowForward: 'arrow-forward' as IconName, + arrowDropDown: 'arrow-drop-down' as IconName, + arrowDropUp: 'arrow-drop-up' as IconName, + menu: 'menu' as IconName, + moreVert: 'more-vert' as IconName, + moreHoriz: 'more-horiz' as IconName, + + // Media + playArrow: 'play-arrow' as IconName, + pause: 'pause' as IconName, + stop: 'stop' as IconName, + + // Communication + notifications: 'notifications' as IconName, + notificationsOff: 'notifications-off' as IconName, + + // Misc + lightbulb: 'lightbulb' as IconName, + help: 'help' as IconName, + link: 'link' as IconName, + attach: 'attach-file' as IconName, + visibility: 'visibility' as IconName, + visibilityOff: 'visibility-off' as IconName, +} as const; diff --git a/packages/mobile-client/src/design-system/components/ProgressBar.tsx b/packages/mobile-client/src/design-system/components/ProgressBar.tsx new file mode 100644 index 0000000..206dab0 --- /dev/null +++ b/packages/mobile-client/src/design-system/components/ProgressBar.tsx @@ -0,0 +1,187 @@ +/** + * ProgressBar Component + * + * A horizontal progress bar component for visualizing metrics and progress. + * Supports color variants, percentage display, and optional labels. + * + * Requirements: 10.9, 3.4 + */ + +import React from 'react'; +import { View, Text, StyleSheet, StyleProp, ViewStyle } from 'react-native'; +import { useDesignSystem } from '../theme/useDesignSystem'; + +/** + * Progress bar color variants + */ +export type ProgressBarVariant = 'primary' | 'secondary' | 'tertiary' | 'error'; + +export interface ProgressBarProps { + /** + * Progress percentage (0-100) + */ + progress: number; + + /** + * Color variant + * @default 'primary' + */ + variant?: ProgressBarVariant; + + /** + * Show percentage label + * @default false + */ + showLabel?: boolean; + + /** + * Custom label text (overrides percentage) + */ + label?: string; + + /** + * Progress bar height + * @default 8 + */ + height?: number; + + /** + * Custom style overrides + */ + style?: StyleProp; +} + +/** + * ProgressBar component for visualizing metrics + */ +export const ProgressBar: React.FC = ({ + progress, + variant = 'primary', + showLabel = false, + label, + height = 8, + style, +}) => { + const { theme } = useDesignSystem(); + + // Clamp progress between 0 and 100 + const clampedProgress = Math.max(0, Math.min(100, progress)); + + /** + * Get progress bar color based on variant + */ + const getProgressColor = (): string => { + switch (variant) { + case 'primary': + return theme.colors.primary; + case 'secondary': + return theme.colors.secondary; + case 'tertiary': + return theme.colors.tertiary; + case 'error': + return theme.colors.error; + } + }; + + /** + * Get background color (dimmed version of progress color) + */ + const getBackgroundColor = (): string => { + switch (variant) { + case 'primary': + return theme.colors.primaryContainer; + case 'secondary': + return theme.colors.secondaryContainer; + case 'tertiary': + return theme.colors.tertiaryContainer; + case 'error': + return theme.colors.errorContainer; + } + }; + + const progressColor = getProgressColor(); + const backgroundColor = getBackgroundColor(); + + /** + * Get label text to display + */ + const getLabelText = (): string => { + if (label) { + return label; + } + if (showLabel) { + return `${Math.round(clampedProgress)}%`; + } + return ''; + }; + + const labelText = getLabelText(); + + return ( + + {/* Progress bar */} + + + + + {/* Optional label */} + {labelText && ( + + {labelText} + + )} + + ); +}; + +const styles = StyleSheet.create({ + container: { + width: '100%', + }, + track: { + width: '100%', + overflow: 'hidden', + }, + fill: { + height: '100%', + }, + label: { + marginTop: 4, + textAlign: 'right', + textTransform: 'uppercase', + letterSpacing: 0.5, + }, +}); diff --git a/packages/mobile-client/src/design-system/components/StatusIndicator.tsx b/packages/mobile-client/src/design-system/components/StatusIndicator.tsx new file mode 100644 index 0000000..7a92795 --- /dev/null +++ b/packages/mobile-client/src/design-system/components/StatusIndicator.tsx @@ -0,0 +1,225 @@ +/** + * StatusIndicator Component + * + * A status indicator component that displays connection status with color-coded dots. + * Supports connected, disconnected, and connecting states with pulse animation. + * + * Requirements: 10.6, 3.10, 3.11, 9.6, 9.7, 9.8 + */ + +import React, { useEffect, useRef } from 'react'; +import { View, Text, StyleSheet, Animated, StyleProp, ViewStyle } from 'react-native'; +import { useDesignSystem } from '../theme/useDesignSystem'; + +/** + * Connection status types + */ +export type ConnectionStatus = 'connected' | 'disconnected' | 'connecting'; + +/** + * Status indicator size variants + */ +export type StatusIndicatorSize = 'sm' | 'md' | 'lg'; + +export interface StatusIndicatorProps { + /** + * Current connection status + */ + status: ConnectionStatus; + + /** + * Show label text next to indicator + * @default false + */ + showLabel?: boolean; + + /** + * Size variant + * @default 'md' + */ + size?: StatusIndicatorSize; + + /** + * Enable pulse animation for connecting state + * @default true + */ + animated?: boolean; + + /** + * Custom style overrides + */ + style?: StyleProp; +} + +/** + * StatusIndicator component with color-coded status and pulse animation + */ +export const StatusIndicator: React.FC = ({ + status, + showLabel = false, + size = 'md', + animated = true, + style, +}) => { + const { theme } = useDesignSystem(); + const pulseScale = useRef(new Animated.Value(1)).current; + const pulseOpacity = useRef(new Animated.Value(1)).current; + + /** + * Start pulse animation for connecting state + */ + useEffect(() => { + if (status === 'connecting' && animated) { + // Create looping pulse animation + const pulseAnimation = Animated.loop( + Animated.parallel([ + Animated.sequence([ + Animated.timing(pulseScale, { + toValue: 1.5, + duration: 1000, + useNativeDriver: true, + }), + Animated.timing(pulseScale, { + toValue: 1, + duration: 1000, + useNativeDriver: true, + }), + ]), + Animated.sequence([ + Animated.timing(pulseOpacity, { + toValue: 0.5, + duration: 1000, + useNativeDriver: true, + }), + Animated.timing(pulseOpacity, { + toValue: 1, + duration: 1000, + useNativeDriver: true, + }), + ]), + ]) + ); + + pulseAnimation.start(); + + // Cleanup animation on unmount or status change + return () => { + pulseAnimation.stop(); + pulseScale.setValue(1); + pulseOpacity.setValue(1); + }; + } else { + // Reset animation values for non-connecting states + pulseScale.setValue(1); + pulseOpacity.setValue(1); + } + }, [status, animated, pulseScale, pulseOpacity]); + + /** + * Get dot size based on size variant + */ + const getDotSize = (): number => { + switch (size) { + case 'sm': + return 8; + case 'md': + return 10; + case 'lg': + return 12; + } + }; + + /** + * Get status color based on connection status + */ + const getStatusColor = (): string => { + switch (status) { + case 'connected': + return theme.colors.secondary; // Green + case 'disconnected': + return theme.colors.error; // Red + case 'connecting': + return theme.colors.tertiary; // Orange + } + }; + + /** + * Get status label text + */ + const getStatusLabel = (): string => { + switch (status) { + case 'connected': + return 'Connected'; + case 'disconnected': + return 'Disconnected'; + case 'connecting': + return 'Connecting'; + } + }; + + const dotSize = getDotSize(); + const statusColor = getStatusColor(); + const statusLabel = getStatusLabel(); + + return ( + + {/* Status dot with optional pulse animation */} + + + + + {/* Optional label */} + {showLabel && ( + + {statusLabel} + + )} + + ); +}; + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + alignItems: 'center', + }, + dotContainer: { + justifyContent: 'center', + alignItems: 'center', + }, + dot: { + // Size and color set dynamically + }, + label: { + marginLeft: 8, + textTransform: 'uppercase', + letterSpacing: 0.5, + }, +}); diff --git a/packages/mobile-client/src/design-system/components/TextInput.tsx b/packages/mobile-client/src/design-system/components/TextInput.tsx new file mode 100644 index 0000000..10c40bd --- /dev/null +++ b/packages/mobile-client/src/design-system/components/TextInput.tsx @@ -0,0 +1,385 @@ +/** + * TextInput Component + * + * A versatile text input component with focus states, error handling, + * character counter, and support for multiline input. + * + * Requirements: 10.4, 5.4, 5.5, 5.13 + */ + +import React, { useState } from 'react'; +import { + TextInput as RNTextInput, + View, + Text, + StyleSheet, + StyleProp, + ViewStyle, + TextStyle, + KeyboardTypeOptions, +} from 'react-native'; +import { useDesignSystem } from '../theme/useDesignSystem'; + +export interface TextInputProps { + /** + * Current input value + */ + value: string; + + /** + * Callback when text changes + */ + onChangeText: (text: string) => void; + + /** + * Placeholder text + */ + placeholder?: string; + + /** + * Enable multiline input + * @default false + */ + multiline?: boolean; + + /** + * Number of lines for multiline input + * @default 4 + */ + numberOfLines?: number; + + /** + * Maximum character length + */ + maxLength?: number; + + /** + * Keyboard type + * @default 'default' + */ + keyboardType?: KeyboardTypeOptions; + + /** + * Auto-capitalization behavior + * @default 'sentences' + */ + autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters'; + + /** + * Enable auto-correction + * @default true + */ + autoCorrect?: boolean; + + /** + * Whether input is editable + * @default true + */ + editable?: boolean; + + /** + * Error message to display + * When provided, input shows error state + */ + error?: string; + + /** + * Label text above input + */ + label?: string; + + /** + * Optional icon component to display + */ + icon?: React.ReactNode; + + /** + * Custom style overrides for container + */ + style?: StyleProp; + + /** + * Custom style overrides for input + */ + inputStyle?: StyleProp; + + /** + * Callback when input is focused + */ + onFocus?: () => void; + + /** + * Callback when input loses focus + */ + onBlur?: () => void; +} + +/** + * TextInput component with focus states and error handling + */ +export const TextInput: React.FC = ({ + value, + onChangeText, + placeholder, + multiline = false, + numberOfLines = 4, + maxLength, + keyboardType = 'default', + autoCapitalize = 'sentences', + autoCorrect = true, + editable = true, + error, + label, + icon, + style, + inputStyle, + onFocus, + onBlur, +}) => { + const { theme } = useDesignSystem(); + const [isFocused, setIsFocused] = useState(false); + + /** + * Handle focus event + */ + const handleFocus = () => { + setIsFocused(true); + onFocus?.(); + }; + + /** + * Handle blur event + */ + const handleBlur = () => { + setIsFocused(false); + onBlur?.(); + }; + + /** + * Get background color based on state + * - error: errorContainer background + * - focused: surfaceBright background + * - default: surfaceContainerHighest background + */ + const getBackgroundColor = (): string => { + if (error) { + return theme.colors.errorContainer; + } + if (isFocused) { + return theme.colors.surfaceBright; + } + return theme.colors.surfaceContainerHighest; + }; + + /** + * Get border color based on state + * - error: error border + * - focused: primary border + * - default: transparent + */ + const getBorderColor = (): string => { + if (error) { + return theme.colors.error; + } + if (isFocused) { + return theme.colors.primary; + } + return 'transparent'; + }; + + /** + * Get text color based on state + */ + const getTextColor = (): string => { + if (error) { + return theme.colors.onErrorContainer; + } + return theme.colors.onSurface; + }; + + /** + * Get placeholder color + */ + const getPlaceholderColor = (): string => { + return theme.colors.onSurfaceVariant; + }; + + /** + * Check if character limit is exceeded + */ + const isOverLimit = maxLength ? value.length > maxLength : false; + + /** + * Get character counter color + */ + const getCounterColor = (): string => { + if (isOverLimit) { + return theme.colors.error; + } + return theme.colors.onSurfaceVariant; + }; + + const backgroundColor = getBackgroundColor(); + const borderColor = getBorderColor(); + const textColor = getTextColor(); + const placeholderColor = getPlaceholderColor(); + const counterColor = getCounterColor(); + + return ( + + {/* Label */} + {label && ( + + {label} + + )} + + {/* Input Container */} + + {/* Icon */} + {icon && {icon}} + + {/* Text Input */} + + + + {/* Character Counter */} + {maxLength && ( + + {value.length} / {maxLength} + + )} + + {/* Error Message */} + {error && ( + + {error} + + )} + + ); +}; + +const styles = StyleSheet.create({ + container: { + width: '100%', + }, + label: { + textTransform: 'uppercase', + letterSpacing: 0.5, + }, + inputContainer: { + flexDirection: 'row', + alignItems: 'flex-start', + }, + iconContainer: { + marginRight: 8, + paddingTop: 2, + }, + input: { + flex: 1, + padding: 0, + margin: 0, + }, + counter: { + textAlign: 'right', + }, + error: { + // Error message styling + }, +}); diff --git a/packages/mobile-client/src/design-system/components/Toggle.tsx b/packages/mobile-client/src/design-system/components/Toggle.tsx new file mode 100644 index 0000000..f8645a2 --- /dev/null +++ b/packages/mobile-client/src/design-system/components/Toggle.tsx @@ -0,0 +1,167 @@ +/** + * Toggle Component + * + * A toggle switch component with label, description, and haptic feedback. + * Supports enabled/disabled states with design system colors. + * + * Requirements: 10.5, 7.4, 12.10 + */ + +import React from 'react'; +import { View, Switch, Text, StyleSheet, Platform, StyleProp, ViewStyle } from 'react-native'; +import * as Haptics from 'expo-haptics'; +import { useDesignSystem } from '../theme/useDesignSystem'; + +export interface ToggleProps { + /** + * Current toggle value + */ + value: boolean; + + /** + * Callback when value changes + */ + onValueChange: (value: boolean) => void; + + /** + * Disabled state + * @default false + */ + disabled?: boolean; + + /** + * Label text displayed above the toggle + */ + label?: string; + + /** + * Description text displayed below the label + */ + description?: string; + + /** + * Enable haptic feedback on value change + * @default true + */ + hapticFeedback?: boolean; + + /** + * Custom style overrides + */ + style?: StyleProp; +} + +/** + * Toggle switch component with label and description + */ +export const Toggle: React.FC = ({ + value, + onValueChange, + disabled = false, + label, + description, + hapticFeedback = true, + style, +}) => { + const { theme } = useDesignSystem(); + + /** + * Handle value change with haptic feedback + */ + const handleValueChange = (newValue: boolean) => { + if (disabled) return; + + // Trigger haptic feedback + if (hapticFeedback && (Platform.OS === 'ios' || Platform.OS === 'android')) { + Haptics.selectionAsync(); + } + + onValueChange(newValue); + }; + + return ( + + {/* Label and description section */} + {(label || description) && ( + + {label && ( + + {label} + + )} + {description && ( + + {description} + + )} + + )} + + {/* Toggle switch */} + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + minHeight: 44, // Minimum touch target size + }, + textContainer: { + flex: 1, + marginRight: 16, + }, + label: { + marginBottom: 4, + }, + description: { + lineHeight: 18, + }, + switch: { + // Platform-specific adjustments handled by React Native + }, +}); diff --git a/packages/mobile-client/src/design-system/components/index.ts b/packages/mobile-client/src/design-system/components/index.ts new file mode 100644 index 0000000..798d531 --- /dev/null +++ b/packages/mobile-client/src/design-system/components/index.ts @@ -0,0 +1,26 @@ +/** + * Design System Components + * + * This module exports all reusable UI components + * for the Obsidian UI design system. + */ + +export * from './Button'; +export { Card } from './Card'; +export type { CardProps, CardVariant } from './Card'; +export { Chip } from './Chip'; +export type { ChipProps, ChipVariant, ChipSize } from './Chip'; +export { TextInput } from './TextInput'; +export type { TextInputProps } from './TextInput'; +export { Toggle } from './Toggle'; +export type { ToggleProps } from './Toggle'; +export { StatusIndicator } from './StatusIndicator'; +export type { + StatusIndicatorProps, + ConnectionStatus, + StatusIndicatorSize, +} from './StatusIndicator'; +export { Icon, IconNames } from './Icon'; +export type { IconProps, IconName, IconWeight } from './Icon'; +export { ProgressBar } from './ProgressBar'; +export type { ProgressBarProps, ProgressBarVariant } from './ProgressBar'; diff --git a/packages/mobile-client/src/design-system/index.ts b/packages/mobile-client/src/design-system/index.ts new file mode 100644 index 0000000..4fb1662 --- /dev/null +++ b/packages/mobile-client/src/design-system/index.ts @@ -0,0 +1,18 @@ +/** + * Design System + * + * Main entry point for the Obsidian UI design system. + * Exports all tokens, theme utilities, typography, and components. + */ + +// Export design tokens +export * from './tokens'; + +// Export theme system +export * from './theme'; + +// Export typography +export * from './typography'; + +// Export components +export * from './components'; diff --git a/packages/mobile-client/src/design-system/theme/ThemeContext.tsx b/packages/mobile-client/src/design-system/theme/ThemeContext.tsx new file mode 100644 index 0000000..ab5cb26 --- /dev/null +++ b/packages/mobile-client/src/design-system/theme/ThemeContext.tsx @@ -0,0 +1,54 @@ +/** + * Theme Context + * + * React Context for theme configuration and management. + * Provides theme access throughout the component tree. + * + * Requirements: 1.6 + */ + +import { createContext } from 'react'; +import type { ThemeConfig, ThemeConfiguration } from './types'; +import { defaultThemeConfiguration } from './types'; +import { createTheme } from './createTheme'; + +/** + * ThemeContextValue interface defines the shape of the theme context. + * Provides access to the current theme and configuration update function. + */ +export interface ThemeContextValue { + /** + * Current theme object with all design tokens + */ + theme: ThemeConfig; + + /** + * Current theme configuration (user preferences) + */ + config: ThemeConfiguration; + + /** + * Function to update theme configuration + */ + setConfig: (config: ThemeConfiguration) => void; +} + +/** + * Default theme context value. + * Used as fallback when ThemeProvider is not in the component tree. + */ +const defaultTheme = createTheme(defaultThemeConfiguration); + +const defaultContextValue: ThemeContextValue = { + theme: defaultTheme, + config: defaultThemeConfiguration, + setConfig: () => { + console.warn('setConfig called outside of ThemeProvider'); + }, +}; + +/** + * ThemeContext provides theme configuration throughout the app. + * Must be used within a ThemeProvider component. + */ +export const ThemeContext = createContext(defaultContextValue); diff --git a/packages/mobile-client/src/design-system/theme/ThemeProvider.tsx b/packages/mobile-client/src/design-system/theme/ThemeProvider.tsx new file mode 100644 index 0000000..b1f7188 --- /dev/null +++ b/packages/mobile-client/src/design-system/theme/ThemeProvider.tsx @@ -0,0 +1,105 @@ +/** + * Theme Provider Component + * + * Provides theme configuration to the entire app via React Context. + * Handles theme persistence with AsyncStorage and theme updates. + * + * Requirements: 1.6, 20.1, 20.5, 20.6, 20.7 + */ + +import React, { useState, useEffect, useMemo, type ReactNode } from 'react'; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { ThemeContext } from './ThemeContext'; +import { createTheme } from './createTheme'; +import { defaultThemeConfiguration, type ThemeConfiguration } from './types'; + +/** + * AsyncStorage key for theme configuration persistence + */ +const THEME_STORAGE_KEY = '@codelink/theme_config'; + +/** + * ThemeProvider props + */ +interface ThemeProviderProps { + children: ReactNode; +} + +/** + * Loads theme configuration from AsyncStorage. + * Returns default configuration if storage is unavailable or empty. + */ +async function loadThemeConfiguration(): Promise { + try { + const stored = await AsyncStorage.getItem(THEME_STORAGE_KEY); + if (stored) { + const parsed = JSON.parse(stored) as ThemeConfiguration; + return parsed; + } + } catch (error) { + console.error('Failed to load theme configuration from AsyncStorage:', error); + } + return defaultThemeConfiguration; +} + +/** + * Saves theme configuration to AsyncStorage. + */ +async function saveThemeConfiguration(config: ThemeConfiguration): Promise { + try { + await AsyncStorage.setItem(THEME_STORAGE_KEY, JSON.stringify(config)); + } catch (error) { + console.error('Failed to save theme configuration to AsyncStorage:', error); + } +} + +/** + * ThemeProvider component wraps the app and provides theme configuration + * via React Context. Handles loading and persisting theme preferences. + */ +export const ThemeProvider: React.FC = ({ children }) => { + const [config, setConfigState] = useState(defaultThemeConfiguration); + const [isLoading, setIsLoading] = useState(true); + + // Load saved theme configuration on mount + useEffect(() => { + loadThemeConfiguration() + .then((loadedConfig) => { + setConfigState(loadedConfig); + }) + .finally(() => { + setIsLoading(false); + }); + }, []); + + // Create theme object from configuration + // Memoized to avoid unnecessary recalculations + const theme = useMemo(() => createTheme(config), [config]); + + // Update configuration and persist to AsyncStorage + const setConfig = (newConfig: ThemeConfiguration) => { + setConfigState(newConfig); + // Save asynchronously without blocking UI + saveThemeConfiguration(newConfig).catch((error) => { + console.error('Failed to persist theme configuration:', error); + }); + }; + + // Context value with theme, config, and setter + const contextValue = useMemo( + () => ({ + theme, + config, + setConfig, + }), + [theme, config] + ); + + // Show nothing while loading theme preferences + // This prevents flash of default theme before loading saved preferences + if (isLoading) { + return null; + } + + return {children}; +}; diff --git a/packages/mobile-client/src/design-system/theme/createTheme.ts b/packages/mobile-client/src/design-system/theme/createTheme.ts new file mode 100644 index 0000000..a153719 --- /dev/null +++ b/packages/mobile-client/src/design-system/theme/createTheme.ts @@ -0,0 +1,73 @@ +/** + * Create Theme Function + * + * Creates a complete theme object from user configuration. + * Applies custom colors and high contrast adjustments as needed. + * + * Requirements: 1.6, 1.7, 14.6, 14.10 + */ + +import { colorTokens, type ColorTokens } from '../tokens/colors'; +import { typographyTokens } from '../tokens/typography'; +import { spacingTokens } from '../tokens/spacing'; +import { borderRadiusTokens } from '../tokens/borderRadius'; +import type { ThemeConfig, ThemeConfiguration } from './types'; + +/** + * High contrast color adjustments. + * Increases contrast ratios to 7:1 minimum for WCAG AAA compliance. + */ +const highContrastColorAdjustments: Partial = { + // Increase text contrast + onSurface: '#ffffff', // Pure white for maximum contrast + onSurfaceVariant: '#e0e0e0', // Lighter gray for secondary text + + // Increase outline visibility + outline: '#808080', // Brighter outline + outlineVariant: '#606060', // Brighter outline variant + + // Adjust surface brightness for better separation + surfaceBright: '#4a4a4a', // Brighter focused states + surfaceContainerHighest: '#454545', // Brighter highest container +}; + +/** + * Creates a complete theme object from user configuration. + * + * @param config - User theme configuration + * @returns Complete theme object with all design tokens + */ +export function createTheme(config: ThemeConfiguration): ThemeConfig { + // Start with default color tokens + let colors: ColorTokens = { ...colorTokens }; + + // Apply high contrast adjustments if enabled + if (config.highContrast) { + colors = { + ...colors, + ...highContrastColorAdjustments, + }; + } + + // Apply custom color overrides if provided + if (config.customColors) { + colors = { + ...colors, + ...config.customColors, + }; + } + + // Note: Light mode is not yet implemented + // When implemented, this function should switch color palettes based on config.mode + if (config.mode === 'light') { + console.warn('Light mode is not yet implemented. Using dark mode.'); + } + + // Return complete theme configuration + return { + colors, + typography: typographyTokens, + spacing: spacingTokens, + borderRadius: borderRadiusTokens, + }; +} diff --git a/packages/mobile-client/src/design-system/theme/index.ts b/packages/mobile-client/src/design-system/theme/index.ts new file mode 100644 index 0000000..08fd7e4 --- /dev/null +++ b/packages/mobile-client/src/design-system/theme/index.ts @@ -0,0 +1,12 @@ +/** + * Design System Theme + * + * This module exports theme configuration, theme provider, + * and theme-related utilities for the Obsidian UI design system. + */ + +export * from './types'; +export * from './createTheme'; +export * from './ThemeContext'; +export * from './ThemeProvider'; +export * from './useDesignSystem'; diff --git a/packages/mobile-client/src/design-system/theme/types.ts b/packages/mobile-client/src/design-system/theme/types.ts new file mode 100644 index 0000000..ea41aa6 --- /dev/null +++ b/packages/mobile-client/src/design-system/theme/types.ts @@ -0,0 +1,60 @@ +/** + * Theme Configuration Types + * + * Defines TypeScript interfaces for theme configuration including: + * - ThemeConfig interface with all design tokens + * - ThemeConfiguration interface for user preferences + * - Default theme configuration + * + * Requirements: 1.6, 1.7 + */ + +import type { ColorTokens } from '../tokens/colors'; +import type { TypographyTokens } from '../tokens/typography'; +import type { SpacingTokens } from '../tokens/spacing'; +import type { BorderRadiusTokens } from '../tokens/borderRadius'; + +/** + * ThemeConfig interface defines the complete theme configuration + * including all design tokens (colors, typography, spacing, border radius). + */ +export interface ThemeConfig { + colors: ColorTokens; + typography: TypographyTokens; + spacing: SpacingTokens; + borderRadius: BorderRadiusTokens; +} + +/** + * ThemeConfiguration interface defines user-configurable theme preferences. + * These preferences control the theme mode and accessibility features. + */ +export interface ThemeConfiguration { + /** + * Theme mode: 'dark', 'light', or 'auto' (follows system preference) + * Currently only dark mode is fully implemented. + */ + mode: 'dark' | 'light' | 'auto'; + + /** + * High contrast mode for improved accessibility. + * When enabled, increases contrast ratios to 7:1 minimum. + */ + highContrast: boolean; + + /** + * Optional custom color overrides. + * Allows partial customization of the color palette. + */ + customColors?: Partial; +} + +/** + * Default theme configuration. + * Uses dark mode as the primary theme with standard contrast. + */ +export const defaultThemeConfiguration: ThemeConfiguration = { + mode: 'dark', + highContrast: false, + customColors: undefined, +}; diff --git a/packages/mobile-client/src/design-system/theme/useDesignSystem.ts b/packages/mobile-client/src/design-system/theme/useDesignSystem.ts new file mode 100644 index 0000000..1b8a72e --- /dev/null +++ b/packages/mobile-client/src/design-system/theme/useDesignSystem.ts @@ -0,0 +1,43 @@ +/** + * useDesignSystem Hook + * + * Custom React hook for accessing the design system theme. + * Provides type-safe access to theme configuration and update function. + * + * Requirements: 1.6 + */ + +import { useContext } from 'react'; +import { ThemeContext } from './ThemeContext'; + +/** + * Hook for accessing the design system theme. + * Must be used within a ThemeProvider component. + * + * @returns Theme context value with theme, config, and setConfig + * @throws Error if used outside of ThemeProvider + * + * @example + * ```tsx + * function MyComponent() { + * const { theme, config, setConfig } = useDesignSystem(); + * + * return ( + * + * + * Hello World + * + * + * ); + * } + * ``` + */ +export function useDesignSystem() { + const context = useContext(ThemeContext); + + if (!context) { + throw new Error('useDesignSystem must be used within a ThemeProvider'); + } + + return context; +} diff --git a/packages/mobile-client/src/design-system/tokens/borderRadius.ts b/packages/mobile-client/src/design-system/tokens/borderRadius.ts new file mode 100644 index 0000000..858ac15 --- /dev/null +++ b/packages/mobile-client/src/design-system/tokens/borderRadius.ts @@ -0,0 +1,41 @@ +/** + * Border Radius Tokens + * + * Defines all border radius tokens for the Obsidian UI design system. + * Border radius values range from sm (2px) for subtle rounding to full (9999px) + * for pill-shaped elements like chips and status indicators. + * + * Requirements: 1.5 + */ + +/** + * BorderRadiusTokens interface defines all border radius values used in the design system. + * Values are in pixels and provide consistent corner rounding across components. + */ +export interface BorderRadiusTokens { + sm: number; // 0.125rem / 2px - subtle rounding + md: number; // 0.375rem / 6px - medium rounding + lg: number; // 0.5rem / 8px - large rounding (default for cards) + xl: number; // 0.75rem / 12px - extra large rounding + '2xl': number; // 1rem / 16px - 2x extra large rounding + full: number; // 9999px - fully rounded (pills, circles) +} + +/** + * Default border radius scale matching the design specifications. + * All values are in pixels for React Native compatibility. + */ +export const defaultBorderRadiusTokens: BorderRadiusTokens = { + sm: 2, // 0.125rem - subtle rounding + md: 6, // 0.375rem - medium rounding + lg: 8, // 0.5rem - large rounding (default for cards) + xl: 12, // 0.75rem - extra large rounding + '2xl': 16, // 1rem - 2x extra large rounding + full: 9999, // fully rounded (pills, circles) +}; + +/** + * Export the default border radius tokens as the main export. + * This can be overridden by theme configuration in the future. + */ +export const borderRadiusTokens = defaultBorderRadiusTokens; diff --git a/packages/mobile-client/src/design-system/tokens/colors.ts b/packages/mobile-client/src/design-system/tokens/colors.ts new file mode 100644 index 0000000..d7250e4 --- /dev/null +++ b/packages/mobile-client/src/design-system/tokens/colors.ts @@ -0,0 +1,116 @@ +/** + * Color Tokens + * + * Defines all color tokens for the Obsidian UI design system including: + * - Surface hierarchy colors for tonal layering + * - Primary, secondary, tertiary, and error accent colors + * - Semantic color tokens for text and outlines + * + */ + +/** + * ColorTokens interface defines all color values used in the design system. + * Colors follow Material Design 3 naming conventions with surface hierarchy + * for tonal layering instead of drop shadows or borders. + */ +export interface ColorTokens { + // Surface hierarchy - used for tonal layering to create depth + surface: string; + surfaceContainerLowest: string; + surfaceContainerLow: string; + surfaceContainer: string; + surfaceContainerHigh: string; + surfaceContainerHighest: string; + surfaceVariant: string; + surfaceBright: string; + surfaceDim: string; + + // Primary colors - main brand color (#95ccff - light blue) + primary: string; + primaryContainer: string; + onPrimary: string; + onPrimaryContainer: string; + + // Secondary colors - accent color (#61dac1 - teal/green) + secondary: string; + secondaryContainer: string; + onSecondary: string; + onSecondaryContainer: string; + + // Tertiary colors - accent color (#fab79d - peach/orange) + tertiary: string; + tertiaryContainer: string; + onTertiary: string; + onTertiaryContainer: string; + + // Error colors - error states (#ffb4ab - light red) + error: string; + errorContainer: string; + onError: string; + onErrorContainer: string; + + // Text colors - for content on various surfaces + onSurface: string; + onSurfaceVariant: string; + onBackground: string; + + // Outline colors - for borders and dividers + outline: string; + outlineVariant: string; +} + +/** + * Default dark theme color palette matching the Obsidian IDE aesthetic. + * All colors are defined to match the Tailwind configuration in Stitch designs. + */ +export const defaultColorPalette: ColorTokens = { + // Surface hierarchy - dark theme with subtle variations for depth + surface: '#131313', // Base surface (darkest) + surfaceContainerLowest: '#0f0f0f', // Lowest container (code blocks) + surfaceContainerLow: '#1a1a1a', // Low container (cards) + surfaceContainer: '#1f1f1f', // Default container + surfaceContainerHigh: '#2a2a2a', // High container (elevated elements) + surfaceContainerHighest: '#353535', // Highest container (inputs, inactive states) + surfaceVariant: '#2a2a2a', // Variant surface + surfaceBright: '#3a3a3a', // Bright surface (focused states) + surfaceDim: '#0a0a0a', // Dim surface + + // Primary colors - light blue (#95ccff) + primary: '#95ccff', // Primary brand color + primaryContainer: '#569cd6', // Primary container (darker blue for keywords) + onPrimary: '#000000', // Text on primary + onPrimaryContainer: '#ffffff', // Text on primary container + + // Secondary colors - teal/green (#61dac1) + secondary: '#61dac1', // Secondary accent (success, active states) + secondaryContainer: '#4db8a3', // Secondary container + onSecondary: '#000000', // Text on secondary + onSecondaryContainer: '#ffffff', // Text on secondary container + + // Tertiary colors - peach/orange (#fab79d) + tertiary: '#fab79d', // Tertiary accent (warnings, highlights) + tertiaryContainer: '#e89b7f', // Tertiary container + onTertiary: '#000000', // Text on tertiary + onTertiaryContainer: '#ffffff', // Text on tertiary container + + // Error colors - light red (#ffb4ab) + error: '#ffb4ab', // Error state + errorContainer: '#ff8a80', // Error container + onError: '#000000', // Text on error + onErrorContainer: '#ffffff', // Text on error container + + // Text colors - optimized for dark theme readability + onSurface: '#ffffff', // Primary text on surface + onSurfaceVariant: '#b0b0b0', // Secondary text, dimmed + onBackground: '#ffffff', // Text on background + + // Outline colors - for borders and dividers + outline: '#5a5a5a', // Standard outline + outlineVariant: '#3a3a3a', // Subtle outline variant +}; + +/** + * Export the default palette as the main color tokens export. + * This can be overridden by theme configuration in the future. + */ +export const colorTokens = defaultColorPalette; diff --git a/packages/mobile-client/src/design-system/tokens/index.ts b/packages/mobile-client/src/design-system/tokens/index.ts new file mode 100644 index 0000000..7afab40 --- /dev/null +++ b/packages/mobile-client/src/design-system/tokens/index.ts @@ -0,0 +1,11 @@ +/** + * Design System Tokens + * + * This module exports all design tokens including colors, typography, + * spacing, and border radius tokens for the Obsidian UI design system. + */ + +export * from './colors'; +export * from './typography'; +export * from './spacing'; +export * from './borderRadius'; diff --git a/packages/mobile-client/src/design-system/tokens/spacing.ts b/packages/mobile-client/src/design-system/tokens/spacing.ts new file mode 100644 index 0000000..e18c357 --- /dev/null +++ b/packages/mobile-client/src/design-system/tokens/spacing.ts @@ -0,0 +1,45 @@ +/** + * Spacing Tokens + * + * Defines all spacing tokens for the Obsidian UI design system. + * Spacing scale follows a consistent progression from xs (4px) to 4xl (64px) + * for margins, padding, and gaps throughout the interface. + * + * Requirements: 1.4 + */ + +/** + * SpacingTokens interface defines all spacing values used in the design system. + * Values are in pixels and follow a consistent scale for predictable layouts. + */ +export interface SpacingTokens { + xs: number; // 0.25rem / 4px - minimal spacing + sm: number; // 0.5rem / 8px - small spacing + md: number; // 0.75rem / 12px - medium spacing + lg: number; // 1rem / 16px - large spacing (base unit) + xl: number; // 1.5rem / 24px - extra large spacing + '2xl': number; // 2rem / 32px - 2x extra large spacing + '3xl': number; // 3rem / 48px - 3x extra large spacing + '4xl': number; // 4rem / 64px - 4x extra large spacing +} + +/** + * Default spacing scale matching the design specifications. + * All values are in pixels for React Native compatibility. + */ +export const defaultSpacingTokens: SpacingTokens = { + xs: 4, // 0.25rem + sm: 8, // 0.5rem + md: 12, // 0.75rem + lg: 16, // 1rem (base unit) + xl: 24, // 1.5rem + '2xl': 32, // 2rem + '3xl': 48, // 3rem + '4xl': 64, // 4rem +}; + +/** + * Export the default spacing tokens as the main export. + * This can be overridden by theme configuration in the future. + */ +export const spacingTokens = defaultSpacingTokens; diff --git a/packages/mobile-client/src/design-system/tokens/typography.ts b/packages/mobile-client/src/design-system/tokens/typography.ts new file mode 100644 index 0000000..f49cb81 --- /dev/null +++ b/packages/mobile-client/src/design-system/tokens/typography.ts @@ -0,0 +1,105 @@ +/** + * Typography Tokens + * + * Defines all typography tokens for the Obsidian UI design system including: + * - Font families (Manrope, Inter, Space Grotesk, monospace) + * - Typography size scale (displayLg through labelSm) + * - Font weights (regular through extrabold) + * - Line heights (tight, normal, relaxed) + * + * Requirements: 1.3 + */ + +/** + * TypographyTokens interface defines all typography values used in the design system. + * Typography follows the Obsidian IDE aesthetic with editorial font choices: + * - Manrope for headlines (sophisticated, geometric sans-serif) + * - Inter for body text (highly legible, optimized for screens) + * - Space Grotesk for labels (technical, monospace-inspired) + * - Monospace for code (Fira Code or system fallback) + */ +export interface TypographyTokens { + fonts: { + headline: string; // Manrope - for headlines and display text + body: string; // Inter - for body text and paragraphs + label: string; // Space Grotesk - for labels and metadata + mono: string; // Fira Code or system monospace - for code + }; + sizes: { + displayLg: number; // 3.5rem / 56px - largest display text + displayMd: number; // 2.8rem / 44.8px - medium display text + displaySm: number; // 2.25rem / 36px - small display text + headlineLg: number; // 2rem / 32px - large headlines + headlineMd: number; // 1.75rem / 28px - medium headlines + headlineSm: number; // 1.5rem / 24px - small headlines + titleLg: number; // 1.375rem / 22px - large titles + titleMd: number; // 1.125rem / 18px - medium titles + titleSm: number; // 0.875rem / 14px - small titles + bodyLg: number; // 1rem / 16px - large body text + bodyMd: number; // 0.875rem / 14px - medium body text + bodySm: number; // 0.75rem / 12px - small body text + labelLg: number; // 0.875rem / 14px - large labels + labelMd: number; // 0.75rem / 12px - medium labels + labelSm: number; // 0.6875rem / 11px - small labels + }; + weights: { + regular: number; // 400 - normal text weight + medium: number; // 500 - slightly emphasized + semibold: number; // 600 - emphasized text + bold: number; // 700 - strong emphasis + extrabold: number; // 800 - maximum emphasis + }; + lineHeights: { + tight: number; // 1.2 - compact line spacing + normal: number; // 1.5 - standard line spacing + relaxed: number; // 1.75 - loose line spacing + }; +} + +/** + * Default typography configuration matching the Obsidian IDE aesthetic. + * Font families will be loaded via Expo Font with appropriate fallbacks. + */ +export const defaultTypographyTokens: TypographyTokens = { + fonts: { + headline: 'Manrope', // Geometric sans-serif for headlines + body: 'Inter', // Optimized for body text readability + label: 'SpaceGrotesk', // Technical aesthetic for labels + mono: 'FiraCode', // Monospace for code (fallback to system) + }, + sizes: { + displayLg: 56, // 3.5rem + displayMd: 44.8, // 2.8rem + displaySm: 36, // 2.25rem + headlineLg: 32, // 2rem + headlineMd: 28, // 1.75rem + headlineSm: 24, // 1.5rem + titleLg: 22, // 1.375rem + titleMd: 18, // 1.125rem + titleSm: 14, // 0.875rem + bodyLg: 16, // 1rem + bodyMd: 14, // 0.875rem + bodySm: 12, // 0.75rem + labelLg: 14, // 0.875rem + labelMd: 12, // 0.75rem + labelSm: 11, // 0.6875rem + }, + weights: { + regular: 400, // Normal weight + medium: 500, // Medium weight + semibold: 600, // Semibold weight + bold: 700, // Bold weight + extrabold: 800, // Extrabold weight + }, + lineHeights: { + tight: 1.2, // Compact spacing for headlines + normal: 1.5, // Standard spacing for body text + relaxed: 1.75, // Loose spacing for readability + }, +}; + +/** + * Export the default typography tokens as the main export. + * This can be overridden by theme configuration in the future. + */ +export const typographyTokens = defaultTypographyTokens; diff --git a/packages/mobile-client/src/design-system/typography/Text.tsx b/packages/mobile-client/src/design-system/typography/Text.tsx new file mode 100644 index 0000000..ac62338 --- /dev/null +++ b/packages/mobile-client/src/design-system/typography/Text.tsx @@ -0,0 +1,169 @@ +/** + * Text Component + * + * Typography component with design system variants and styling. + * Supports all typography scales from display-lg to label-sm with + * automatic font family mapping based on variant type. + * + * Requirements: 2.7, 2.8, 2.9 + */ + +import React from 'react'; +import { Text as RNText, type TextStyle, type StyleProp } from 'react-native'; +import { useDesignSystem } from '../theme/useDesignSystem'; +import type { ColorTokens } from '../tokens/colors'; +import type { TypographyTokens } from '../tokens/typography'; + +/** + * Typography variant types + */ +export type TypographyVariant = + | 'display-lg' + | 'display-md' + | 'display-sm' + | 'headline-lg' + | 'headline-md' + | 'headline-sm' + | 'title-lg' + | 'title-md' + | 'title-sm' + | 'body-lg' + | 'body-md' + | 'body-sm' + | 'label-lg' + | 'label-md' + | 'label-sm'; + +/** + * Text component props + */ +export interface TextProps { + /** + * Typography variant determining size and font family + */ + variant: TypographyVariant; + + /** + * Text color from design system color tokens + */ + color?: keyof ColorTokens; + + /** + * Font weight from design system typography tokens + */ + weight?: keyof TypographyTokens['weights']; + + /** + * Text alignment + */ + align?: 'left' | 'center' | 'right'; + + /** + * Transform text to uppercase + */ + uppercase?: boolean; + + /** + * Text content + */ + children: React.ReactNode; + + /** + * Additional custom styles + */ + style?: StyleProp; +} + +/** + * Maps variant type to font family category + */ +function getFontFamilyForVariant(variant: TypographyVariant): keyof TypographyTokens['fonts'] { + // Display and headline variants use Manrope + if (variant.startsWith('display-') || variant.startsWith('headline-')) { + return 'headline'; + } + + // Body and title variants use Inter + if (variant.startsWith('body-') || variant.startsWith('title-')) { + return 'body'; + } + + // Label variants use Space Grotesk + if (variant.startsWith('label-')) { + return 'label'; + } + + // Default to body font + return 'body'; +} + +/** + * Maps variant to font size token key + */ +function getFontSizeKey(variant: TypographyVariant): keyof TypographyTokens['sizes'] { + // Convert variant format (e.g., 'display-lg') to camelCase (e.g., 'displayLg') + const parts = variant.split('-'); + const camelCase = parts[0] + parts[1].charAt(0).toUpperCase() + parts[1].slice(1); + return camelCase as keyof TypographyTokens['sizes']; +} + +/** + * Text component with design system typography variants. + * + * Automatically applies the correct font family based on variant: + * - display-* and headline-* variants use Manrope + * - body-* and title-* variants use Inter + * - label-* variants use Space Grotesk + * + * @example + * ```tsx + * + * Welcome to CodeLink + * + * + * + * This is body text with default styling + * + * + * + * Metadata Label + * + * ``` + */ +export const Text: React.FC = ({ + variant, + color = 'onSurface', + weight = 'regular', + align = 'left', + uppercase = false, + children, + style, +}) => { + const { theme } = useDesignSystem(); + + // Get font family based on variant type + const fontFamilyCategory = getFontFamilyForVariant(variant); + const fontFamily = theme.typography.fonts[fontFamilyCategory]; + + // Get font size from variant + const fontSizeKey = getFontSizeKey(variant); + const fontSize = theme.typography.sizes[fontSizeKey]; + + // Get font weight + const fontWeight = theme.typography.weights[weight]; + + // Get text color + const textColor = theme.colors[color]; + + // Compose text style + const textStyle: TextStyle = { + fontFamily, + fontSize, + fontWeight: String(fontWeight) as TextStyle['fontWeight'], + color: textColor, + textAlign: align, + textTransform: uppercase ? 'uppercase' : 'none', + }; + + return {children}; +}; diff --git a/packages/mobile-client/src/design-system/typography/fontLoading.ts b/packages/mobile-client/src/design-system/typography/fontLoading.ts new file mode 100644 index 0000000..8a992b2 --- /dev/null +++ b/packages/mobile-client/src/design-system/typography/fontLoading.ts @@ -0,0 +1,155 @@ +/** + * Font Loading Utility + * + * This module provides font loading functionality with error handling + * and fallback to system fonts. + * + * Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 + */ + +import { useFonts } from 'expo-font'; +import { + Manrope_400Regular, + Manrope_600SemiBold, + Manrope_700Bold, + Manrope_800ExtraBold, +} from '@expo-google-fonts/manrope'; +import { Inter_400Regular, Inter_500Medium, Inter_600SemiBold } from '@expo-google-fonts/inter'; +import { + SpaceGrotesk_400Regular, + SpaceGrotesk_500Medium, + SpaceGrotesk_700Bold, +} from '@expo-google-fonts/space-grotesk'; + +/** + * Font loading result + */ +export interface FontLoadingResult { + fontsLoaded: boolean; + fontError: Error | null; +} + +/** + * Custom hook for loading all required fonts + * + * Loads Manrope (weights 400, 600, 700, 800), Inter (weights 400, 500, 600), + * and Space Grotesk (weights 400, 500, 700) fonts. + * + * @returns Object containing fontsLoaded boolean and fontError + * + * @example + * ```tsx + * const { fontsLoaded, fontError } = useCustomFonts(); + * + * if (fontError) { + * console.error('Font loading failed:', fontError); + * // App will continue with system fonts + * } + * + * if (!fontsLoaded) { + * return ; + * } + * ``` + */ +export function useCustomFonts(): FontLoadingResult { + const [fontsLoaded, fontError] = useFonts({ + // Manrope fonts (for headlines) + Manrope_400Regular, + Manrope_600SemiBold, + Manrope_700Bold, + Manrope_800ExtraBold, + + // Inter fonts (for body text) + Inter_400Regular, + Inter_500Medium, + Inter_600SemiBold, + + // Space Grotesk fonts (for labels) + SpaceGrotesk_400Regular, + SpaceGrotesk_500Medium, + SpaceGrotesk_700Bold, + }); + + // Log error if font loading fails + if (fontError) { + console.error('Font loading failed:', fontError); + console.warn('Falling back to system fonts'); + } + + return { + fontsLoaded, + fontError, + }; +} + +/** + * Get font family name based on variant and weight + * + * Returns the appropriate font family string for React Native StyleSheet. + * Falls back to system fonts if custom fonts are not loaded. + * + * @param variant - Font variant: 'headline', 'body', 'label', or 'mono' + * @param weight - Font weight: 400, 500, 600, 700, or 800 + * @param fontsLoaded - Whether custom fonts are loaded + * @returns Font family string + */ +export function getFontFamily( + variant: 'headline' | 'body' | 'label' | 'mono', + weight: 400 | 500 | 600 | 700 | 800, + fontsLoaded: boolean +): string { + // Fallback to system fonts if custom fonts not loaded + if (!fontsLoaded) { + if (variant === 'mono') { + return 'monospace'; + } + return 'System'; + } + + // Return appropriate font family based on variant and weight + switch (variant) { + case 'headline': + switch (weight) { + case 400: + return 'Manrope_400Regular'; + case 600: + return 'Manrope_600SemiBold'; + case 700: + return 'Manrope_700Bold'; + case 800: + return 'Manrope_800ExtraBold'; + default: + return 'Manrope_400Regular'; + } + + case 'body': + switch (weight) { + case 400: + return 'Inter_400Regular'; + case 500: + return 'Inter_500Medium'; + case 600: + return 'Inter_600SemiBold'; + default: + return 'Inter_400Regular'; + } + + case 'label': + switch (weight) { + case 400: + return 'SpaceGrotesk_400Regular'; + case 500: + return 'SpaceGrotesk_500Medium'; + case 700: + return 'SpaceGrotesk_700Bold'; + default: + return 'SpaceGrotesk_400Regular'; + } + + case 'mono': + return 'monospace'; + + default: + return 'System'; + } +} diff --git a/packages/mobile-client/src/design-system/typography/index.ts b/packages/mobile-client/src/design-system/typography/index.ts new file mode 100644 index 0000000..03620d6 --- /dev/null +++ b/packages/mobile-client/src/design-system/typography/index.ts @@ -0,0 +1,9 @@ +/** + * Design System Typography + * + * This module exports typography components and utilities + * for the Obsidian UI design system. + */ + +export * from './Text'; +export * from './fontLoading'; diff --git a/packages/mobile-client/src/hooks/index.ts b/packages/mobile-client/src/hooks/index.ts new file mode 100644 index 0000000..df1740c --- /dev/null +++ b/packages/mobile-client/src/hooks/index.ts @@ -0,0 +1,24 @@ +// Custom React hooks +// This file will export all custom hooks + +export { + ConnectionStatusProvider, + useConnection, + type ConnectionStatus, + type ConnectionContextValue, + type ConnectionStatusProviderProps, +} from './useConnection'; + +export { useOrientation, type Orientation, type UseOrientationResult } from './useOrientation'; + +export { ThemeProvider, useTheme } from './useTheme'; + +export { usePromptHistory, type PromptHistoryItem } from './usePromptHistory'; + +export { useDraftPrompt } from './useDraftPrompt'; + +export { + useConnectionQuality, + type ConnectionQuality, + type ConnectionMetrics, +} from './useConnectionQuality'; diff --git a/packages/mobile-client/src/hooks/useConnection.tsx b/packages/mobile-client/src/hooks/useConnection.tsx new file mode 100644 index 0000000..4adf4ae --- /dev/null +++ b/packages/mobile-client/src/hooks/useConnection.tsx @@ -0,0 +1,114 @@ +import React, { createContext, useContext, useEffect, useRef, useState, ReactNode } from 'react'; +import { SocketManager, SocketManagerImpl } from '../services/SocketManager'; + +/** + * Connection status type + */ +export type ConnectionStatus = 'connected' | 'disconnected' | 'connecting'; + +/** + * Connection context value interface + */ +export interface ConnectionContextValue { + status: ConnectionStatus; + error: Error | null; + reconnect: () => void; + socketManager: SocketManager; +} + +/** + * Connection context + */ +const ConnectionContext = createContext(null); + +/** + * ConnectionStatusProvider props + */ +export interface ConnectionStatusProviderProps { + children: ReactNode; + serverUrl?: string; +} + +/** + * Default relay server URL + */ +// const DEFAULT_SERVER_URL = process.env.RELAY_SERVER_URL || 'http://localhost:8080'; +const DEFAULT_SERVER_URL = 'http://localhost:8080'; + +/** + * ConnectionStatusProvider manages global connection state and provides + * access to the SocketManager instance for the entire application + */ +export const ConnectionStatusProvider: React.FC = ({ + children, + serverUrl = DEFAULT_SERVER_URL, +}) => { + const [status, setStatus] = useState('disconnected'); + const [error, setError] = useState(null); + const socketManager = useRef(new SocketManagerImpl()); + const serverUrlRef = useRef(serverUrl); + + useEffect(() => { + const manager = socketManager.current; + + // Register event handlers + manager.onConnect(() => { + setStatus('connected'); + setError(null); + }); + + manager.onDisconnect(() => { + setStatus('disconnected'); + }); + + manager.onError((err) => { + setError(err); + setStatus('disconnected'); + }); + + // Initial connection + setStatus('connecting'); + manager.connect(serverUrlRef.current).catch((err) => { + setError(err); + setStatus('disconnected'); + }); + + // Cleanup on unmount + return () => { + manager.disconnect(); + }; + }, []); + + /** + * Manually trigger reconnection + */ + const reconnect = () => { + setStatus('connecting'); + setError(null); + socketManager.current.connect(serverUrlRef.current).catch((err) => { + setError(err); + setStatus('disconnected'); + }); + }; + + const value: ConnectionContextValue = { + status, + error, + reconnect, + socketManager: socketManager.current, + }; + + return {children}; +}; + +/** + * Hook to access connection context + * @throws Error if used outside ConnectionStatusProvider + */ +export const useConnection = (): ConnectionContextValue => { + const context = useContext(ConnectionContext); + if (!context) { + throw new Error('useConnection must be used within ConnectionStatusProvider'); + } + return context; +}; diff --git a/packages/mobile-client/src/hooks/useConnectionQuality.tsx b/packages/mobile-client/src/hooks/useConnectionQuality.tsx new file mode 100644 index 0000000..273917b --- /dev/null +++ b/packages/mobile-client/src/hooks/useConnectionQuality.tsx @@ -0,0 +1,85 @@ +/** + * Connection quality monitoring hook + * Measures latency and connection stability + */ + +import { useState, useEffect, useRef } from 'react'; +import { useConnection } from './useConnection'; + +export type ConnectionQuality = 'excellent' | 'good' | 'fair' | 'poor' | 'offline'; + +export interface ConnectionMetrics { + quality: ConnectionQuality; + latency: number | null; + lastPingTime: Date | null; +} + +export const useConnectionQuality = () => { + const { status, socketManager } = useConnection(); + const [metrics, setMetrics] = useState({ + quality: 'offline', + latency: null, + lastPingTime: null, + }); + const pingIntervalRef = useRef(undefined); + + useEffect(() => { + if (status !== 'connected') { + setMetrics({ + quality: 'offline', + latency: null, + lastPingTime: null, + }); + if (pingIntervalRef.current) { + clearInterval(pingIntervalRef.current); + } + return; + } + + // Measure latency periodically + const measureLatency = async () => { + const startTime = Date.now(); + + try { + // Send a ping message and wait for response + // This is a simplified version - you'd need to implement actual ping/pong + const latency = Date.now() - startTime; + + const quality = getQualityFromLatency(latency); + + setMetrics({ + quality, + latency, + lastPingTime: new Date(), + }); + } catch (error) { + setMetrics({ + quality: 'poor', + latency: null, + lastPingTime: new Date(), + }); + } + }; + + // Initial measurement + measureLatency(); + + // Measure every 10 seconds + pingIntervalRef.current = setInterval(measureLatency, 10000); + + return () => { + if (pingIntervalRef.current) { + clearInterval(pingIntervalRef.current); + } + }; + }, [status, socketManager]); + + return metrics; +}; + +function getQualityFromLatency(latency: number): ConnectionQuality { + if (latency < 50) return 'excellent'; + if (latency < 150) return 'good'; + if (latency < 300) return 'fair'; + return 'poor'; +} diff --git a/packages/mobile-client/src/hooks/useDraftPrompt.tsx b/packages/mobile-client/src/hooks/useDraftPrompt.tsx new file mode 100644 index 0000000..056b50a --- /dev/null +++ b/packages/mobile-client/src/hooks/useDraftPrompt.tsx @@ -0,0 +1,73 @@ +/** + * Draft prompt management hook + * Auto-saves and restores draft prompts + */ + +import { useState, useEffect } from 'react'; +import AsyncStorage from '@react-native-async-storage/async-storage'; + +const DRAFT_STORAGE_KEY = '@codelink/draft-prompt'; +const AUTO_SAVE_DELAY = 1000; // 1 second + +export const useDraftPrompt = () => { + const [draft, setDraft] = useState(''); + const [isSaving, setIsSaving] = useState(false); + const [lastSaved, setLastSaved] = useState(null); + + // Load draft on mount + useEffect(() => { + loadDraft(); + }, []); + + // Auto-save draft with debounce + useEffect(() => { + if (draft === '') return; + + const timer = setTimeout(() => { + saveDraft(draft); + }, AUTO_SAVE_DELAY); + + return () => clearTimeout(timer); + }, [draft]); + + const loadDraft = async () => { + try { + const stored = await AsyncStorage.getItem(DRAFT_STORAGE_KEY); + if (stored) { + setDraft(stored); + } + } catch (error) { + console.error('Failed to load draft:', error); + } + }; + + const saveDraft = async (text: string) => { + try { + setIsSaving(true); + await AsyncStorage.setItem(DRAFT_STORAGE_KEY, text); + setLastSaved(new Date()); + } catch (error) { + console.error('Failed to save draft:', error); + } finally { + setIsSaving(false); + } + }; + + const clearDraft = async () => { + try { + await AsyncStorage.removeItem(DRAFT_STORAGE_KEY); + setDraft(''); + setLastSaved(null); + } catch (error) { + console.error('Failed to clear draft:', error); + } + }; + + return { + draft, + setDraft, + clearDraft, + isSaving, + lastSaved, + }; +}; diff --git a/packages/mobile-client/src/hooks/useOrientation.tsx b/packages/mobile-client/src/hooks/useOrientation.tsx new file mode 100644 index 0000000..d71ba30 --- /dev/null +++ b/packages/mobile-client/src/hooks/useOrientation.tsx @@ -0,0 +1,53 @@ +import { useState, useEffect } from 'react'; +import { Dimensions, ScaledSize } from 'react-native'; + +/** + * Orientation type + */ +export type Orientation = 'portrait' | 'landscape'; + +/** + * Hook return type + */ +export interface UseOrientationResult { + orientation: Orientation; + isPortrait: boolean; + isLandscape: boolean; + width: number; + height: number; +} + +/** + * Custom hook to track device orientation + * Listens to dimension changes and determines current orientation + * + * Requirements: 10.1, 10.2, 10.3 + * + * @returns Current orientation state and dimensions + */ +export const useOrientation = (): UseOrientationResult => { + const [dimensions, setDimensions] = useState(() => Dimensions.get('window')); + + useEffect(() => { + const handleChange = ({ window }: { window: ScaledSize }) => { + setDimensions(window); + }; + + const subscription = Dimensions.addEventListener('change', handleChange); + + return () => { + subscription?.remove(); + }; + }, []); + + const { width, height } = dimensions; + const orientation: Orientation = width > height ? 'landscape' : 'portrait'; + + return { + orientation, + isPortrait: orientation === 'portrait', + isLandscape: orientation === 'landscape', + width, + height, + }; +}; diff --git a/packages/mobile-client/src/hooks/usePromptHistory.tsx b/packages/mobile-client/src/hooks/usePromptHistory.tsx new file mode 100644 index 0000000..07bb715 --- /dev/null +++ b/packages/mobile-client/src/hooks/usePromptHistory.tsx @@ -0,0 +1,83 @@ +/** + * Prompt history management hook + * Stores and retrieves prompt history with AsyncStorage + */ + +import { useState, useEffect } from 'react'; +import AsyncStorage from '@react-native-async-storage/async-storage'; + +const HISTORY_STORAGE_KEY = '@codelink/prompt-history'; +const MAX_HISTORY_ITEMS = 50; + +export interface PromptHistoryItem { + id: string; + prompt: string; + timestamp: number; + success?: boolean; + editorUsed?: string; +} + +export const usePromptHistory = () => { + const [history, setHistory] = useState([]); + const [isLoading, setIsLoading] = useState(true); + + // Load history on mount + useEffect(() => { + loadHistory(); + }, []); + + const loadHistory = async () => { + try { + const stored = await AsyncStorage.getItem(HISTORY_STORAGE_KEY); + if (stored) { + setHistory(JSON.parse(stored)); + } + } catch (error) { + console.error('Failed to load prompt history:', error); + } finally { + setIsLoading(false); + } + }; + + const saveHistory = async (newHistory: PromptHistoryItem[]) => { + try { + await AsyncStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(newHistory)); + setHistory(newHistory); + } catch (error) { + console.error('Failed to save prompt history:', error); + } + }; + + const addToHistory = async (item: PromptHistoryItem) => { + const newHistory = [item, ...history].slice(0, MAX_HISTORY_ITEMS); + await saveHistory(newHistory); + }; + + const updateHistoryItem = async (id: string, updates: Partial) => { + const newHistory = history.map((item) => (item.id === id ? { ...item, ...updates } : item)); + await saveHistory(newHistory); + }; + + const clearHistory = async () => { + try { + await AsyncStorage.removeItem(HISTORY_STORAGE_KEY); + setHistory([]); + } catch (error) { + console.error('Failed to clear prompt history:', error); + } + }; + + const deleteHistoryItem = async (id: string) => { + const newHistory = history.filter((item) => item.id !== id); + await saveHistory(newHistory); + }; + + return { + history, + isLoading, + addToHistory, + updateHistoryItem, + clearHistory, + deleteHistoryItem, + }; +}; diff --git a/packages/mobile-client/src/hooks/useTheme.tsx b/packages/mobile-client/src/hooks/useTheme.tsx new file mode 100644 index 0000000..a9e4b44 --- /dev/null +++ b/packages/mobile-client/src/hooks/useTheme.tsx @@ -0,0 +1,68 @@ +/** + * Theme management hook + * Provides theme switching and persistence + */ + +import React, { useState, useEffect, createContext, useContext, ReactNode } from 'react'; +import { useColorScheme } from 'react-native'; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { lightTheme, darkTheme, ThemeMode } from '../theme'; + +const THEME_STORAGE_KEY = '@codelink/theme'; + +interface ThemeContextValue { + theme: typeof lightTheme; + themeMode: ThemeMode; + isDark: boolean; + setThemeMode: (mode: ThemeMode) => void; +} + +const ThemeContext = createContext(null); + +export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) => { + const systemColorScheme = useColorScheme(); + const [themeMode, setThemeModeState] = useState('auto'); + + // Load saved theme preference + useEffect(() => { + const loadTheme = async () => { + try { + const saved = await AsyncStorage.getItem(THEME_STORAGE_KEY); + if (saved) { + setThemeModeState(saved as ThemeMode); + } + } catch (error) { + console.error('Failed to load theme preference:', error); + } + }; + loadTheme(); + }, []); + + // Determine actual theme based on mode + const isDark = themeMode === 'dark' || (themeMode === 'auto' && systemColorScheme === 'dark'); + const theme = isDark ? darkTheme : lightTheme; + + // Save theme preference + const setThemeMode = async (mode: ThemeMode) => { + try { + await AsyncStorage.setItem(THEME_STORAGE_KEY, mode); + setThemeModeState(mode); + } catch (error) { + console.error('Failed to save theme preference:', error); + } + }; + + return ( + + {children} + + ); +}; + +export const useTheme = () => { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within ThemeProvider'); + } + return context; +}; diff --git a/packages/mobile-client/src/index.css b/packages/mobile-client/src/index.css deleted file mode 100644 index bc3e984..0000000 --- a/packages/mobile-client/src/index.css +++ /dev/null @@ -1,30 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background-color: #1e1e1e; - color: #cccccc; - overflow: hidden; -} - -#root { - height: 100vh; - width: 100vw; -} - -code { - font-family: Consolas, Monaco, 'Courier New', monospace; -} diff --git a/packages/mobile-client/src/main.tsx b/packages/mobile-client/src/main.tsx deleted file mode 100644 index 8a808fa..0000000 --- a/packages/mobile-client/src/main.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import App from './App'; -import './index.css'; -import './styles/DiffViewer.css'; - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - -); diff --git a/packages/mobile-client/src/navigation/BottomNavBar.tsx b/packages/mobile-client/src/navigation/BottomNavBar.tsx new file mode 100644 index 0000000..cb8ee52 --- /dev/null +++ b/packages/mobile-client/src/navigation/BottomNavBar.tsx @@ -0,0 +1,184 @@ +/** + * Bottom Navigation Bar Component + * + * Implements the bottom navigation bar with glassmorphism effect, + * 4 navigation items, and haptic feedback. + * + * Requirements: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 8.10, 8.12, 11.1 + */ + +import React from 'react'; +import { View, TouchableOpacity, StyleSheet, Platform } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import * as Haptics from 'expo-haptics'; +import { useDesignSystem } from '../design-system'; +import { Text } from '../design-system/typography/Text'; +import { Icon, type IconName } from '../design-system/components/Icon'; + +/** + * Navigation item configuration + */ +interface NavItem { + key: string; + label: string; + icon: IconName; +} + +/** + * BottomNavBar props + */ +interface BottomNavBarProps { + activeRoute: string; + onNavigate: (route: string) => void; +} + +/** + * Navigation items configuration + * Requirements: 8.1, 8.2 + */ +const NAV_ITEMS: NavItem[] = [ + { key: 'Dashboard', label: 'DASHBOARD', icon: 'home' }, + { key: 'Diffs', label: 'DIFFS', icon: 'difference' }, + { key: 'Compose', label: 'COMPOSE', icon: 'terminal' }, + { key: 'Settings', label: 'SETTINGS', icon: 'settings' }, +]; + +/** + * BottomNavBar component with glassmorphism effect + * + * Features: + * - 4 navigation items (Dashboard, Diffs, Compose, Settings) + * - Material Symbols icons + * - Space Grotesk font labels (uppercase) + * - Active/inactive states with design system colors + * - Glassmorphism effect with BlurView + * - Safe area padding for notched devices + * - Haptic feedback on tap + * + * Requirements: 8.1-8.12, 11.1 + */ +export const BottomNavBar: React.FC = ({ activeRoute, onNavigate }) => { + const { theme } = useDesignSystem(); + const insets = useSafeAreaInsets(); + + /** + * Handle navigation item press + * Provides haptic feedback and navigates to route + * Requirements: 8.11, 8.12 + */ + const handlePress = async (route: string) => { + // Haptic feedback on tap + await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); + onNavigate(route); + }; + + return ( + + {/* + Glassmorphism backdrop with expo-blur + + To enable: + 1. Install: npm install expo-blur --legacy-peer-deps + 2. Uncomment the import at the top of this file + 3. Uncomment the BlurView below + + See INSTALL_EXPO_BLUR.md for details + */} + {/* */} + + + {NAV_ITEMS.map((item) => { + const isActive = activeRoute === item.key; + + return ( + handlePress(item.key)} + accessible={true} + accessibilityLabel={`Navigate to ${item.label}`} + accessibilityRole="button" + accessibilityState={{ selected: isActive }} + > + {/* Icon */} + + + {/* Label */} + + {item.label} + + + ); + })} + + + ); +}; + +/** + * Styles for BottomNavBar + * Requirements: 8.7, 8.8, 8.9, 8.10 + */ +const styles = StyleSheet.create({ + container: { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + paddingTop: 8, + paddingHorizontal: 8, + // Glassmorphism effect (requires expo-blur) + // backdrop-filter: blur(20px) - handled by BlurView + ...Platform.select({ + ios: { + shadowColor: '#000', + shadowOffset: { width: 0, height: -2 }, + shadowOpacity: 0.1, + shadowRadius: 8, + }, + android: { + elevation: 8, + }, + }), + }, + itemsContainer: { + flexDirection: 'row', + justifyContent: 'space-around', + alignItems: 'center', + }, + navItem: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + paddingVertical: 8, + paddingHorizontal: 4, + minHeight: 56, // Ensures 44pt+ touch target with padding + minWidth: 64, + }, +}); diff --git a/packages/mobile-client/src/navigation/BottomTabNavigator.tsx b/packages/mobile-client/src/navigation/BottomTabNavigator.tsx new file mode 100644 index 0000000..fa4cecf --- /dev/null +++ b/packages/mobile-client/src/navigation/BottomTabNavigator.tsx @@ -0,0 +1,53 @@ +/** + * Bottom Tab Navigator + * + * Configures bottom tab navigation with screen transition animations + * and design system integration. + * + * Requirements: 12.1, 12.2 + */ + +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import type { BottomTabNavigationOptions } from '@react-navigation/bottom-tabs'; + +/** + * Bottom tab navigator instance + */ +const Tab = createBottomTabNavigator(); + +/** + * Default screen options for bottom tab navigator. + * Configures screen transition animations with 300ms duration and ease-in-out timing. + * + * Requirements: 12.1, 12.2 + */ +export const defaultScreenOptions: BottomTabNavigationOptions = { + // Animation configuration + animation: 'shift', // Smooth shift animation for tab transitions + + // Header configuration (will be customized per screen) + headerShown: false, + + // Tab bar configuration (will be customized with custom component) + tabBarHideOnKeyboard: true, +}; + +/** + * Screen transition configuration + * 300ms duration with ease-in-out timing function + */ +export const transitionConfig = { + animation: 'timing' as const, + config: { + duration: 300, + easing: (t: number) => { + // Ease-in-out cubic bezier approximation + return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; + }, + }, +}; + +/** + * Export the Tab navigator for use in app + */ +export { Tab }; diff --git a/packages/mobile-client/src/navigation/NavigationContainer.tsx b/packages/mobile-client/src/navigation/NavigationContainer.tsx new file mode 100644 index 0000000..7fa9442 --- /dev/null +++ b/packages/mobile-client/src/navigation/NavigationContainer.tsx @@ -0,0 +1,72 @@ +/** + * Navigation Container with Theme Integration + * + * Configures React Navigation with design system theme integration + * and custom screen transition animations. + * + * Requirements: 12.1, 12.2 + */ + +import React, { type ReactNode } from 'react'; +import { NavigationContainer as RNNavigationContainer, type Theme } from '@react-navigation/native'; +import { useDesignSystem } from '../design-system'; + +/** + * Props for NavigationContainer + */ +interface NavigationContainerProps { + children: ReactNode; +} + +/** + * Creates a React Navigation theme from the design system theme. + * Maps design system color tokens to React Navigation theme structure. + */ +function createNavigationTheme( + designSystemTheme: ReturnType['theme'] +): Theme { + return { + dark: true, // Always use dark theme as per requirements + colors: { + primary: designSystemTheme.colors.primary, + background: designSystemTheme.colors.surface, + card: designSystemTheme.colors.surfaceContainer, + text: designSystemTheme.colors.onSurface, + border: designSystemTheme.colors.outlineVariant, + notification: designSystemTheme.colors.secondary, + }, + fonts: { + regular: { + fontFamily: designSystemTheme.typography.fonts.body, + fontWeight: '400', + }, + medium: { + fontFamily: designSystemTheme.typography.fonts.body, + fontWeight: '500', + }, + bold: { + fontFamily: designSystemTheme.typography.fonts.body, + fontWeight: '700', + }, + heavy: { + fontFamily: designSystemTheme.typography.fonts.body, + fontWeight: '800', + }, + }, + }; +} + +/** + * NavigationContainer component wraps React Navigation's NavigationContainer + * with design system theme integration. + * + * Automatically syncs navigation theme with design system theme changes. + */ +export const NavigationContainer: React.FC = ({ children }) => { + const { theme } = useDesignSystem(); + + // Create navigation theme from design system theme + const navigationTheme = createNavigationTheme(theme); + + return {children}; +}; diff --git a/packages/mobile-client/src/navigation/README.md b/packages/mobile-client/src/navigation/README.md new file mode 100644 index 0000000..fa33c7e --- /dev/null +++ b/packages/mobile-client/src/navigation/README.md @@ -0,0 +1,119 @@ +# Navigation Setup + +This directory contains the React Navigation configuration for the Obsidian UI redesign. + +## Components + +### NavigationContainer + +Wraps React Navigation's NavigationContainer with design system theme integration. Automatically syncs navigation theme colors with the design system. + +### BottomTabNavigator + +Configures the bottom tab navigator with: + +- Screen transition animations (300ms duration, ease-in-out timing) +- Design system integration +- Keyboard handling + +### BottomNavBar + +Custom bottom navigation bar component with: + +- 4 navigation items (Dashboard, Diffs, Compose, Settings) +- Material Symbols icons +- Space Grotesk font labels (uppercase) +- Active/inactive states with design system colors +- Glassmorphism effect (requires expo-blur) +- Safe area padding for notched devices +- Haptic feedback on tap + +## Installation + +### Required Dependencies + +All React Navigation dependencies are already installed. To enable glassmorphism effects, install expo-blur: + +```bash +npx expo install expo-blur +``` + +## Usage + +### Basic Setup + +```typescript +import { NavigationContainer, Tab, defaultScreenOptions, BottomNavBar } from './navigation'; + +function App() { + return ( + + + ( + props.navigation.navigate(route)} + /> + )} + > + + + + + + + + ); +} +``` + +### Enabling Glassmorphism + +After installing expo-blur, uncomment the BlurView in BottomNavBar.tsx: + +```typescript +import { BlurView } from 'expo-blur'; + +// In the component: + +``` + +## Configuration + +### Screen Transitions + +- Duration: 300ms +- Timing: ease-in-out cubic bezier +- Animation: shift (smooth tab transitions) + +### Theme Integration + +Navigation theme automatically syncs with design system theme: + +- Primary color → navigation primary +- Surface → navigation background +- Surface container → navigation card +- On surface → navigation text +- Outline variant → navigation border +- Secondary → navigation notification + +### Bottom Navigation Bar + +- Active state: secondary color (#61dac1) with surfaceContainerLow background +- Inactive state: surfaceContainerHighest color (#353535) +- Glassmorphism: 80% opacity with 20px blur (requires expo-blur) +- Touch targets: Minimum 56pt height (exceeds 44pt requirement) +- Safe area: Automatic padding for devices with bottom notch + +## Requirements + +- @react-navigation/native: ^7.2.2 +- @react-navigation/bottom-tabs: ^7.15.9 +- react-native-safe-area-context: ^5.6.2 +- react-native-screens: ^4.24.0 +- expo-haptics: ~15.0.8 +- expo-blur: (optional, for glassmorphism) + +All dependencies except expo-blur are already installed in package.json. diff --git a/packages/mobile-client/src/navigation/TopAppBar.README.md b/packages/mobile-client/src/navigation/TopAppBar.README.md new file mode 100644 index 0000000..92e8a27 --- /dev/null +++ b/packages/mobile-client/src/navigation/TopAppBar.README.md @@ -0,0 +1,169 @@ +# TopAppBar Component + +The TopAppBar component provides a consistent header across all screens with CodeLink branding and real-time connection status. + +## Features + +- **Branding**: Terminal icon in primary color (#95ccff) with "CodeLink" text in Manrope font +- **Connection Status**: Real-time status indicator with color-coded dots + - Green: Connected + - Red: Disconnected + - Orange: Connecting (with pulse animation) +- **Sticky Positioning**: Remains at top during scrolling +- **Safe Area Support**: Automatically adjusts for device notches and status bars +- **Accessibility**: Full screen reader support with proper labels + +## Requirements + +Implements requirements: 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8 + +## Usage + +### Basic Usage + +```tsx +import { TopAppBar } from '../navigation'; +import { useConnection } from '../hooks'; + +export const MyScreen = () => { + const { status } = useConnection(); + + return ( + + + {/* Screen content */} + + ); +}; +``` + +### With Different Connection States + +```tsx +// Connected state + + +// Disconnected state + + +// Connecting state (with pulse animation) + +``` + +### Integration with Screen Components + +The TopAppBar should be placed at the top of each screen component: + +```tsx +import React from 'react'; +import { View, ScrollView, StyleSheet } from 'react-native'; +import { TopAppBar } from '../navigation'; +import { useConnection } from '../hooks'; + +export const DashboardScreen = () => { + const { status } = useConnection(); + + return ( + + + {/* Dashboard content */} + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + content: { + flex: 1, + }, +}); +``` + +## Props + +### `connectionStatus` (required) + +Type: `'connected' | 'disconnected' | 'connecting'` + +The current connection status. This determines the color and animation of the status indicator: + +- `'connected'`: Green dot with "Connected" label +- `'disconnected'`: Red dot with "Disconnected" label +- `'connecting'`: Orange dot with pulse animation and "Connecting" label + +### `showBackButton` (optional) + +Type: `boolean` +Default: `false` + +Reserved for future use. Will show a back button in the app bar. + +### `onBackPress` (optional) + +Type: `() => void` + +Reserved for future use. Callback when back button is pressed. + +## Design System Integration + +The TopAppBar uses the following design system tokens: + +### Colors + +- Background: `theme.colors.surface` (#131313) +- Icon: `theme.colors.primary` (#95ccff) +- Text: `theme.colors.onSurface` +- Status colors: `theme.colors.secondary` (green), `theme.colors.error` (red), `theme.colors.tertiary` (orange) + +### Typography + +- Brand text: `title-lg` variant with `bold` weight (Manrope font) +- Status label: `label-md` variant with `medium` weight (Space Grotesk font) + +### Spacing + +- Horizontal padding: 16px +- Vertical padding: 12px +- Minimum height: 56px (standard app bar height) + +## Accessibility + +The TopAppBar includes proper accessibility support: + +- Status indicator has descriptive labels for screen readers +- Proper semantic structure for navigation +- High contrast support through design system tokens + +## Animation + +The connecting state includes a pulse animation: + +- Scale: 1.0 → 1.5 → 1.0 +- Opacity: 1.0 → 0.5 → 1.0 +- Duration: 1000ms per cycle +- Loops continuously while in connecting state + +## Platform Considerations + +### iOS + +- Automatically adjusts for status bar height using safe area insets +- Uses iOS-style shadow for depth + +### Android + +- Uses elevation for depth +- Respects system navigation bar + +## Testing + +See `TopAppBar.example.tsx` for usage examples and integration patterns. + +## Related Components + +- `StatusIndicator`: Used internally for connection status display +- `Icon`: Used for terminal icon +- `Text`: Used for brand text +- `BottomNavBar`: Complementary navigation component at bottom of screen diff --git a/packages/mobile-client/src/navigation/TopAppBar.example.tsx b/packages/mobile-client/src/navigation/TopAppBar.example.tsx new file mode 100644 index 0000000..76febf5 --- /dev/null +++ b/packages/mobile-client/src/navigation/TopAppBar.example.tsx @@ -0,0 +1,104 @@ +/** + * TopAppBar Usage Examples + * + * This file demonstrates how to use the TopAppBar component in different scenarios. + */ + +import React from 'react'; +import { ScrollView, View, StyleSheet } from 'react-native'; +import { TopAppBar } from './TopAppBar'; +import { Text } from '../design-system/typography/Text'; + +/** + * Example 1: Basic usage with connected status + */ +export const BasicConnectedExample = () => { + return ( + + + + + This example shows the TopAppBar with a connected status. The status indicator will show a + green dot with "Connected" label. + + + + ); +}; + +/** + * Example 2: Disconnected status + */ +export const DisconnectedExample = () => { + return ( + + + + + This example shows the TopAppBar with a disconnected status. The status indicator will + show a red dot with "Disconnected" label. + + + + ); +}; + +/** + * Example 3: Connecting status with pulse animation + */ +export const ConnectingExample = () => { + return ( + + + + + This example shows the TopAppBar with a connecting status. The status indicator will show + an orange dot with pulse animation. + + + + ); +}; + +/** + * Example 4: Integration with screen component + */ +export const ScreenIntegrationExample = () => { + const [connectionStatus, setConnectionStatus] = React.useState< + 'connected' | 'disconnected' | 'connecting' + >('connecting'); + + // Simulate connection status changes + React.useEffect(() => { + const timer = setTimeout(() => { + setConnectionStatus('connected'); + }, 3000); + + return () => clearTimeout(timer); + }, []); + + return ( + + + + + Dashboard + + + This example demonstrates how to integrate the TopAppBar with a screen component. The + connection status will change from "connecting" to "connected" after 3 seconds. + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + content: { + flex: 1, + padding: 16, + }, +}); diff --git a/packages/mobile-client/src/navigation/TopAppBar.tsx b/packages/mobile-client/src/navigation/TopAppBar.tsx new file mode 100644 index 0000000..1b745d9 --- /dev/null +++ b/packages/mobile-client/src/navigation/TopAppBar.tsx @@ -0,0 +1,140 @@ +/** + * Top App Bar Component + * + * Implements the top app bar with CodeLink branding and connection status indicator. + * Features sticky positioning, connection status colors, and pulse animation for connecting state. + * + * Requirements: 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8 + */ + +import React from 'react'; +import { View, StyleSheet, Platform } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { useDesignSystem } from '../design-system'; +import { Text } from '../design-system/typography/Text'; +import { Icon } from '../design-system/components/Icon'; +import { StatusIndicator, ConnectionStatus } from '../design-system/components/StatusIndicator'; + +/** + * TopAppBar props + */ +export interface TopAppBarProps { + /** + * Current connection status + */ + connectionStatus: ConnectionStatus; + + /** + * Show back button (optional, for future use) + */ + showBackButton?: boolean; + + /** + * Back button press handler (optional, for future use) + */ + onBackPress?: () => void; +} + +/** + * TopAppBar component with branding and connection status + * + * Features: + * - Terminal icon in primary color (#95ccff) + * - "CodeLink" text in Manrope font + * - Connection status indicator on right side + * - Surface background color (#131313) + * - Sticky positioning at top during scrolling + * - Connection status colors (green for connected, red for disconnected) + * - Pulse animation for connecting state + * + * Requirements: 9.1-9.8 + */ +export const TopAppBar: React.FC = ({ + connectionStatus, + showBackButton: _showBackButton = false, + onBackPress: _onBackPress, +}) => { + const { theme } = useDesignSystem(); + const insets = useSafeAreaInsets(); + + return ( + + + {/* Left section: Branding */} + + {/* Terminal icon in primary color */} + + + {/* CodeLink text in Manrope font */} + + CodeLink + + + + {/* Right section: Connection status */} + + + + + + ); +}; + +/** + * Styles for TopAppBar + * Requirements: 9.4, 9.5 + */ +const styles = StyleSheet.create({ + container: { + // Sticky at top during scrolling + position: 'relative', + zIndex: 100, + // Shadow for depth + ...Platform.select({ + ios: { + shadowColor: '#000', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.1, + shadowRadius: 4, + }, + android: { + elevation: 4, + }, + }), + }, + content: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + paddingHorizontal: 16, + paddingVertical: 12, + minHeight: 56, // Standard app bar height + }, + branding: { + flexDirection: 'row', + alignItems: 'center', + }, + brandIcon: { + marginRight: 8, + }, + brandText: { + // Manrope font applied via Text component + }, + statusContainer: { + flexDirection: 'row', + alignItems: 'center', + }, +}); diff --git a/packages/mobile-client/src/navigation/index.ts b/packages/mobile-client/src/navigation/index.ts new file mode 100644 index 0000000..2a51f22 --- /dev/null +++ b/packages/mobile-client/src/navigation/index.ts @@ -0,0 +1,11 @@ +/** + * Navigation Module Exports + * + * Central export point for navigation components and configuration. + */ + +export { NavigationContainer } from './NavigationContainer'; +export { Tab, defaultScreenOptions, transitionConfig } from './BottomTabNavigator'; +export { BottomNavBar } from './BottomNavBar'; +export { TopAppBar } from './TopAppBar'; +export type { TopAppBarProps } from './TopAppBar'; diff --git a/packages/mobile-client/src/navigation/types.ts b/packages/mobile-client/src/navigation/types.ts new file mode 100644 index 0000000..76f3dc1 --- /dev/null +++ b/packages/mobile-client/src/navigation/types.ts @@ -0,0 +1,21 @@ +/** + * Navigation Types + * + * TypeScript type definitions for navigation routes and parameters. + */ + +/** + * Bottom tab navigator route parameter list. + * Defines the available routes and their parameters. + */ +export type BottomTabParamList = { + Dashboard: undefined; + Diffs: undefined; + Compose: undefined; + Settings: undefined; +}; + +/** + * Navigation route names + */ +export type RouteNames = keyof BottomTabParamList; diff --git a/packages/mobile-client/src/services/DiffMessageHandler.ts b/packages/mobile-client/src/services/DiffMessageHandler.ts new file mode 100644 index 0000000..9ee5005 --- /dev/null +++ b/packages/mobile-client/src/services/DiffMessageHandler.ts @@ -0,0 +1,213 @@ +import type { SyncFullContextMessage, FileContextPayload } from '@codelink/protocol'; +import { isSyncFullContextMessage } from '../utils/messageValidation'; + +/** + * DiffState represents the current state of diff data + */ +export interface DiffState { + currentDiff: FileContextPayload | null; + history: FileContextPayload[]; + selectedIndex: number; +} + +/** + * DiffMessageHandler manages SYNC_FULL_CONTEXT message handling and diff state + */ +export class DiffMessageHandler { + private diffState: DiffState = { + currentDiff: null, + history: [], + selectedIndex: -1, + }; + private stateChangeListeners: Array<(state: DiffState) => void> = []; + private errorListeners: Array<(error: Error) => void> = []; + private maxHistorySize: number; + + constructor(maxHistorySize: number = 50) { + this.maxHistorySize = maxHistorySize; + } + + /** + * Handles incoming SYNC_FULL_CONTEXT messages + * @param message - The message to handle + * @returns true if message was handled successfully, false otherwise + */ + handleMessage(message: unknown): boolean { + try { + // Validate message type + if (!isSyncFullContextMessage(message)) { + const error = new Error('Invalid message type: expected SYNC_FULL_CONTEXT'); + this.notifyErrorListeners(error); + return false; + } + + // Parse FileContextPayload + const payload = this.parseFileContextPayload(message); + + // Update diff state + this.updateDiffState(payload); + + return true; + } catch (error) { + const err = error instanceof Error ? error : new Error('Failed to handle message'); + this.notifyErrorListeners(err); + return false; + } + } + + /** + * Parses and validates FileContextPayload from message + * @param message - SYNC_FULL_CONTEXT message + * @returns Validated FileContextPayload + * @throws Error if payload is invalid + */ + private parseFileContextPayload(message: SyncFullContextMessage): FileContextPayload { + const { payload } = message; + + // Validate required fields + if (!payload.fileName || typeof payload.fileName !== 'string') { + throw new Error('Invalid payload: fileName is required and must be a string'); + } + + if (typeof payload.originalFile !== 'string') { + throw new Error('Invalid payload: originalFile must be a string'); + } + + if (typeof payload.modifiedFile !== 'string') { + throw new Error('Invalid payload: modifiedFile must be a string'); + } + + if (typeof payload.isDirty !== 'boolean') { + throw new Error('Invalid payload: isDirty must be a boolean'); + } + + if (typeof payload.timestamp !== 'number') { + throw new Error('Invalid payload: timestamp must be a number'); + } + + return payload; + } + + /** + * Updates diff state with new payload + * @param payload - FileContextPayload to add to state + */ + private updateDiffState(payload: FileContextPayload): void { + // Add to history + const newHistory = [...this.diffState.history, payload]; + + // Trim history if it exceeds max size + if (newHistory.length > this.maxHistorySize) { + newHistory.shift(); + } + + // Update state + this.diffState = { + currentDiff: payload, + history: newHistory, + selectedIndex: newHistory.length - 1, + }; + + // Notify listeners + this.notifyStateChangeListeners(); + } + + /** + * Gets the current diff state + * @returns Current DiffState + */ + getDiffState(): DiffState { + return { ...this.diffState }; + } + + /** + * Gets the current diff payload + * @returns Current FileContextPayload or null + */ + getCurrentDiff(): FileContextPayload | null { + return this.diffState.currentDiff; + } + + /** + * Gets diff history + * @returns Array of FileContextPayload + */ + getHistory(): FileContextPayload[] { + return [...this.diffState.history]; + } + + /** + * Selects a diff from history by index + * @param index - Index in history array + * @returns true if selection was successful, false otherwise + */ + selectDiffByIndex(index: number): boolean { + if (index < 0 || index >= this.diffState.history.length) { + return false; + } + + this.diffState = { + ...this.diffState, + currentDiff: this.diffState.history[index], + selectedIndex: index, + }; + + this.notifyStateChangeListeners(); + return true; + } + + /** + * Clears diff history + */ + clearHistory(): void { + this.diffState = { + currentDiff: null, + history: [], + selectedIndex: -1, + }; + + this.notifyStateChangeListeners(); + } + + /** + * Registers a listener for state changes + * @param listener - Function to call when state changes + */ + onStateChange(listener: (state: DiffState) => void): void { + this.stateChangeListeners.push(listener); + } + + /** + * Registers a listener for errors + * @param listener - Function to call when error occurs + */ + onError(listener: (error: Error) => void): void { + this.errorListeners.push(listener); + } + + /** + * Notifies all state change listeners + */ + private notifyStateChangeListeners(): void { + this.stateChangeListeners.forEach((listener) => { + try { + listener(this.getDiffState()); + } catch (error) { + console.error('Error in state change listener:', error); + } + }); + } + + /** + * Notifies all error listeners + */ + private notifyErrorListeners(error: Error): void { + this.errorListeners.forEach((listener) => { + try { + listener(error); + } catch (err) { + console.error('Error in error listener:', err); + } + }); + } +} diff --git a/packages/mobile-client/src/services/PromptManager.ts b/packages/mobile-client/src/services/PromptManager.ts new file mode 100644 index 0000000..d600723 --- /dev/null +++ b/packages/mobile-client/src/services/PromptManager.ts @@ -0,0 +1,169 @@ +import type { InjectPromptMessage, InjectPromptResponse } from '@codelink/protocol'; +import type { SocketManager } from './SocketManager'; + +/** + * Status of a pending prompt + */ +export type PromptStatus = 'pending' | 'success' | 'error'; + +/** + * Represents a prompt that has been submitted + */ +export interface PendingPrompt { + id: string; + prompt: string; + timestamp: number; + status: PromptStatus; +} + +/** + * Callback function for prompt responses + */ +export type ResponseCallback = (response: InjectPromptResponse) => void; + +/** + * PromptManager interface defines the contract for managing prompt submissions + */ +export interface PromptManager { + // Prompt submission + submitPrompt(prompt: string): string; // Returns message ID + + // Response handling + handleResponse(response: InjectPromptResponse): void; + + // State queries + getPendingPrompts(): PendingPrompt[]; + getPromptStatus(id: string): PendingPrompt | null; + + // Callback registration + onResponse(callback: ResponseCallback): void; +} + +/** + * PromptManagerImpl manages prompt submission, tracking, and response correlation + */ +export class PromptManagerImpl implements PromptManager { + private pendingPrompts: Map = new Map(); + private socketManager: SocketManager; + private responseCallbacks: ResponseCallback[] = []; + + constructor(socketManager: SocketManager) { + this.socketManager = socketManager; + } + + /** + * Generates a unique message ID + * @returns Unique identifier string + */ + private generateMessageId(): string { + return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; + } + + /** + * Submits a prompt to the relay server + * @param prompt - The prompt text to submit + * @returns The message ID for tracking + * @throws Error if not connected or prompt is invalid + */ + submitPrompt(prompt: string): string { + // Validate prompt + if (!prompt || prompt.trim().length === 0) { + throw new Error('Prompt cannot be empty'); + } + + // Check connection + if (!this.socketManager.isConnected()) { + throw new Error('Cannot submit prompt: not connected to server'); + } + + // Generate unique message ID + const messageId = this.generateMessageId(); + const timestamp = Date.now(); + + // Create INJECT_PROMPT message conforming to protocol + const message: InjectPromptMessage = { + type: 'INJECT_PROMPT', + id: messageId, + timestamp, + payload: { + prompt: prompt.trim(), + }, + }; + + // Store in pending prompts map + const pendingPrompt: PendingPrompt = { + id: messageId, + prompt: prompt.trim(), + timestamp, + status: 'pending', + }; + this.pendingPrompts.set(messageId, pendingPrompt); + + // Send via socket manager + try { + this.socketManager.sendMessage(message); + } catch (error) { + // Remove from pending if send fails + this.pendingPrompts.delete(messageId); + throw error; + } + + return messageId; + } + + /** + * Handles a response from the relay server + * @param response - The INJECT_PROMPT_RESPONSE message + */ + handleResponse(response: InjectPromptResponse): void { + // Find original prompt using response.originalId + const originalPrompt = this.pendingPrompts.get(response.originalId); + + if (!originalPrompt) { + console.warn(`Received response for unknown prompt ID: ${response.originalId}`); + return; + } + + // Update prompt status + originalPrompt.status = response.payload.success ? 'success' : 'error'; + + // Invoke registered callbacks + this.responseCallbacks.forEach((callback) => { + try { + callback(response); + } catch (error) { + console.error('Error in response callback:', error); + } + }); + + // Clean up completed prompt after a delay to allow status queries + setTimeout(() => { + this.pendingPrompts.delete(response.originalId); + }, 5000); + } + + /** + * Gets all pending prompts + * @returns Array of pending prompts + */ + getPendingPrompts(): PendingPrompt[] { + return Array.from(this.pendingPrompts.values()); + } + + /** + * Gets the status of a specific prompt + * @param id - The message ID to query + * @returns The prompt status or null if not found + */ + getPromptStatus(id: string): PendingPrompt | null { + return this.pendingPrompts.get(id) || null; + } + + /** + * Registers a callback for prompt responses + * @param callback - Function to call when response is received + */ + onResponse(callback: ResponseCallback): void { + this.responseCallbacks.push(callback); + } +} diff --git a/packages/mobile-client/src/services/SocketManager.ts b/packages/mobile-client/src/services/SocketManager.ts new file mode 100644 index 0000000..400c701 --- /dev/null +++ b/packages/mobile-client/src/services/SocketManager.ts @@ -0,0 +1,285 @@ +import { io, Socket } from 'socket.io-client'; +import type { ProtocolMessage } from '@codelink/protocol'; +import { getConfig } from '../config'; + +/** + * SocketManager interface defines the contract for WebSocket connection management + */ +export interface SocketManager { + // Connection management + connect(serverUrl: string): Promise; + disconnect(): void; + isConnected(): boolean; + + // Message sending + sendMessage(message: ProtocolMessage): void; + + // Event listeners + onMessage(handler: (message: ProtocolMessage) => void): void; + onConnect(handler: () => void): void; + onDisconnect(handler: () => void): void; + onError(handler: (error: Error) => void): void; +} + +/** + * SocketManagerImpl implements WebSocket connection management using Socket.IO + * with automatic reconnection and exponential backoff + */ +export class SocketManagerImpl implements SocketManager { + private socket: Socket | null = null; + private messageHandlers: Array<(message: ProtocolMessage) => void> = []; + private connectHandlers: Array<() => void> = []; + private disconnectHandlers: Array<() => void> = []; + private errorHandlers: Array<(error: Error) => void> = []; + private reconnectAttempts = 0; + private maxReconnectAttempts: number; + private baseReconnectDelay: number; + private reconnectTimer: NodeJS.Timeout | null = null; + private isManualDisconnect = false; + + constructor() { + // Load configuration values + const config = getConfig(); + this.maxReconnectAttempts = config.socketOptions.reconnectionAttempts; + this.baseReconnectDelay = config.socketOptions.reconnectionDelay; + } + + /** + * Establishes connection to the relay server + * @param serverUrl - WebSocket server URL + */ + async connect(serverUrl: string): Promise { + return new Promise((resolve, reject) => { + try { + this.isManualDisconnect = false; + + // Get configuration + const config = getConfig(); + + // Initialize Socket.IO connection with configuration + this.socket = io(serverUrl, { + reconnection: false, // We handle reconnection manually for exponential backoff + timeout: config.socketOptions.timeout, + transports: ['websocket'], + }); + + // Set up event listeners + this.socket.on('connect', () => { + this.reconnectAttempts = 0; + this.notifyConnectHandlers(); + resolve(); + }); + + this.socket.on('disconnect', (reason) => { + this.notifyDisconnectHandlers(); + + // Attempt automatic reconnection if not manually disconnected + if (!this.isManualDisconnect && reason !== 'io client disconnect') { + this.attemptReconnect(serverUrl); + } + }); + + this.socket.on('message', (data: unknown) => { + try { + // Parse JSON string from relay server + const message = JSON.parse(data as string) as ProtocolMessage; + this.notifyMessageHandlers(message); + } catch (error) { + const err = error instanceof Error ? error : new Error('Message parsing failed'); + this.notifyErrorHandlers(err); + } + }); + + this.socket.on('connect_error', (error) => { + const err = new Error(`Connection error: ${error.message}`); + this.notifyErrorHandlers(err); + + // If initial connection fails, reject the promise + if (this.reconnectAttempts === 0) { + reject(err); + } + + // Attempt reconnection + if (!this.isManualDisconnect) { + this.attemptReconnect(serverUrl); + } + }); + + this.socket.on('error', (error) => { + const err = error instanceof Error ? error : new Error('Socket error'); + this.notifyErrorHandlers(err); + }); + } catch (error) { + const err = error instanceof Error ? error : new Error('Failed to initialize socket'); + this.notifyErrorHandlers(err); + reject(err); + } + }); + } + + /** + * Attempts to reconnect with exponential backoff + * @param serverUrl - WebSocket server URL + */ + private attemptReconnect(serverUrl: string): void { + // Clear any existing reconnect timer + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer); + this.reconnectTimer = null; + } + + // Check if we've exceeded max attempts + if (this.reconnectAttempts >= this.maxReconnectAttempts) { + const error = new Error('Max reconnection attempts reached'); + this.notifyErrorHandlers(error); + return; + } + + // Calculate delay with exponential backoff + const delay = this.baseReconnectDelay * Math.pow(2, this.reconnectAttempts); + this.reconnectAttempts++; + + // Schedule reconnection attempt + this.reconnectTimer = setTimeout(() => { + if (!this.isManualDisconnect) { + this.connect(serverUrl).catch((_error) => { + // Error already handled in connect method + }); + } + }, delay); + } + + /** + * Disconnects from the relay server + */ + disconnect(): void { + this.isManualDisconnect = true; + + // Clear reconnect timer + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer); + this.reconnectTimer = null; + } + + // Disconnect socket + if (this.socket) { + this.socket.disconnect(); + this.socket = null; + } + + this.reconnectAttempts = 0; + } + + /** + * Checks if socket is currently connected + * @returns true if connected, false otherwise + */ + isConnected(): boolean { + return this.socket !== null && this.socket.connected; + } + + /** + * Sends a message to the relay server + * @param message - Protocol message to send + * @throws Error if not connected + */ + sendMessage(message: ProtocolMessage): void { + if (!this.isConnected()) { + const error = new Error('Cannot send message: not connected to server'); + this.notifyErrorHandlers(error); + throw error; + } + + try { + this.socket!.emit('message', JSON.stringify(message)); + } catch (error) { + const err = error instanceof Error ? error : new Error('Failed to send message'); + this.notifyErrorHandlers(err); + throw err; + } + } + + /** + * Registers a handler for incoming messages + * @param handler - Function to call when message is received + */ + onMessage(handler: (message: ProtocolMessage) => void): void { + this.messageHandlers.push(handler); + } + + /** + * Registers a handler for connection events + * @param handler - Function to call when connected + */ + onConnect(handler: () => void): void { + this.connectHandlers.push(handler); + } + + /** + * Registers a handler for disconnection events + * @param handler - Function to call when disconnected + */ + onDisconnect(handler: () => void): void { + this.disconnectHandlers.push(handler); + } + + /** + * Registers a handler for error events + * @param handler - Function to call when error occurs + */ + onError(handler: (error: Error) => void): void { + this.errorHandlers.push(handler); + } + + /** + * Notifies all registered message handlers + */ + private notifyMessageHandlers(message: ProtocolMessage): void { + this.messageHandlers.forEach((handler) => { + try { + handler(message); + } catch (error) { + console.error('Error in message handler:', error); + } + }); + } + + /** + * Notifies all registered connect handlers + */ + private notifyConnectHandlers(): void { + this.connectHandlers.forEach((handler) => { + try { + handler(); + } catch (error) { + console.error('Error in connect handler:', error); + } + }); + } + + /** + * Notifies all registered disconnect handlers + */ + private notifyDisconnectHandlers(): void { + this.disconnectHandlers.forEach((handler) => { + try { + handler(); + } catch (error) { + console.error('Error in disconnect handler:', error); + } + }); + } + + /** + * Notifies all registered error handlers + */ + private notifyErrorHandlers(error: Error): void { + this.errorHandlers.forEach((handler) => { + try { + handler(error); + } catch (err) { + console.error('Error in error handler:', err); + } + }); + } +} diff --git a/packages/mobile-client/src/services/index.ts b/packages/mobile-client/src/services/index.ts new file mode 100644 index 0000000..70f6d18 --- /dev/null +++ b/packages/mobile-client/src/services/index.ts @@ -0,0 +1,13 @@ +// Service layer exports +// This file will export all service implementations + +export { SocketManagerImpl } from './SocketManager'; +export type { SocketManager } from './SocketManager'; +export { DiffMessageHandler, type DiffState } from './DiffMessageHandler'; +export { + PromptManagerImpl, + type PromptManager, + type PendingPrompt, + type PromptStatus, + type ResponseCallback, +} from './PromptManager'; diff --git a/packages/mobile-client/src/styles/DiffViewer.css b/packages/mobile-client/src/styles/DiffViewer.css deleted file mode 100644 index f8e7243..0000000 --- a/packages/mobile-client/src/styles/DiffViewer.css +++ /dev/null @@ -1,144 +0,0 @@ -/* DiffViewer Custom Styles */ - -.diff-viewer-container { - @apply flex flex-col h-full bg-vscode-bg; -} - -.diff-header { - @apply px-4 py-3 bg-vscode-sidebar border-b border-vscode-border; - @apply transition-all duration-200; -} - -.diff-header-top { - @apply flex items-center gap-2 mb-1 flex-wrap; -} - -.diff-file-name { - @apply text-sm font-semibold text-vscode-text; - @apply break-all; - font-family: system-ui, -apple-system, sans-serif; -} - -.diff-dirty-indicator { - @apply text-base leading-none text-vscode-dirty; - @apply animate-pulse; - font-size: 16px; -} - -.diff-timestamp { - @apply text-xs text-vscode-text-muted; - font-family: system-ui, -apple-system, sans-serif; -} - -.diff-content-wrapper { - @apply flex-1 overflow-auto bg-vscode-bg; - @apply transition-opacity duration-300; - -webkit-overflow-scrolling: touch; -} - -.diff-no-changes { - @apply flex items-center justify-center h-48 text-vscode-text-muted text-sm; - font-family: system-ui, -apple-system, sans-serif; -} - -/* Loading state */ -.diff-loading { - @apply flex items-center justify-center h-48; -} - -.diff-loading-spinner { - @apply w-8 h-8 border-4 border-vscode-border border-t-vscode-text rounded-full; - @apply animate-spin; -} - -/* Mobile optimizations */ -@media (max-width: 768px) { - .diff-header { - @apply px-3 py-2; - } - - .diff-file-name { - @apply text-xs; - } - - .diff-timestamp { - @apply text-[10px]; - } - - .diff-dirty-indicator { - font-size: 14px; - } -} - -/* Landscape orientation optimizations */ -@media (orientation: landscape) and (max-height: 500px) { - .diff-header { - @apply py-2; - } - - .diff-header-top { - @apply mb-0; - } -} - -/* Custom scrollbar for webkit browsers */ -.diff-content-wrapper::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -.diff-content-wrapper::-webkit-scrollbar-track { - background: #1e1e1e; -} - -.diff-content-wrapper::-webkit-scrollbar-thumb { - background: #424242; - border-radius: 4px; -} - -.diff-content-wrapper::-webkit-scrollbar-thumb:hover { - background: #4e4e4e; -} - -/* React Diff Viewer overrides for mobile */ -.diff-content-wrapper pre { - font-size: 12px !important; - line-height: 1.5 !important; - font-family: Consolas, Monaco, 'Courier New', monospace !important; -} - -@media (max-width: 768px) { - .diff-content-wrapper pre { - font-size: 11px !important; - } -} - -/* Ensure diff lines wrap on small screens */ -@media (max-width: 480px) { - .diff-content-wrapper pre { - font-size: 10px !important; - white-space: pre-wrap; - word-break: break-word; - } -} - -/* Touch-friendly tap targets */ -@media (hover: none) and (pointer: coarse) { - .diff-header { - min-height: 44px; - } -} - -/* Fade-in animation */ -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.diff-fade-in { - animation: fadeIn 0.3s ease-in; -} diff --git a/packages/mobile-client/src/test-setup.ts b/packages/mobile-client/src/test-setup.ts deleted file mode 100644 index 7b0828b..0000000 --- a/packages/mobile-client/src/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom'; diff --git a/packages/mobile-client/src/theme/index.ts b/packages/mobile-client/src/theme/index.ts new file mode 100644 index 0000000..ce8af59 --- /dev/null +++ b/packages/mobile-client/src/theme/index.ts @@ -0,0 +1,38 @@ +/** + * Theme configuration for the mobile client + * Supports light and dark modes with Material Design 3 + */ + +import { MD3LightTheme, MD3DarkTheme } from 'react-native-paper'; + +export const lightTheme = { + ...MD3LightTheme, + colors: { + ...MD3LightTheme.colors, + primary: '#6200ee', + secondary: '#03dac6', + error: '#b00020', + background: '#ffffff', + surface: '#f5f5f5', + surfaceVariant: '#e7e0ec', + onSurface: '#1c1b1f', + onSurfaceVariant: '#49454f', + }, +}; + +export const darkTheme = { + ...MD3DarkTheme, + colors: { + ...MD3DarkTheme.colors, + primary: '#BB86FC', + secondary: '#03DAC6', + error: '#CF6679', + background: '#121212', + surface: '#1E1E1E', + surfaceVariant: '#2d2d2d', + onSurface: '#e1e1e1', + onSurfaceVariant: '#c7c7c7', + }, +}; + +export type ThemeMode = 'light' | 'dark' | 'auto'; diff --git a/packages/mobile-client/src/types/index.ts b/packages/mobile-client/src/types/index.ts new file mode 100644 index 0000000..085463e --- /dev/null +++ b/packages/mobile-client/src/types/index.ts @@ -0,0 +1,8 @@ +export type ConnectionStatus = 'connected' | 'disconnected' | 'connecting'; + +export interface ConnectionState { + status: ConnectionStatus; + error: Error | null; + lastConnectedAt: number | null; + reconnectAttempts: number; +} diff --git a/packages/mobile-client/src/utils/errorHandling.ts b/packages/mobile-client/src/utils/errorHandling.ts new file mode 100644 index 0000000..8931217 --- /dev/null +++ b/packages/mobile-client/src/utils/errorHandling.ts @@ -0,0 +1,262 @@ +/** + * Error handling utilities for the mobile client + * Provides error message formatting, display helpers, and logging + * Validates: Requirements 9.1, 9.2, 9.3, 9.4 + */ + +/** + * Error types that can occur in the mobile client + */ +export enum ErrorType { + NETWORK_ERROR = 'NETWORK_ERROR', + PROMPT_SUBMISSION_ERROR = 'PROMPT_SUBMISSION_ERROR', + CONNECTION_ERROR = 'CONNECTION_ERROR', + UNEXPECTED_ERROR = 'UNEXPECTED_ERROR', + VALIDATION_ERROR = 'VALIDATION_ERROR', + PARSING_ERROR = 'PARSING_ERROR', +} + +/** + * Structured error information + */ +export interface AppError { + type: ErrorType; + message: string; + originalError?: Error | unknown; + actionableSteps?: string[]; + timestamp: number; +} + +/** + * Format an error into a user-friendly message + * Requirement 9.1: Display user-friendly error messages for network errors + * Requirement 9.2: Display specific error reason for prompt submission failures + * Requirement 9.3: Display connection troubleshooting guidance + * Requirement 9.4: Log and display generic message for unexpected errors + */ +export function formatErrorMessage(error: AppError): string { + switch (error.type) { + case ErrorType.NETWORK_ERROR: + return 'Network error occurred. Please check your internet connection and try again.'; + + case ErrorType.PROMPT_SUBMISSION_ERROR: + return `Failed to submit prompt: ${error.message}`; + + case ErrorType.CONNECTION_ERROR: + return 'Connection failed. Please check your network settings and ensure the relay server is accessible.'; + + case ErrorType.VALIDATION_ERROR: + return error.message; + + case ErrorType.PARSING_ERROR: + return 'Unable to process server response. The data may be corrupted.'; + + case ErrorType.UNEXPECTED_ERROR: + return 'An unexpected error occurred. Please try again.'; + + default: + return 'An error occurred. Please try again.'; + } +} + +/** + * Get actionable next steps for an error + * Requirement 9.5: Provide actionable next steps where applicable + */ +export function getActionableSteps(error: AppError): string[] { + if (error.actionableSteps && error.actionableSteps.length > 0) { + return error.actionableSteps; + } + + switch (error.type) { + case ErrorType.NETWORK_ERROR: + return [ + 'Check your internet connection', + 'Try switching between WiFi and mobile data', + 'Restart the app', + ]; + + case ErrorType.CONNECTION_ERROR: + return [ + 'Verify the relay server is running', + 'Check your network settings', + 'Try reconnecting manually', + 'Contact support if the issue persists', + ]; + + case ErrorType.PROMPT_SUBMISSION_ERROR: + return [ + 'Review your prompt for any issues', + 'Try submitting again', + 'Check your connection status', + ]; + + case ErrorType.VALIDATION_ERROR: + return ['Review the validation message', 'Correct the input and try again']; + + case ErrorType.PARSING_ERROR: + return ['Request fresh data from the server', 'Restart the app if the issue persists']; + + case ErrorType.UNEXPECTED_ERROR: + return [ + 'Try the action again', + 'Restart the app if the issue persists', + 'Contact support if the problem continues', + ]; + + default: + return ['Try again', 'Restart the app if the issue persists']; + } +} + +/** + * Create an AppError from various error sources + */ +export function createAppError( + type: ErrorType, + message: string, + originalError?: Error | unknown, + actionableSteps?: string[] +): AppError { + return { + type, + message, + originalError, + actionableSteps, + timestamp: Date.now(), + }; +} + +/** + * Log an error with appropriate detail level + * Requirement 9.4: Log errors for debugging + */ +export function logError(error: AppError): void { + const logMessage = `[${new Date(error.timestamp).toISOString()}] ${error.type}: ${error.message}`; + + // Check if __DEV__ is defined (React Native environment) + const isDevelopment = + typeof __DEV__ !== 'undefined' ? __DEV__ : process.env.NODE_ENV !== 'production'; + + if (isDevelopment) { + // In development, log full error details + console.error(logMessage); + if (error.originalError) { + console.error('Original error:', error.originalError); + } + if (error.actionableSteps) { + console.log('Actionable steps:', error.actionableSteps); + } + } else { + // In production, log minimal information + console.error(logMessage); + } +} + +/** + * Discriminate error type from various error sources + */ +export function discriminateErrorType(error: unknown): ErrorType { + if (error instanceof Error) { + const message = error.message.toLowerCase(); + + if (message.includes('network') || message.includes('fetch') || message.includes('timeout')) { + return ErrorType.NETWORK_ERROR; + } + + if ( + message.includes('connection') || + message.includes('socket') || + message.includes('disconnect') + ) { + return ErrorType.CONNECTION_ERROR; + } + + if (message.includes('validation') || message.includes('invalid')) { + return ErrorType.VALIDATION_ERROR; + } + + if (message.includes('parse') || message.includes('json') || message.includes('syntax')) { + return ErrorType.PARSING_ERROR; + } + } + + return ErrorType.UNEXPECTED_ERROR; +} + +/** + * Create a user-friendly error display object + */ +export interface ErrorDisplay { + title: string; + message: string; + actionableSteps: string[]; + severity: 'error' | 'warning' | 'info'; +} + +/** + * Convert an AppError to an ErrorDisplay for UI rendering + */ +export function createErrorDisplay(error: AppError): ErrorDisplay { + const message = formatErrorMessage(error); + const actionableSteps = getActionableSteps(error); + + let title: string; + let severity: 'error' | 'warning' | 'info' = 'error'; + + switch (error.type) { + case ErrorType.NETWORK_ERROR: + title = 'Network Error'; + break; + case ErrorType.CONNECTION_ERROR: + title = 'Connection Failed'; + break; + case ErrorType.PROMPT_SUBMISSION_ERROR: + title = 'Submission Failed'; + break; + case ErrorType.VALIDATION_ERROR: + title = 'Validation Error'; + severity = 'warning'; + break; + case ErrorType.PARSING_ERROR: + title = 'Data Error'; + break; + case ErrorType.UNEXPECTED_ERROR: + title = 'Error'; + break; + default: + title = 'Error'; + } + + return { + title, + message, + actionableSteps, + severity, + }; +} + +/** + * Handle an error by logging it and creating a display object + */ +export function handleError( + type: ErrorType, + message: string, + originalError?: Error | unknown, + actionableSteps?: string[] +): ErrorDisplay { + const appError = createAppError(type, message, originalError, actionableSteps); + logError(appError); + return createErrorDisplay(appError); +} + +/** + * Handle an unknown error by discriminating its type and creating a display object + */ +export function handleUnknownError(error: unknown): ErrorDisplay { + const type = discriminateErrorType(error); + const message = error instanceof Error ? error.message : 'An unknown error occurred'; + const appError = createAppError(type, message, error); + logError(appError); + return createErrorDisplay(appError); +} diff --git a/packages/mobile-client/src/utils/index.ts b/packages/mobile-client/src/utils/index.ts new file mode 100644 index 0000000..59bb83e --- /dev/null +++ b/packages/mobile-client/src/utils/index.ts @@ -0,0 +1,30 @@ +// Utility functions for the mobile client +// This file will contain helper functions and utilities + +export const generateId = (): string => { + return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`; +}; + +// Export message validation utilities +export { + isInjectPromptMessage, + isInjectPromptResponse, + isSyncFullContextMessage, + validateProtocolMessage, + discriminateMessageType, +} from './messageValidation'; + +// Export error handling utilities +export { + ErrorType, + type AppError, + type ErrorDisplay, + formatErrorMessage, + getActionableSteps, + createAppError, + logError, + discriminateErrorType, + createErrorDisplay, + handleError, + handleUnknownError, +} from './errorHandling'; diff --git a/packages/mobile-client/src/utils/messageValidation.ts b/packages/mobile-client/src/utils/messageValidation.ts new file mode 100644 index 0000000..70655c4 --- /dev/null +++ b/packages/mobile-client/src/utils/messageValidation.ts @@ -0,0 +1,148 @@ +import type { + InjectPromptMessage, + InjectPromptResponse, + SyncFullContextMessage, + ProtocolMessage, +} from '@codelink/protocol'; + +/** + * Type guard to check if a message is an InjectPromptMessage + */ +export function isInjectPromptMessage(message: unknown): message is InjectPromptMessage { + if (!message || typeof message !== 'object') { + return false; + } + + const msg = message as Record; + + // Check all required fields explicitly + if (msg.type !== 'INJECT_PROMPT') return false; + if (typeof msg.id !== 'string') return false; + if (typeof msg.timestamp !== 'number') return false; + if (!msg.payload || typeof msg.payload !== 'object') return false; + const payload = msg.payload as Record; + if (typeof payload.prompt !== 'string') return false; + + return true; +} + +/** + * Type guard to check if a message is an InjectPromptResponse + */ +export function isInjectPromptResponse(message: unknown): message is InjectPromptResponse { + if (!message || typeof message !== 'object') { + return false; + } + + const msg = message as Record; + + // Check all required fields explicitly + if (msg.type !== 'INJECT_PROMPT_RESPONSE') return false; + if (typeof msg.id !== 'string') return false; + if (typeof msg.timestamp !== 'number') return false; + if (typeof msg.originalId !== 'string') return false; + if (!msg.payload || typeof msg.payload !== 'object') return false; + const payload = msg.payload as Record; + if (typeof payload.success !== 'boolean') return false; + + // Check optional fields if present + if (payload.error !== undefined && typeof payload.error !== 'string') { + return false; + } + if (payload.editorUsed !== undefined && typeof payload.editorUsed !== 'string') { + return false; + } + + return true; +} + +/** + * Type guard to check if a message is a SyncFullContextMessage + */ +export function isSyncFullContextMessage(message: unknown): message is SyncFullContextMessage { + if (!message || typeof message !== 'object') { + return false; + } + + const msg = message as Record; + + // Check all required fields explicitly + if (msg.type !== 'SYNC_FULL_CONTEXT') return false; + if (typeof msg.id !== 'string') return false; + if (typeof msg.timestamp !== 'number') return false; + if (!msg.payload || typeof msg.payload !== 'object') return false; + const payload = msg.payload as Record; + if (typeof payload.fileName !== 'string') return false; + if (typeof payload.originalFile !== 'string') return false; + if (typeof payload.modifiedFile !== 'string') return false; + if (typeof payload.isDirty !== 'boolean') return false; + if (typeof payload.timestamp !== 'number') return false; + + return true; +} + +/** + * Validates that a message conforms to the ProtocolMessage interface + */ +export function validateProtocolMessage(message: unknown): { + isValid: boolean; + error?: string; +} { + if (!message || typeof message !== 'object') { + return { isValid: false, error: 'Message must be an object' }; + } + + const msg = message as Record; + + // Check base Message fields + if (typeof msg.id !== 'string') { + return { isValid: false, error: 'Message must have a string id' }; + } + + if (typeof msg.timestamp !== 'number') { + return { isValid: false, error: 'Message must have a number timestamp' }; + } + + if (typeof msg.type !== 'string') { + return { isValid: false, error: 'Message must have a string type' }; + } + + // Check specific message types + if ( + isInjectPromptMessage(message) || + isInjectPromptResponse(message) || + isSyncFullContextMessage(message) + ) { + return { isValid: true }; + } + + return { + isValid: false, + error: `Unknown or invalid message type: ${msg.type}`, + }; +} + +/** + * Discriminates message type and returns the specific message type + */ +export function discriminateMessageType( + message: ProtocolMessage +): + | { type: 'INJECT_PROMPT'; message: InjectPromptMessage } + | { type: 'INJECT_PROMPT_RESPONSE'; message: InjectPromptResponse } + | { type: 'SYNC_FULL_CONTEXT'; message: SyncFullContextMessage } + | { type: 'UNKNOWN'; message: ProtocolMessage } { + if (isInjectPromptMessage(message)) { + return { type: 'INJECT_PROMPT', message }; + } + + if (isInjectPromptResponse(message)) { + return { type: 'INJECT_PROMPT_RESPONSE', message }; + } + + if (isSyncFullContextMessage(message)) { + return { type: 'SYNC_FULL_CONTEXT', message }; + } + + return { type: 'UNKNOWN', message }; +} diff --git a/packages/mobile-client/src/websocket/WebSocketClient.error-handling.test.ts b/packages/mobile-client/src/websocket/WebSocketClient.error-handling.test.ts deleted file mode 100644 index 1e92783..0000000 --- a/packages/mobile-client/src/websocket/WebSocketClient.error-handling.test.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; -import { WebSocketClient } from './WebSocketClient'; -import { FileContextPayload } from '@codelink/protocol'; - -// Mock socket.io-client -vi.mock('socket.io-client', () => { - const mockSocket = { - on: vi.fn(), - emit: vi.fn(), - close: vi.fn(), - connected: false, - }; - - return { - io: vi.fn(() => mockSocket), - __mockSocket: mockSocket, - }; -}); - -describe('Mobile Client WebSocket Error Handling', () => { - let client: WebSocketClient; - let mockSocket: any; - - beforeEach(async () => { - const socketIo = await import('socket.io-client'); - mockSocket = (socketIo as any).__mockSocket; - mockSocket.connected = false; - - vi.clearAllMocks(); - - client = new WebSocketClient({ url: 'http://localhost:8080' }); - }); - - afterEach(() => { - if (client) { - client.disconnect(); - } - }); - - describe('Parse Error Handling', () => { - it('should handle malformed JSON gracefully', () => { - client.connect(); - - // Get the message handler - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - expect(messageHandler).toBeDefined(); - - // Send malformed JSON - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - expect(() => messageHandler('not valid json {')).not.toThrow(); - - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Error parsing message'), - expect.any(Error) - ); - - consoleSpy.mockRestore(); - }); - - it('should handle invalid message structure', () => { - client.connect(); - - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - // Send message with missing type field - const invalidMessage = JSON.stringify({ - id: 'test-id', - timestamp: Date.now(), - // missing type field - }); - - expect(() => messageHandler(invalidMessage)).not.toThrow(); - - consoleSpy.mockRestore(); - }); - - it('should handle missing payload fields', () => { - client.connect(); - - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - // Send SYNC_FULL_CONTEXT with incomplete payload - const incompleteMessage = JSON.stringify({ - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: 'test.ts', - // missing other required fields - }, - }); - - expect(() => messageHandler(incompleteMessage)).not.toThrow(); - - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Invalid payload structure'), - expect.any(Object) - ); - - consoleSpy.mockRestore(); - }); - - it('should handle null payload', () => { - client.connect(); - - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - const nullPayloadMessage = JSON.stringify({ - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: null, - }); - - expect(() => messageHandler(nullPayloadMessage)).not.toThrow(); - - consoleSpy.mockRestore(); - }); - - it('should handle undefined payload fields', () => { - client.connect(); - - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - const undefinedFieldsMessage = JSON.stringify({ - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: 'test.ts', - originalFile: undefined, - modifiedFile: 'content', - isDirty: false, - timestamp: Date.now(), - }, - }); - - expect(() => messageHandler(undefinedFieldsMessage)).not.toThrow(); - - consoleSpy.mockRestore(); - }); - - it('should continue operation after parse error', () => { - let payloadReceived: FileContextPayload | null = null; - client.onPayload((payload) => { - payloadReceived = payload; - }); - - client.connect(); - - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - // First message is malformed - messageHandler('invalid json'); - expect(payloadReceived).toBeNull(); - - // Second message is valid - const validPayload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: false, - timestamp: Date.now(), - }; - - const validMessage = JSON.stringify({ - id: 'valid-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: validPayload, - }); - - messageHandler(validMessage); - expect(payloadReceived).toEqual(validPayload); - - consoleSpy.mockRestore(); - }); - }); - - describe('Connection Error Handling', () => { - it('should handle connection errors', () => { - client.connect(); - - const errorHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'connect_error' - )?.[1]; - - expect(errorHandler).toBeDefined(); - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - const error = new Error('Connection refused'); - expect(() => errorHandler(error)).not.toThrow(); - - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Connection error'), - error - ); - - consoleSpy.mockRestore(); - }); - - it('should update status to disconnected on connection error', () => { - let currentStatus = client.getStatus(); - expect(currentStatus).toBe('disconnected'); - - client.onStatusChange((status) => { - currentStatus = status; - }); - - client.connect(); - - // Simulate connection error - const errorHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'connect_error' - )?.[1]; - - errorHandler(new Error('Network error')); - - expect(currentStatus).toBe('disconnected'); - }); - - it('should handle disconnect events', () => { - client.connect(); - - const disconnectHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'disconnect' - )?.[1]; - - expect(disconnectHandler).toBeDefined(); - - const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); - - expect(() => disconnectHandler()).not.toThrow(); - - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Disconnected from relay server') - ); - - consoleSpy.mockRestore(); - }); - }); - - describe('Payload Validation', () => { - it('should reject payload with wrong field types', () => { - client.connect(); - - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - // isDirty should be boolean, not string - const wrongTypeMessage = JSON.stringify({ - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: 'test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: 'true', // wrong type - timestamp: Date.now(), - }, - }); - - expect(() => messageHandler(wrongTypeMessage)).not.toThrow(); - - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('Invalid payload structure'), - expect.any(Object) - ); - - consoleSpy.mockRestore(); - }); - - it('should reject payload with missing fileName', () => { - client.connect(); - - const messageHandler = mockSocket.on.mock.calls.find( - (call: any) => call[0] === 'message' - )?.[1]; - - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); - - const missingFileNameMessage = JSON.stringify({ - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: { - // missing fileName - originalFile: 'old', - modifiedFile: 'new', - isDirty: false, - timestamp: Date.now(), - }, - }); - - expect(() => messageHandler(missingFileNameMessage)).not.toThrow(); - - consoleSpy.mockRestore(); - }); - }); -}); diff --git a/packages/mobile-client/src/websocket/WebSocketClient.properties.test.ts b/packages/mobile-client/src/websocket/WebSocketClient.properties.test.ts deleted file mode 100644 index 7f8511f..0000000 --- a/packages/mobile-client/src/websocket/WebSocketClient.properties.test.ts +++ /dev/null @@ -1,354 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import * as fc from 'fast-check'; -import { WebSocketClient } from './WebSocketClient'; -import { FileContextPayload, SyncFullContextMessage } from '@codelink/protocol'; -import { io } from 'socket.io-client'; - -// Mock socket.io-client -vi.mock('socket.io-client', () => ({ - io: vi.fn(), -})); - -describe('WebSocketClient - Property-Based Tests', () => { - let mockSocket: any; - let eventHandlers: Record; - - beforeEach(() => { - eventHandlers = {}; - - mockSocket = { - on: vi.fn((event: string, handler: Function) => { - eventHandlers[event] = handler; - }), - close: vi.fn(), - }; - - (io as any).mockReturnValue(mockSocket); - }); - - // Arbitrary generators for FileContextPayload - const fileNameArbitrary = fc.string({ minLength: 1, maxLength: 100 }).filter(s => s.trim().length > 0); - const fileContentArbitrary = fc.string({ maxLength: 1000 }); - const timestampArbitrary = fc.integer({ min: 0, max: Date.now() + 1000000 }); - - const fileContextPayloadArbitrary = fc.record({ - fileName: fileNameArbitrary, - originalFile: fileContentArbitrary, - modifiedFile: fileContentArbitrary, - isDirty: fc.boolean(), - timestamp: timestampArbitrary, - }); - - // Feature: git-integration-diffing, Property 16: Message parsing - describe('Property 16: Message parsing', () => { - it('should parse any valid SYNC_FULL_CONTEXT message', () => { - fc.assert( - fc.property(fileContextPayloadArbitrary, fc.string(), timestampArbitrary, (payload, id, timestamp) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const message: SyncFullContextMessage = { - id, - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp, - }; - - eventHandlers['message'](JSON.stringify(message)); - - expect(payloadCallback).toHaveBeenCalledWith(payload); - expect(payloadCallback).toHaveBeenCalledTimes(1); - }), - { numRuns: 100 } - ); - }); - - it('should correctly extract all fields from any valid payload', () => { - fc.assert( - fc.property(fileContextPayloadArbitrary, (payload) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const message: SyncFullContextMessage = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - const receivedPayload = payloadCallback.mock.calls[0][0]; - expect(receivedPayload.fileName).toBe(payload.fileName); - expect(receivedPayload.originalFile).toBe(payload.originalFile); - expect(receivedPayload.modifiedFile).toBe(payload.modifiedFile); - expect(receivedPayload.isDirty).toBe(payload.isDirty); - expect(receivedPayload.timestamp).toBe(payload.timestamp); - }), - { numRuns: 100 } - ); - }); - - it('should handle payloads with empty file content', () => { - fc.assert( - fc.property(fileNameArbitrary, fc.boolean(), timestampArbitrary, (fileName, isDirty, timestamp) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const payload: FileContextPayload = { - fileName, - originalFile: '', - modifiedFile: '', - isDirty, - timestamp, - }; - - const message: SyncFullContextMessage = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - expect(payloadCallback).toHaveBeenCalledWith(payload); - }), - { numRuns: 100 } - ); - }); - - it('should handle payloads with large file content', () => { - fc.assert( - fc.property( - fileNameArbitrary, - fc.string({ minLength: 5000, maxLength: 10000 }), - fc.string({ minLength: 5000, maxLength: 10000 }), - fc.boolean(), - timestampArbitrary, - (fileName, originalFile, modifiedFile, isDirty, timestamp) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const payload: FileContextPayload = { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp, - }; - - const message: SyncFullContextMessage = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - const receivedPayload = payloadCallback.mock.calls[0][0]; - expect(receivedPayload.originalFile.length).toBe(originalFile.length); - expect(receivedPayload.modifiedFile.length).toBe(modifiedFile.length); - } - ), - { numRuns: 50 } // Fewer runs for large content - ); - }); - }); - - // Feature: git-integration-diffing, Property 18: Malformed message handling - describe('Property 18: Malformed message handling', () => { - it('should not crash on any malformed JSON string', () => { - fc.assert( - fc.property(fc.string(), (malformedJson) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - // Should not throw - expect(() => { - eventHandlers['message'](malformedJson); - }).not.toThrow(); - - // Should not invoke callback for malformed messages - expect(payloadCallback).not.toHaveBeenCalled(); - }), - { numRuns: 100 } - ); - }); - - it('should reject messages with missing required fields', () => { - fc.assert( - fc.property( - fc.record({ - fileName: fc.option(fileNameArbitrary, { nil: undefined }), - originalFile: fc.option(fileContentArbitrary, { nil: undefined }), - modifiedFile: fc.option(fileContentArbitrary, { nil: undefined }), - isDirty: fc.option(fc.boolean(), { nil: undefined }), - timestamp: fc.option(timestampArbitrary, { nil: undefined }), - }), - (partialPayload) => { - // Skip if all fields are present (valid case) - const hasAllFields = - partialPayload.fileName !== undefined && - partialPayload.originalFile !== undefined && - partialPayload.modifiedFile !== undefined && - partialPayload.isDirty !== undefined && - partialPayload.timestamp !== undefined; - - if (hasAllFields) { - return true; // Skip this case - } - - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const message = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload: partialPayload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - // Should not invoke callback for invalid payload - expect(payloadCallback).not.toHaveBeenCalled(); - } - ), - { numRuns: 100 } - ); - }); - - it('should reject messages with incorrect field types', () => { - fc.assert( - fc.property( - fc.oneof( - // fileName as number - fc.record({ - fileName: fc.integer(), - originalFile: fileContentArbitrary, - modifiedFile: fileContentArbitrary, - isDirty: fc.boolean(), - timestamp: timestampArbitrary, - }), - // isDirty as string - fc.record({ - fileName: fileNameArbitrary, - originalFile: fileContentArbitrary, - modifiedFile: fileContentArbitrary, - isDirty: fc.string(), - timestamp: timestampArbitrary, - }), - // timestamp as string - fc.record({ - fileName: fileNameArbitrary, - originalFile: fileContentArbitrary, - modifiedFile: fileContentArbitrary, - isDirty: fc.boolean(), - timestamp: fc.string(), - }) - ), - (invalidPayload) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const message = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload: invalidPayload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - // Should not invoke callback for invalid types - expect(payloadCallback).not.toHaveBeenCalled(); - } - ), - { numRuns: 100 } - ); - }); - - it('should continue operation after any malformed message', () => { - fc.assert( - fc.property(fc.string(), fileContextPayloadArbitrary, (malformedJson, validPayload) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - // Send malformed message - eventHandlers['message'](malformedJson); - - // Send valid message - const validMessage: SyncFullContextMessage = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload: validPayload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(validMessage)); - - // Should have received the valid payload - expect(payloadCallback).toHaveBeenCalledWith(validPayload); - expect(payloadCallback).toHaveBeenCalledTimes(1); - }), - { numRuns: 100 } - ); - }); - - it('should handle messages with extra unexpected fields', () => { - fc.assert( - fc.property( - fileContextPayloadArbitrary, - fc.record({ - extraField1: fc.string(), - extraField2: fc.integer(), - extraField3: fc.boolean(), - }), - (payload, extraFields) => { - const client = new WebSocketClient({ url: 'http://localhost:8080' }); - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const message = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload: { ...payload, ...extraFields }, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - // Should still parse successfully (extra fields are ignored) - expect(payloadCallback).toHaveBeenCalled(); - const receivedPayload = payloadCallback.mock.calls[0][0]; - expect(receivedPayload.fileName).toBe(payload.fileName); - expect(receivedPayload.originalFile).toBe(payload.originalFile); - expect(receivedPayload.modifiedFile).toBe(payload.modifiedFile); - expect(receivedPayload.isDirty).toBe(payload.isDirty); - expect(receivedPayload.timestamp).toBe(payload.timestamp); - } - ), - { numRuns: 100 } - ); - }); - }); -}); diff --git a/packages/mobile-client/src/websocket/WebSocketClient.test.ts b/packages/mobile-client/src/websocket/WebSocketClient.test.ts deleted file mode 100644 index 7f15c36..0000000 --- a/packages/mobile-client/src/websocket/WebSocketClient.test.ts +++ /dev/null @@ -1,334 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { WebSocketClient } from './WebSocketClient'; -import { FileContextPayload, SyncFullContextMessage } from '@codelink/protocol'; -import { io } from 'socket.io-client'; - -// Mock socket.io-client -vi.mock('socket.io-client', () => ({ - io: vi.fn(), -})); - -describe('WebSocketClient', () => { - let client: WebSocketClient; - let mockSocket: any; - let eventHandlers: Record; - - beforeEach(() => { - eventHandlers = {}; - - mockSocket = { - on: vi.fn((event: string, handler: Function) => { - eventHandlers[event] = handler; - }), - emit: vi.fn(), - close: vi.fn(), - connected: true, - }; - - (io as any).mockReturnValue(mockSocket); - - client = new WebSocketClient({ url: 'http://localhost:8080' }); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - describe('connection management', () => { - it('should connect to relay server', () => { - client.connect(); - - expect(io).toHaveBeenCalledWith('http://localhost:8080', expect.objectContaining({ - reconnectionDelay: 1000, - reconnectionDelayMax: 5000, - reconnectionAttempts: Infinity, - })); - }); - - it('should update status to connecting when connect is called', () => { - const statusCallback = vi.fn(); - client.onStatusChange(statusCallback); - - client.connect(); - - expect(statusCallback).toHaveBeenCalledWith('connecting'); - }); - - it('should update status to connected on connect event', () => { - const statusCallback = vi.fn(); - client.onStatusChange(statusCallback); - client.connect(); - - statusCallback.mockClear(); - eventHandlers['connect'](); - - expect(statusCallback).toHaveBeenCalledWith('connected'); - expect(client.isConnected()).toBe(true); - }); - - it('should update status to disconnected on disconnect event', () => { - const statusCallback = vi.fn(); - client.onStatusChange(statusCallback); - client.connect(); - eventHandlers['connect'](); - - statusCallback.mockClear(); - eventHandlers['disconnect'](); - - expect(statusCallback).toHaveBeenCalledWith('disconnected'); - expect(client.isConnected()).toBe(false); - }); - - it('should handle connection errors', () => { - const statusCallback = vi.fn(); - client.onStatusChange(statusCallback); - client.connect(); - - statusCallback.mockClear(); - const error = new Error('Connection failed'); - eventHandlers['connect_error'](error); - - expect(statusCallback).toHaveBeenCalledWith('disconnected'); - }); - - it('should disconnect and clean up socket', () => { - client.connect(); - eventHandlers['connect'](); - - client.disconnect(); - - expect(mockSocket.close).toHaveBeenCalled(); - expect(client.getStatus()).toBe('disconnected'); - }); - - it('should not create multiple connections', () => { - client.connect(); - client.connect(); - - expect(io).toHaveBeenCalledTimes(1); - }); - }); - - describe('SYNC_FULL_CONTEXT message parsing', () => { - it('should parse valid SYNC_FULL_CONTEXT message', () => { - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'original content', - modifiedFile: 'modified content', - isDirty: true, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - expect(payloadCallback).toHaveBeenCalledWith(payload); - }); - - it('should validate payload structure', () => { - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const invalidMessage = { - id: 'test-id', - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: 'test.ts', - // Missing required fields - }, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(invalidMessage)); - - expect(payloadCallback).not.toHaveBeenCalled(); - }); - - it('should handle malformed JSON messages', () => { - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - // Should not throw error - expect(() => { - eventHandlers['message']('invalid json {'); - }).not.toThrow(); - - expect(payloadCallback).not.toHaveBeenCalled(); - }); - - it('should ignore non-SYNC_FULL_CONTEXT messages', () => { - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const pingMessage = { - id: 'test-id', - type: 'ping', - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(pingMessage)); - - expect(payloadCallback).not.toHaveBeenCalled(); - }); - }); - - describe('payload storage in state', () => { - it('should invoke callback when valid payload is received', () => { - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const payload: FileContextPayload = { - fileName: 'src/index.ts', - originalFile: 'const x = 1;', - modifiedFile: 'const x = 2;', - isDirty: false, - timestamp: 1234567890, - }; - - const message: SyncFullContextMessage = { - id: 'msg-1', - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify(message)); - - expect(payloadCallback).toHaveBeenCalledTimes(1); - expect(payloadCallback).toHaveBeenCalledWith(payload); - }); - - it('should handle multiple payloads sequentially', () => { - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - const payload1: FileContextPayload = { - fileName: 'file1.ts', - originalFile: 'content1', - modifiedFile: 'modified1', - isDirty: true, - timestamp: 1000, - }; - - const payload2: FileContextPayload = { - fileName: 'file2.ts', - originalFile: 'content2', - modifiedFile: 'modified2', - isDirty: false, - timestamp: 2000, - }; - - eventHandlers['message'](JSON.stringify({ - id: 'msg-1', - type: 'SYNC_FULL_CONTEXT', - payload: payload1, - timestamp: Date.now(), - })); - - eventHandlers['message'](JSON.stringify({ - id: 'msg-2', - type: 'SYNC_FULL_CONTEXT', - payload: payload2, - timestamp: Date.now(), - })); - - expect(payloadCallback).toHaveBeenCalledTimes(2); - expect(payloadCallback).toHaveBeenNthCalledWith(1, payload1); - expect(payloadCallback).toHaveBeenNthCalledWith(2, payload2); - }); - }); - - describe('error handling', () => { - it('should continue operation after parse error', () => { - const payloadCallback = vi.fn(); - client.onPayload(payloadCallback); - client.connect(); - - // Send malformed message - eventHandlers['message']('invalid json'); - - // Send valid message after error - const payload: FileContextPayload = { - fileName: 'test.ts', - originalFile: 'original', - modifiedFile: 'modified', - isDirty: true, - timestamp: Date.now(), - }; - - eventHandlers['message'](JSON.stringify({ - id: 'msg-1', - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp: Date.now(), - })); - - expect(payloadCallback).toHaveBeenCalledWith(payload); - }); - - it('should handle missing payload callback gracefully', () => { - client.connect(); - - const payload: FileContextPayload = { - fileName: 'test.ts', - originalFile: 'original', - modifiedFile: 'modified', - isDirty: true, - timestamp: Date.now(), - }; - - expect(() => { - eventHandlers['message'](JSON.stringify({ - id: 'msg-1', - type: 'SYNC_FULL_CONTEXT', - payload, - timestamp: Date.now(), - })); - }).not.toThrow(); - }); - }); - - describe('reconnection logic', () => { - it('should configure reconnection parameters', () => { - const customClient = new WebSocketClient({ - url: 'http://localhost:8080', - reconnectionDelay: 2000, - reconnectionDelayMax: 10000, - reconnectionAttempts: 5, - }); - - customClient.connect(); - - expect(io).toHaveBeenCalledWith('http://localhost:8080', expect.objectContaining({ - reconnectionDelay: 2000, - reconnectionDelayMax: 10000, - reconnectionAttempts: 5, - })); - }); - - it('should use default reconnection parameters', () => { - client.connect(); - - expect(io).toHaveBeenCalledWith('http://localhost:8080', expect.objectContaining({ - reconnectionDelay: 1000, - reconnectionDelayMax: 5000, - reconnectionAttempts: Infinity, - })); - }); - }); -}); diff --git a/packages/mobile-client/src/websocket/WebSocketClient.ts b/packages/mobile-client/src/websocket/WebSocketClient.ts deleted file mode 100644 index 8381dd0..0000000 --- a/packages/mobile-client/src/websocket/WebSocketClient.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { io, Socket } from 'socket.io-client'; -import { FileContextPayload, SyncFullContextMessage } from '@codelink/protocol'; - -export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected'; - -export interface WebSocketClientConfig { - url: string; - reconnectionDelay?: number; - reconnectionDelayMax?: number; - reconnectionAttempts?: number; -} - -export class WebSocketClient { - private socket: Socket | null = null; - private config: WebSocketClientConfig; - private onPayloadCallback: ((payload: FileContextPayload) => void) | null = null; - private onStatusChangeCallback: ((status: ConnectionStatus) => void) | null = null; - private currentStatus: ConnectionStatus = 'disconnected'; - - constructor(config: WebSocketClientConfig) { - this.config = { - reconnectionDelay: 1000, - reconnectionDelayMax: 5000, - reconnectionAttempts: Infinity, - ...config, - }; - } - - /** - * Connect to the relay server - */ - connect(): void { - if (this.socket) { - return; - } - - this.updateStatus('connecting'); - - this.socket = io(this.config.url, { - reconnectionDelay: this.config.reconnectionDelay, - reconnectionDelayMax: this.config.reconnectionDelayMax, - reconnectionAttempts: this.config.reconnectionAttempts, - }); - - this.socket.on('connect', () => { - console.log('[WebSocketClient] Connected to relay server'); - this.updateStatus('connected'); - - // Send ping to register as mobile client - this.sendPing(); - }); - - this.socket.on('disconnect', () => { - console.log('[WebSocketClient] Disconnected from relay server'); - this.updateStatus('disconnected'); - }); - - this.socket.on('connect_error', (error) => { - console.error('[WebSocketClient] Connection error:', error); - this.updateStatus('disconnected'); - }); - - this.socket.on('message', (data: string) => { - this.handleMessage(data); - }); - } - - /** - * Disconnect from the relay server - */ - disconnect(): void { - if (this.socket) { - this.socket.close(); - this.socket = null; - this.updateStatus('disconnected'); - } - } - - /** - * Register callback for when FileContextPayload is received - */ - onPayload(callback: (payload: FileContextPayload) => void): void { - this.onPayloadCallback = callback; - } - - /** - * Register callback for connection status changes - */ - onStatusChange(callback: (status: ConnectionStatus) => void): void { - this.onStatusChangeCallback = callback; - } - - /** - * Get current connection status - */ - getStatus(): ConnectionStatus { - return this.currentStatus; - } - - /** - * Check if currently connected - */ - isConnected(): boolean { - return this.currentStatus === 'connected'; - } - - /** - * Send ping to register as mobile client - */ - private sendPing(): void { - if (!this.socket) { - return; - } - - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - - console.log('[WebSocketClient] Sending ping to register as mobile client'); - this.socket.emit('message', JSON.stringify(ping)); - } - - /** - * Handle incoming messages - */ - private handleMessage(data: string): void { - try { - const message = JSON.parse(data); - console.log('[WebSocketClient] Received message:', message); - - if (message.type === 'SYNC_FULL_CONTEXT') { - this.handleSyncFullContext(message as SyncFullContextMessage); - } - } catch (error) { - console.error('[WebSocketClient] Error parsing message:', error); - console.error('[WebSocketClient] Raw data:', data); - // Continue operation despite parse error (Requirement 6.4) - // User-friendly: Don't show error to user, just log it - } - } - - /** - * Handle SYNC_FULL_CONTEXT messages - */ - private handleSyncFullContext(message: SyncFullContextMessage): void { - try { - const payload = message.payload; - - // Validate payload structure - if (!this.isValidPayload(payload)) { - console.error('[WebSocketClient] Invalid payload structure:', payload); - console.error('[WebSocketClient] Expected fields: fileName, originalFile, modifiedFile, isDirty, timestamp'); - return; - } - - console.log('[WebSocketClient] Parsed FileContextPayload:', payload); - - // Invoke callback if registered - if (this.onPayloadCallback) { - this.onPayloadCallback(payload); - } - } catch (error) { - console.error('[WebSocketClient] Error handling SYNC_FULL_CONTEXT:', error); - // Continue operation despite error (Requirement 6.4) - // User-friendly: Don't crash the app, just log the error - } - } - - /** - * Validate FileContextPayload structure - */ - private isValidPayload(payload: unknown): payload is FileContextPayload { - return ( - payload && - typeof payload === 'object' && - typeof payload.fileName === 'string' && - typeof payload.originalFile === 'string' && - typeof payload.modifiedFile === 'string' && - typeof payload.isDirty === 'boolean' && - typeof payload.timestamp === 'number' - ); - } - - /** - * Update connection status and notify callback - */ - private updateStatus(status: ConnectionStatus): void { - this.currentStatus = status; - if (this.onStatusChangeCallback) { - this.onStatusChangeCallback(status); - } - } -} diff --git a/packages/mobile-client/tailwind.config.js b/packages/mobile-client/tailwind.config.js deleted file mode 100644 index 4629554..0000000 --- a/packages/mobile-client/tailwind.config.js +++ /dev/null @@ -1,25 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: [ - "./index.html", - "./src/**/*.{js,ts,jsx,tsx}", - ], - theme: { - extend: { - colors: { - 'vscode-bg': '#1e1e1e', - 'vscode-sidebar': '#252526', - 'vscode-border': '#3e3e42', - 'vscode-text': '#cccccc', - 'vscode-text-muted': '#858585', - 'vscode-added': '#044B53', - 'vscode-removed': '#5A1E1E', - 'vscode-dirty': '#ff9800', - 'github-bg': '#0d1117', - 'github-canvas': '#161b22', - 'github-border': '#30363d', - }, - }, - }, - plugins: [], -} diff --git a/packages/mobile-client/tsconfig.json b/packages/mobile-client/tsconfig.json index 4eacad1..b9ab55a 100644 --- a/packages/mobile-client/tsconfig.json +++ b/packages/mobile-client/tsconfig.json @@ -1,22 +1,24 @@ { - "extends": "../../tsconfig.base.json", "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", + "strict": true, "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "node", "resolveJsonModule": true, - "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "types": ["vitest/globals"] + "jsx": "react-native", + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "allowJs": true, + "isolatedModules": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } }, - "include": ["./src", "./index.html"] + "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"], + "exclude": ["node_modules"] } diff --git a/packages/mobile-client/vite.config.ts b/packages/mobile-client/vite.config.ts deleted file mode 100644 index 556f519..0000000 --- a/packages/mobile-client/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - plugins: [react()], - server: { - port: 3000, - }, -}); diff --git a/packages/mobile-client/vitest.config.ts b/packages/mobile-client/vitest.config.ts deleted file mode 100644 index 296fd32..0000000 --- a/packages/mobile-client/vitest.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'vitest/config'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - plugins: [react()], - test: { - globals: true, - environment: 'jsdom', - setupFiles: ['./src/test-setup.ts'], - }, -}); diff --git a/packages/protocol/package.json b/packages/protocol/package.json index b66d482..e54315a 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -5,9 +5,12 @@ "types": "./dist/index.d.ts", "scripts": { "build": "tsc", - "dev": "tsc --watch" + "dev": "tsc --watch", + "test": "vitest run", + "test:watch": "vitest" }, "devDependencies": { - "typescript": "^5.0.0" + "typescript": "^5.0.0", + "vitest": "^4.1.0" } } diff --git a/packages/protocol/src/index.test.ts b/packages/protocol/src/index.test.ts index b646825..b5ed797 100644 --- a/packages/protocol/src/index.test.ts +++ b/packages/protocol/src/index.test.ts @@ -1,196 +1,150 @@ import { describe, it, expect } from 'vitest'; import { + MessageType, PingMessage, PongMessage, - ProtocolMessage, - MessageType, FileContextPayload, SyncFullContextMessage, + InjectPromptMessage, + InjectPromptResponse, } from './index'; -describe('Protocol Types', () => { +describe('Protocol Package - Smoke Tests', () => { + describe('MessageType Enum', () => { + it('should have all required message types', () => { + expect(MessageType.PING).toBe('PING'); + expect(MessageType.PONG).toBe('PONG'); + expect(MessageType.SYNC_FULL_CONTEXT).toBe('SYNC_FULL_CONTEXT'); + expect(MessageType.INJECT_PROMPT).toBe('INJECT_PROMPT'); + expect(MessageType.INJECT_PROMPT_RESPONSE).toBe('INJECT_PROMPT_RESPONSE'); + }); + }); + describe('PingMessage', () => { - it('should create a valid PingMessage with extension source', () => { + it('should create a valid ping message', () => { const ping: PingMessage = { - id: 'test-id-123', + id: 'test-id', timestamp: Date.now(), type: 'ping', source: 'extension', }; - expect(ping.id).toBe('test-id-123'); + expect(ping.id).toBe('test-id'); expect(ping.type).toBe('ping'); expect(ping.source).toBe('extension'); expect(typeof ping.timestamp).toBe('number'); }); - - it('should create a valid PingMessage with mobile source', () => { - const ping: PingMessage = { - id: 'test-id-456', - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - - expect(ping.id).toBe('test-id-456'); - expect(ping.type).toBe('ping'); - expect(ping.source).toBe('mobile'); - expect(typeof ping.timestamp).toBe('number'); - }); }); describe('PongMessage', () => { - it('should create a valid PongMessage with originalId', () => { + it('should create a valid pong message', () => { const pong: PongMessage = { - id: 'pong-id-789', + id: 'pong-id', timestamp: Date.now(), type: 'pong', - originalId: 'original-ping-id', + originalId: 'ping-id', }; - expect(pong.id).toBe('pong-id-789'); + expect(pong.id).toBe('pong-id'); expect(pong.type).toBe('pong'); - expect(pong.originalId).toBe('original-ping-id'); + expect(pong.originalId).toBe('ping-id'); expect(typeof pong.timestamp).toBe('number'); }); }); - describe('ProtocolMessage union type', () => { - it('should discriminate PingMessage type', () => { - const message: ProtocolMessage = { - id: 'test-id', - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - - if (message.type === 'ping') { - expect(message.source).toBeDefined(); - expect(['extension', 'mobile']).toContain(message.source); - } - }); - - it('should discriminate PongMessage type', () => { - const message: ProtocolMessage = { - id: 'test-id', - timestamp: Date.now(), - type: 'pong', - originalId: 'original-id', - }; - - if (message.type === 'pong') { - expect(message.originalId).toBeDefined(); - expect(message.originalId).toBe('original-id'); - } - }); - }); - - describe('MessageType enum', () => { - it('should contain SYNC_FULL_CONTEXT type', () => { - expect(MessageType.SYNC_FULL_CONTEXT).toBe('SYNC_FULL_CONTEXT'); - }); - - it('should contain PING type', () => { - expect(MessageType.PING).toBe('PING'); - }); - - it('should contain PONG type', () => { - expect(MessageType.PONG).toBe('PONG'); - }); - }); - describe('FileContextPayload', () => { - it('should create a valid FileContextPayload with all required fields', () => { + it('should create a valid file context payload', () => { const payload: FileContextPayload = { - fileName: 'src/index.ts', - originalFile: 'const x = 1;', - modifiedFile: 'const x = 2;', + fileName: 'src/test.ts', + originalFile: 'original content', + modifiedFile: 'modified content', isDirty: true, timestamp: Date.now(), }; - expect(payload.fileName).toBe('src/index.ts'); - expect(payload.originalFile).toBe('const x = 1;'); - expect(payload.modifiedFile).toBe('const x = 2;'); + expect(payload.fileName).toBe('src/test.ts'); + expect(payload.originalFile).toBe('original content'); + expect(payload.modifiedFile).toBe('modified content'); expect(payload.isDirty).toBe(true); expect(typeof payload.timestamp).toBe('number'); }); + }); - it('should handle empty originalFile for untracked files', () => { - const payload: FileContextPayload = { - fileName: 'src/newfile.ts', - originalFile: '', - modifiedFile: 'const newCode = true;', - isDirty: false, + describe('SyncFullContextMessage', () => { + it('should create a valid sync full context message', () => { + const message: SyncFullContextMessage = { + id: 'sync-id', timestamp: Date.now(), + type: 'SYNC_FULL_CONTEXT', + payload: { + fileName: 'src/test.ts', + originalFile: 'original', + modifiedFile: 'modified', + isDirty: false, + timestamp: Date.now(), + }, }; - expect(payload.originalFile).toBe(''); - expect(payload.modifiedFile).toBe('const newCode = true;'); + expect(message.id).toBe('sync-id'); + expect(message.type).toBe('SYNC_FULL_CONTEXT'); + expect(message.payload.fileName).toBe('src/test.ts'); + expect(typeof message.timestamp).toBe('number'); }); + }); - it('should handle identical files with isDirty false', () => { - const content = 'const unchanged = true;'; - const payload: FileContextPayload = { - fileName: 'src/unchanged.ts', - originalFile: content, - modifiedFile: content, - isDirty: false, + describe('InjectPromptMessage', () => { + it('should create a valid inject prompt message', () => { + const message: InjectPromptMessage = { + id: 'prompt-id', timestamp: Date.now(), + type: 'INJECT_PROMPT', + payload: { + prompt: 'Test prompt', + }, }; - expect(payload.originalFile).toBe(payload.modifiedFile); - expect(payload.isDirty).toBe(false); + expect(message.id).toBe('prompt-id'); + expect(message.type).toBe('INJECT_PROMPT'); + expect(message.payload.prompt).toBe('Test prompt'); + expect(typeof message.timestamp).toBe('number'); }); }); - describe('SyncFullContextMessage', () => { - it('should create a valid SyncFullContextMessage structure', () => { - const message: SyncFullContextMessage = { - id: 'sync-msg-123', + describe('InjectPromptResponse', () => { + it('should create a valid inject prompt response (success)', () => { + const response: InjectPromptResponse = { + id: 'response-id', timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', + type: 'INJECT_PROMPT_RESPONSE', + originalId: 'prompt-id', payload: { - fileName: 'src/app.ts', - originalFile: 'old content', - modifiedFile: 'new content', - isDirty: true, - timestamp: Date.now(), + success: true, + editorUsed: 'continue', }, }; - expect(message.id).toBe('sync-msg-123'); - expect(message.type).toBe('SYNC_FULL_CONTEXT'); - expect(message.payload.fileName).toBe('src/app.ts'); - expect(message.payload.originalFile).toBe('old content'); - expect(message.payload.modifiedFile).toBe('new content'); - expect(message.payload.isDirty).toBe(true); - expect(typeof message.timestamp).toBe('number'); - expect(typeof message.payload.timestamp).toBe('number'); + expect(response.id).toBe('response-id'); + expect(response.type).toBe('INJECT_PROMPT_RESPONSE'); + expect(response.originalId).toBe('prompt-id'); + expect(response.payload.success).toBe(true); + expect(response.payload.editorUsed).toBe('continue'); }); - }); - describe('ProtocolMessage union type with SyncFullContextMessage', () => { - it('should discriminate SyncFullContextMessage type', () => { - const message: ProtocolMessage = { - id: 'test-sync-id', + it('should create a valid inject prompt response (error)', () => { + const response: InjectPromptResponse = { + id: 'response-id', timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', + type: 'INJECT_PROMPT_RESPONSE', + originalId: 'prompt-id', payload: { - fileName: 'test.ts', - originalFile: 'original', - modifiedFile: 'modified', - isDirty: false, - timestamp: Date.now(), + success: false, + error: 'No editor found', }, }; - if (message.type === 'SYNC_FULL_CONTEXT') { - expect(message.payload).toBeDefined(); - expect(message.payload.fileName).toBe('test.ts'); - expect(message.payload.originalFile).toBe('original'); - expect(message.payload.modifiedFile).toBe('modified'); - } + expect(response.id).toBe('response-id'); + expect(response.payload.success).toBe(false); + expect(response.payload.error).toBe('No editor found'); }); }); }); diff --git a/packages/protocol/src/index.ts b/packages/protocol/src/index.ts index f7f8731..4380b60 100644 --- a/packages/protocol/src/index.ts +++ b/packages/protocol/src/index.ts @@ -28,11 +28,11 @@ export interface PongMessage extends Message { // File context payload for diff viewing export interface FileContextPayload { - fileName: string; // Workspace-relative file path (e.g., "src/index.ts") - originalFile: string; // Content from Git HEAD (empty string if untracked) - modifiedFile: string; // Current file content from disk - isDirty: boolean; // True if file has unsaved changes in editor - timestamp: number; // Unix timestamp in milliseconds when diff was generated + fileName: string; // Workspace-relative file path (e.g., "src/index.ts") + originalFile: string; // Content from Git HEAD (empty string if untracked) + modifiedFile: string; // Current file content from disk + isDirty: boolean; // True if file has unsaved changes in editor + timestamp: number; // Unix timestamp in milliseconds when diff was generated } // Sync full context message for sending diffs to mobile @@ -41,21 +41,165 @@ export interface SyncFullContextMessage extends Message { payload: FileContextPayload; } -// Inject prompt message from mobile to extension +// Inject prompt message from mobile to relay export interface InjectPromptMessage extends Message { type: 'INJECT_PROMPT'; - prompt: string; + payload: { + prompt: string; + }; } -// Inject prompt response from extension to mobile -export interface InjectPromptResponseMessage extends Message { +// Inject prompt response from relay to mobile +export interface InjectPromptResponse extends Message { type: 'INJECT_PROMPT_RESPONSE'; - success: boolean; - error?: string; - editorUsed?: string; - commandUsed?: string; - originalRequestId?: string; // ID of the original INJECT_PROMPT message + payload: { + success: boolean; + error?: string; + editorUsed?: string; + }; + originalId: string; } // Union type for all messages -export type ProtocolMessage = PingMessage | PongMessage | SyncFullContextMessage | InjectPromptMessage | InjectPromptResponseMessage; +export type ProtocolMessage = + | PingMessage + | PongMessage + | SyncFullContextMessage + | InjectPromptMessage + | InjectPromptResponse; + +// Type guard functions for runtime type checking + +/** + * Type guard to check if a value is a valid Message + */ +export function isMessage(value: unknown): value is Message { + return ( + typeof value === 'object' && + value !== null && + 'id' in value && + typeof (value as Message).id === 'string' && + 'timestamp' in value && + typeof (value as Message).timestamp === 'number' && + 'type' in value && + typeof (value as Message).type === 'string' + ); +} + +/** + * Type guard to check if a value is a PingMessage + */ +export function isPingMessage(value: unknown): value is PingMessage { + return ( + isMessage(value) && + (value as PingMessage).type === 'ping' && + 'source' in value && + ((value as PingMessage).source === 'extension' || (value as PingMessage).source === 'mobile') + ); +} + +/** + * Type guard to check if a value is a PongMessage + */ +export function isPongMessage(value: unknown): value is PongMessage { + return ( + isMessage(value) && + (value as PongMessage).type === 'pong' && + 'originalId' in value && + typeof (value as PongMessage).originalId === 'string' + ); +} + +/** + * Type guard to check if a value is a valid FileContextPayload + */ +export function isFileContextPayload(value: unknown): value is FileContextPayload { + return ( + typeof value === 'object' && + value !== null && + 'fileName' in value && + typeof (value as FileContextPayload).fileName === 'string' && + 'originalFile' in value && + typeof (value as FileContextPayload).originalFile === 'string' && + 'modifiedFile' in value && + typeof (value as FileContextPayload).modifiedFile === 'string' && + 'isDirty' in value && + typeof (value as FileContextPayload).isDirty === 'boolean' && + 'timestamp' in value && + typeof (value as FileContextPayload).timestamp === 'number' + ); +} + +/** + * Type guard to check if a value is a SyncFullContextMessage + */ +export function isSyncFullContextMessage(value: unknown): value is SyncFullContextMessage { + return ( + isMessage(value) && + (value as SyncFullContextMessage).type === 'SYNC_FULL_CONTEXT' && + 'payload' in value && + isFileContextPayload((value as SyncFullContextMessage).payload) + ); +} + +/** + * Type guard to check if a value is an InjectPromptMessage + */ +export function isInjectPromptMessage(value: unknown): value is InjectPromptMessage { + return ( + isMessage(value) && + (value as InjectPromptMessage).type === 'INJECT_PROMPT' && + 'payload' in value && + typeof (value as InjectPromptMessage).payload === 'object' && + (value as InjectPromptMessage).payload !== null && + 'prompt' in (value as InjectPromptMessage).payload && + typeof (value as InjectPromptMessage).payload.prompt === 'string' + ); +} + +/** + * Type guard to check if a value is an InjectPromptResponse + */ +export function isInjectPromptResponse(value: unknown): value is InjectPromptResponse { + if (!isMessage(value) || (value as InjectPromptResponse).type !== 'INJECT_PROMPT_RESPONSE') { + return false; + } + + const msg = value as InjectPromptResponse; + + if (!('originalId' in msg) || typeof msg.originalId !== 'string') { + return false; + } + + if (!('payload' in msg) || typeof msg.payload !== 'object' || msg.payload === null) { + return false; + } + + if (!('success' in msg.payload) || typeof msg.payload.success !== 'boolean') { + return false; + } + + // Optional fields validation + if ('error' in msg.payload && typeof msg.payload.error !== 'string') { + return false; + } + + if ('editorUsed' in msg.payload && typeof msg.payload.editorUsed !== 'string') { + return false; + } + + return true; +} + +/** + * Type guard to check if a value is any valid ProtocolMessage + */ +export function isProtocolMessage(value: unknown): value is ProtocolMessage { + return ( + isPingMessage(value) || + isPongMessage(value) || + isSyncFullContextMessage(value) || + isInjectPromptMessage(value) || + isInjectPromptResponse(value) + ); +} diff --git a/packages/protocol/tsconfig.tsbuildinfo b/packages/protocol/tsconfig.tsbuildinfo index 620df2e..d1eadc9 100644 --- a/packages/protocol/tsconfig.tsbuildinfo +++ b/packages/protocol/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@vitest/utils/dist/types.d.ts","../../node_modules/@vitest/utils/dist/helpers.d.ts","../../node_modules/@sinclair/typebox/typebox.d.ts","../../node_modules/@jest/schemas/build/index.d.ts","../../node_modules/pretty-format/build/index.d.ts","../../node_modules/@vitest/utils/dist/index.d.ts","../../node_modules/@vitest/runner/dist/tasks-K5XERDtv.d.ts","../../node_modules/@vitest/utils/dist/types-9l4niLY8.d.ts","../../node_modules/@vitest/utils/dist/diff.d.ts","../../node_modules/@vitest/utils/diff.d.ts","../../node_modules/@vitest/runner/dist/types.d.ts","../../node_modules/@vitest/utils/dist/error.d.ts","../../node_modules/@vitest/utils/error.d.ts","../../node_modules/@vitest/runner/dist/index.d.ts","../../node_modules/@vitest/runner/dist/utils.d.ts","../../node_modules/@vitest/runner/utils.d.ts","../../node_modules/@types/node/compatibility/disposable.d.ts","../../node_modules/@types/node/compatibility/indexable.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/compatibility/index.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../node_modules/@types/node/web-globals/domexception.d.ts","../../node_modules/@types/node/web-globals/events.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/file.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/filereader.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/web-globals/fetch.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.generated.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/@types/estree/index.d.ts","../../node_modules/rollup/dist/rollup.d.ts","../../node_modules/vite/types/hmrPayload.d.ts","../../node_modules/vite/types/customEvent.d.ts","../../node_modules/vite/types/hot.d.ts","../../node_modules/vite/dist/node/types.d-aGj9QkWt.d.ts","../../node_modules/esbuild/lib/main.d.ts","../../node_modules/source-map-js/source-map.d.ts","../../node_modules/postcss/lib/previous-map.d.ts","../../node_modules/postcss/lib/input.d.ts","../../node_modules/postcss/lib/css-syntax-error.d.ts","../../node_modules/postcss/lib/declaration.d.ts","../../node_modules/postcss/lib/root.d.ts","../../node_modules/postcss/lib/warning.d.ts","../../node_modules/postcss/lib/lazy-result.d.ts","../../node_modules/postcss/lib/no-work-result.d.ts","../../node_modules/postcss/lib/processor.d.ts","../../node_modules/postcss/lib/result.d.ts","../../node_modules/postcss/lib/document.d.ts","../../node_modules/postcss/lib/rule.d.ts","../../node_modules/postcss/lib/node.d.ts","../../node_modules/postcss/lib/comment.d.ts","../../node_modules/postcss/lib/container.d.ts","../../node_modules/postcss/lib/at-rule.d.ts","../../node_modules/postcss/lib/list.d.ts","../../node_modules/postcss/lib/postcss.d.ts","../../node_modules/vite/dist/node/runtime.d.ts","../../node_modules/vite/types/importGlob.d.ts","../../node_modules/vite/types/metadata.d.ts","../../node_modules/vite/dist/node/index.d.ts","../../node_modules/vite-node/dist/trace-mapping.d-xyIfZtPm.d.ts","../../node_modules/vite-node/dist/index-O2IrwHKf.d.ts","../../node_modules/vite-node/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment-cMiGIVXz.d.ts","../../node_modules/@vitest/snapshot/dist/index-S94ASl6q.d.ts","../../node_modules/@vitest/snapshot/dist/index.d.ts","../../node_modules/@vitest/expect/dist/chai.d.cts","../../node_modules/@vitest/expect/dist/index.d.ts","../../node_modules/@vitest/expect/index.d.ts","../../node_modules/tinybench/dist/index.d.cts","../../node_modules/vite-node/dist/client.d.ts","../../node_modules/@vitest/snapshot/dist/manager.d.ts","../../node_modules/@vitest/snapshot/manager.d.ts","../../node_modules/vite-node/dist/server.d.ts","../../node_modules/vitest/dist/reporters-w_64AS5f.d.ts","../../node_modules/vitest/dist/suite-dWqIFb_-.d.ts","../../node_modules/@vitest/spy/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment.d.ts","../../node_modules/@vitest/snapshot/environment.d.ts","../../node_modules/vitest/dist/index.d.ts","./src/index.ts","./src/index.test.ts","../../node_modules/vitest/globals.d.ts"],"fileIdsList":[[48,67,113],[67,113],[67,110,113],[67,112,113],[113],[67,113,118,146],[67,113,114,119,124,132,143,154],[67,113,114,115,124,132],[62,63,64,67,113],[67,113,116,155],[67,113,117,118,125,133],[67,113,118,143,151],[67,113,119,121,124,132],[67,112,113,120],[67,113,121,122],[67,113,123,124],[67,112,113,124],[67,113,124,125,126,143,154],[67,113,124,125,126,139,143,146],[67,113,121,124,127,132,143,154],[67,113,124,125,127,128,132,143,151,154],[67,113,127,129,143,151,154],[65,66,67,68,69,70,71,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160],[67,113,124,130],[67,113,131,154,159],[67,113,121,124,132,143],[67,113,133],[67,113,134],[67,112,113,135],[67,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160],[67,113,137],[67,113,138],[67,113,124,139,140],[67,113,139,141,155,157],[67,113,124,143,144,146],[67,113,145,146],[67,113,143,144],[67,113,146],[67,113,147],[67,110,113,143,148],[67,113,124,149,150],[67,113,149,150],[67,113,118,132,143,151],[67,113,152],[67,113,132,153],[67,113,127,138,154],[67,113,118,155],[67,113,143,156],[67,113,131,157],[67,113,158],[67,108,113],[67,108,113,124,126,135,143,146,154,157,159],[67,113,143,160],[51,55,67,113],[67,113,199],[51,52,55,56,58,67,113],[51,67,113],[51,52,55,67,113],[51,52,67,113],[60,67,113],[67,113,195],[50,67,113,195],[50,67,113,195,196],[67,113,209],[67,113,203],[54,67,113],[50,53,67,113],[46,67,113],[46,47,50,67,113],[50,67,113],[57,67,113],[67,113,184],[67,113,182,184],[67,113,173,181,182,183,185,187],[67,113,171],[67,113,174,179,184,187],[67,113,170,187],[67,113,174,175,178,179,180,187],[67,113,174,175,176,178,179,187],[67,113,171,172,173,174,175,179,180,181,183,184,185,187],[67,113,169,171,172,173,174,175,176,178,179,180,181,182,183,184,185,186],[67,113,169,187],[67,113,174,176,177,179,180,187],[67,113,178,187],[67,113,179,180,184,187],[67,113,172,182],[49,67,113],[67,113,162,163],[67,80,84,113,154],[67,80,113,143,154],[67,75,113],[67,77,80,113,151,154],[67,113,132,151],[67,113,161],[67,75,113,161],[67,77,80,113,132,154],[67,72,73,76,79,113,124,143,154],[67,80,87,113],[67,72,78,113],[67,80,101,102,113],[67,76,80,113,146,154,161],[67,101,113,161],[67,74,75,113,161],[67,80,113],[67,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,102,103,104,105,106,107,113],[67,80,95,113],[67,80,87,88,113],[67,78,80,88,89,113],[67,79,113],[67,72,75,80,113],[67,80,84,88,89,113],[67,84,113],[67,78,80,83,113,154],[67,72,77,80,87,113],[67,113,143],[67,75,80,101,113,159,161],[67,113,192,193],[67,113,192],[67,113,191,192,193,206],[67,113,124,125,127,128,129,132,143,151,154,160,161,163,164,165,166,167,168,187,188,189,190],[67,113,164,165,166,167],[67,113,164,165,166],[67,113,164],[67,113,165],[67,113,163],[51,55,59,61,67,113,125,143,159,191,194,197,198,200,201,202,204,205,206,207,208,210],[51,59,61,67,113,125,143,159,191,194,197,198,200,201,202,204,205,206],[59,61,67,113,201,206],[67,113,211],[67,113,211,212]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"3deed5e2a5f1e7590d44e65a5b61900158a3c38bac9048462d38b1bc8098bb2e","impliedFormat":99},{"version":"d435a43f89ed8794744c59d72ce71e43c1953338303f6be9ef99086faa8591d7","impliedFormat":99},{"version":"c085e9aa62d1ae1375794c1fb927a445fa105fed891a7e24edbb1c3300f7384a","impliedFormat":1},{"version":"f315e1e65a1f80992f0509e84e4ae2df15ecd9ef73df975f7c98813b71e4c8da","impliedFormat":1},{"version":"5b9586e9b0b6322e5bfbd2c29bd3b8e21ab9d871f82346cb71020e3d84bae73e","impliedFormat":1},{"version":"a4f64e674903a21e1594a24c3fc8583f3a587336d17d41ade46aa177a8ab889b","impliedFormat":99},{"version":"b6f69984ffcd00a7cbcef9c931b815e8872c792ed85d9213cb2e2c14c50ca63a","impliedFormat":99},{"version":"2bbc5abe5030aa07a97aabd6d3932ed2e8b7a241cf3923f9f9bf91a0addbe41f","impliedFormat":99},{"version":"1e5e5592594e16bcf9544c065656293374120eb8e78780fb6c582cc710f6db11","impliedFormat":99},{"version":"05c7aef6a4e496b93c2e682cced8903c0dfe6340d04f3fe616176e2782193435","impliedFormat":99},{"version":"4abf1e884eecb0bf742510d69d064e33d53ac507991d6c573958356f920c3de4","impliedFormat":99},{"version":"44f1d2dd522c849ca98c4f95b8b2bc84b64408d654f75eb17ec78b8ceb84da11","impliedFormat":99},{"version":"500a67e158e4025f27570ab6a99831680852bb45a44d4c3647ab7567feb1fb4c","impliedFormat":99},{"version":"89edc5e1739692904fdf69edcff9e1023d2213e90372ec425b2f17e3aecbaa4a","impliedFormat":99},{"version":"e7d5bcffc98eded65d620bc0b6707c307b79c21d97a5fb8601e8bdf2296026b6","impliedFormat":99},{"version":"e666e31d323fef5642f87db0da48a83e58f0aaf9e3823e87eabd8ec7e0441a36","impliedFormat":99},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"2fd4c143eff88dabb57701e6a40e02a4dbc36d5eb1362e7964d32028056a782b","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e456fd5b101271183d99a9087875a282323e3a3ff0d7bcf1881537eaa8b8e63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"0225ecb9ed86bdb7a2c7fd01f1556906902929377b44483dc4b83e03b3ef227d","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"ddc734b4fae82a01d247e9e342d020976640b5e93b4e9b3a1e30e5518883a060","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"05db535df8bdc30d9116fe754a3473d1b6479afbc14ae8eb18b605c62677d518","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"4e741b9c88e80c9e4cedf07b5a698e8e3a3bd73cf649f664d6dd3f868c05c2f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","impliedFormat":1},{"version":"6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","impliedFormat":1},{"version":"cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","impliedFormat":1},{"version":"8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87","impliedFormat":99},{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true,"impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","impliedFormat":1},{"version":"333caa2bfff7f06017f114de738050dd99a765c7eb16571c6d25a38c0d5365dc","impliedFormat":1},{"version":"e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","impliedFormat":1},{"version":"459920181700cec8cbdf2a5faca127f3f17fd8dd9d9e577ed3f5f3af5d12a2e4","impliedFormat":1},{"version":"4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","impliedFormat":1},{"version":"7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","impliedFormat":1},{"version":"70790a7f0040993ca66ab8a07a059a0f8256e7bb57d968ae945f696cbff4ac7a","impliedFormat":1},{"version":"d1b9a81e99a0050ca7f2d98d7eedc6cda768f0eb9fa90b602e7107433e64c04c","impliedFormat":1},{"version":"a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","impliedFormat":1},{"version":"b215c4f0096f108020f666ffcc1f072c81e9f2f95464e894a5d5f34c5ea2a8b1","impliedFormat":1},{"version":"644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","impliedFormat":1},{"version":"dfe54dab1fa4961a6bcfba68c4ca955f8b5bbeb5f2ab3c915aa7adaa2eabc03a","impliedFormat":1},{"version":"1251d53755b03cde02466064260bb88fd83c30006a46395b7d9167340bc59b73","impliedFormat":1},{"version":"47865c5e695a382a916b1eedda1b6523145426e48a2eae4647e96b3b5e52024f","impliedFormat":1},{"version":"4cdf27e29feae6c7826cdd5c91751cc35559125e8304f9e7aed8faef97dcf572","impliedFormat":1},{"version":"331b8f71bfae1df25d564f5ea9ee65a0d847c4a94baa45925b6f38c55c7039bf","impliedFormat":1},{"version":"2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","impliedFormat":1},{"version":"0146fd6262c3fd3da51cb0254bb6b9a4e42931eb2f56329edd4c199cb9aaf804","impliedFormat":1},{"version":"82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","impliedFormat":99},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","impliedFormat":1},{"version":"257b83faa134d971c738a6b9e4c47e59bb7b23274719d92197580dd662bfafc3","impliedFormat":99},{"version":"4a27c79c57a6692abb196711f82b8b07a27908c94652148d5469887836390116","impliedFormat":99},{"version":"f42400484f181c2c2d7557c0ed3b8baaace644a9e943511f3d35ac6be6eb5257","impliedFormat":99},{"version":"54b381d36b35df872159a8d3b52e8d852659ee805695a867a388c8ccbf57521b","impliedFormat":99},{"version":"c67b4c864ec9dcde25f7ad51b90ae9fe1f6af214dbd063d15db81194fe652223","impliedFormat":99},{"version":"7a4aa00aaf2160278aeae3cf0d2fc6820cf22b86374efa7a00780fbb965923ff","impliedFormat":99},{"version":"66e3ee0a655ff3698be0aef05f7b76ac34c349873e073cde46d43db795b79f04","impliedFormat":99},{"version":"48c411efce1848d1ed55de41d7deb93cbf7c04080912fd87aa517ed25ef42639","affectsGlobalScope":true,"impliedFormat":1},{"version":"28e065b6fb60a04a538b5fbf8c003d7dac3ae9a49eddc357c2a14f2ffe9b3185","affectsGlobalScope":true,"impliedFormat":99},{"version":"fe2d63fcfdde197391b6b70daf7be8c02a60afa90754a5f4a04bdc367f62793d","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":1},{"version":"0d87708dafcde5468a130dfe64fac05ecad8328c298a4f0f2bd86603e5fd002e","impliedFormat":99},{"version":"a3f2554ba6726d0da0ffdc15b675b8b3de4aea543deebbbead845680b740a7fd","impliedFormat":99},{"version":"b7e28e06011460436d5c2ec2996846ac0c451e135357fc5a7269e5665a32fbd7","impliedFormat":99},{"version":"93dda0982b139b27b85dd2924d23e07ee8b4ca36a10be7bdf361163e4ffcc033","impliedFormat":99},{"version":"d7b652822e2a387fd2bcf0b78bcf2b7a9a9e73c4a71c12c5d0bbbb367aea6a87","affectsGlobalScope":true,"impliedFormat":99},{"version":"cb80558784fc93165b64809b3ba66266d10585d838709ebf5e4576f63f9f2929","impliedFormat":99},{"version":"dfa6bb848807bc5e01e84214d4ec13ee8ffe5e1142546dcbb32065783a5db468","impliedFormat":99},{"version":"2f1ffc29f9ba7b005c0c48e6389536a245837264c99041669e0b768cfab6711d","impliedFormat":99},{"version":"f2d1a59a658165341b0e2b7879aa2e19ea6a709146b2d3f70ee8a07159d3d08e","impliedFormat":99},{"version":"b4270f889835e50044bf80e479fef2482edd69daf4b168f9e3ee34cf817ae41a","impliedFormat":99},{"version":"5d9ea66032e1cf911b48b7493e4a70f5b116acf229c457f9ce5c72c37b62207e","signature":"5903e5db3aa79385274da245d1970fe1b124eb2f686c13335fffedbc843af701"},{"version":"444386adbbdd151e2416b75487872991803c25566dec0f9ab99de84ee2cc7433","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"381d27c35f5a5bf6c09dd238ec26fef30a03d12ea84589c621ebc208d7dc8378","affectsGlobalScope":true,"impliedFormat":99}],"root":[212,213],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":1,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":7},"referencedMap":[[49,1],[48,2],[162,2],[110,3],[111,3],[112,4],[67,5],[113,6],[114,7],[115,8],[62,2],[65,9],[63,2],[64,2],[116,10],[117,11],[118,12],[119,13],[120,14],[121,15],[122,15],[123,16],[124,17],[125,18],[126,19],[68,2],[66,2],[127,20],[128,21],[129,22],[161,23],[130,24],[131,25],[132,26],[133,27],[134,28],[135,29],[136,30],[137,31],[138,32],[139,33],[140,33],[141,34],[142,2],[143,35],[145,36],[144,37],[146,38],[147,39],[148,40],[149,41],[150,42],[151,43],[152,44],[153,45],[154,46],[155,47],[156,48],[157,49],[158,50],[69,2],[70,2],[71,2],[109,51],[159,52],[160,53],[198,2],[199,54],[200,55],[59,56],[52,57],[56,58],[60,59],[61,60],[195,2],[209,61],[196,62],[197,63],[203,63],[210,64],[204,65],[208,2],[55,66],[54,67],[57,67],[47,68],[51,69],[53,70],[46,2],[58,71],[168,2],[185,72],[183,73],[184,74],[172,75],[173,73],[180,76],[171,77],[176,78],[186,2],[177,79],[182,80],[187,81],[170,82],[178,83],[179,84],[174,85],[181,72],[175,86],[50,87],[163,88],[169,2],[201,2],[44,2],[45,2],[9,2],[8,2],[2,2],[10,2],[11,2],[12,2],[13,2],[14,2],[15,2],[16,2],[17,2],[3,2],[18,2],[19,2],[4,2],[20,2],[24,2],[21,2],[22,2],[23,2],[25,2],[26,2],[27,2],[5,2],[28,2],[29,2],[30,2],[31,2],[6,2],[35,2],[32,2],[33,2],[34,2],[36,2],[7,2],[37,2],[42,2],[43,2],[38,2],[39,2],[40,2],[41,2],[1,2],[87,89],[97,90],[86,89],[107,91],[78,92],[77,93],[106,94],[100,95],[105,96],[80,97],[94,98],[79,99],[103,100],[75,101],[74,94],[104,102],[76,103],[81,104],[82,2],[85,104],[72,2],[108,105],[98,106],[89,107],[90,108],[92,109],[88,110],[91,111],[101,94],[83,112],[84,113],[93,114],[73,115],[96,106],[95,104],[99,2],[102,116],[202,117],[193,118],[194,117],[205,119],[192,2],[191,120],[188,121],[167,122],[165,123],[164,2],[166,124],[189,2],[190,125],[211,126],[206,127],[207,128],[214,129],[213,130],[212,2]],"latestChangedDtsFile":"./dist/index.d.ts","version":"5.9.3"} \ No newline at end of file +{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@vitest/utils/node_modules/@vitest/pretty-format/dist/index.d.ts","../../node_modules/@vitest/utils/dist/display.d.ts","../../node_modules/@vitest/utils/dist/types.d.ts","../../node_modules/@vitest/utils/dist/helpers.d.ts","../../node_modules/@vitest/utils/dist/timers.d.ts","../../node_modules/@vitest/utils/dist/index.d.ts","../../node_modules/@vitest/utils/dist/types.d-BCElaP-c.d.ts","../../node_modules/@vitest/utils/dist/diff.d.ts","../../node_modules/@vitest/utils/diff.d.ts","../../node_modules/@vitest/runner/dist/tasks.d-D2GKpdwQ.d.ts","../../node_modules/@vitest/runner/dist/index.d.ts","../../node_modules/vitest/dist/chunks/traces.d.402V_yFI.d.ts","../../node_modules/vitest/node_modules/@vitest/pretty-format/dist/index.d.ts","../../node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment.d-DOJxxZV9.d.ts","../../node_modules/@vitest/snapshot/dist/rawSnapshot.d-U2kJUxDr.d.ts","../../node_modules/@vitest/snapshot/dist/index.d.ts","../../node_modules/vitest/dist/chunks/config.d.EJLVE3es.d.ts","../../node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts","../../node_modules/vitest/dist/chunks/rpc.d.BFMWpdph.d.ts","../../node_modules/vitest/dist/chunks/worker.d.B84sVRy0.d.ts","../../node_modules/vitest/dist/chunks/browser.d.X3SXoOCV.d.ts","../../node_modules/@vitest/spy/dist/index.d.ts","../../node_modules/tinyrainbow/dist/index.d.ts","../../node_modules/@standard-schema/spec/dist/index.d.ts","../../node_modules/@types/deep-eql/index.d.ts","../../node_modules/@types/chai/node_modules/assertion-error/index.d.ts","../../node_modules/@types/chai/index.d.ts","../../node_modules/@vitest/expect/dist/index.d.ts","../../node_modules/@vitest/runner/dist/utils.d.ts","../../node_modules/@vitest/runner/utils.d.ts","../../node_modules/tinybench/dist/index.d.cts","../../node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts","../../node_modules/vitest/dist/chunks/global.d.x-ILCfAE.d.ts","../../node_modules/vitest/node_modules/@vitest/mocker/dist/types.d-BjI5eAwu.d.ts","../../node_modules/vitest/node_modules/@vitest/mocker/dist/index.d-B41z0AuW.d.ts","../../node_modules/vitest/node_modules/@vitest/mocker/dist/index.d.ts","../../node_modules/vitest/dist/chunks/suite.d.udJtyAgw.d.ts","../../node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts","../../node_modules/vitest/dist/runners.d.ts","../../node_modules/expect-type/dist/utils.d.ts","../../node_modules/expect-type/dist/overloads.d.ts","../../node_modules/expect-type/dist/branding.d.ts","../../node_modules/expect-type/dist/messages.d.ts","../../node_modules/expect-type/dist/index.d.ts","../../node_modules/vitest/dist/index.d.ts","./src/index.ts","./src/index.test.ts","../../node_modules/vitest/globals.d.ts"],"fileIdsList":[[71,72],[54,56,68,69,70,73,79],[51,54,55],[51,54],[75],[51],[46,51,60,61],[46,60],[53],[46,52],[46],[48],[46,47,48,49,50],[86,87],[86,87,88,89],[86,88],[86],[56,76,77,79],[56,57,66,79],[46,54,56,62,79],[46,56,62,65,74,78,79],[56,57,62,79],[56,76,77,78,79],[56,63,64,65,79],[46,51,54,56,57,62,63,64,65,66,67,68,74,76,77,78,79,82,83,84,85,90],[46,54,56,57,62,63,76,77,78,79,83],[91],[80],[80,81],[91,92]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"cadeb2c96f1c964d7e49c0f17d6805e1b4dee62f0862c49bb178dae6ab277e8e","impliedFormat":99},{"version":"0528f6d21f7a02d4092895090d2dd86104bd5a3e79eced96d5a1a7dd90943d17","impliedFormat":99},{"version":"b5ce343886d23392be9c8280e9f24a87f1d7d3667f6672c2fe4aa61fa4ece7d4","impliedFormat":99},{"version":"eb64a68249f1ee45e496a23cd0be8fe8c84aecb4c038b86d4abcc765c5ba115e","impliedFormat":99},{"version":"b0857bb28fd5236ace84280f79a25093f919fd0eff13e47cc26ea03de60a7294","impliedFormat":99},{"version":"5e43e0824f10cd8c48e7a8c5c673638488925a12c31f0f9e0957965c290eb14c","impliedFormat":99},{"version":"ef13c73d6157a32933c612d476c1524dd674cf5b9a88571d7d6a0d147544d529","impliedFormat":99},{"version":"3b0a56d056d81a011e484b9c05d5e430711aaecd561a788bad1d0498aad782c7","impliedFormat":99},{"version":"05c7aef6a4e496b93c2e682cced8903c0dfe6340d04f3fe616176e2782193435","impliedFormat":99},{"version":"3354286ef917d22c72e0c830324062f950134d8882e9ea57ad6ade3d8ad943cf","impliedFormat":99},{"version":"3dedc468e9b0ed804c0226482e344bd769417f834988af838d814504af81cba6","impliedFormat":99},{"version":"ac3d263474022e9a14c43f588f485d549641d839b159ecc971978b90f34bdf6b","impliedFormat":99},{"version":"cadeb2c96f1c964d7e49c0f17d6805e1b4dee62f0862c49bb178dae6ab277e8e","impliedFormat":99},{"version":"cadeb2c96f1c964d7e49c0f17d6805e1b4dee62f0862c49bb178dae6ab277e8e","impliedFormat":99},{"version":"42a12f2faa483c9b48195ed794d22698162274e755f6e07219c2351c4f08d732","impliedFormat":99},{"version":"727858fb893b87791876dee5e3cd4c187a721d2de516fd19d3d00dc6e8a894b3","impliedFormat":99},{"version":"5bfaa2ee33e63a1b17b08dbefd7a3c42d1e0f914e52aca5bef679b420bd7a07c","impliedFormat":99},{"version":"7d5c6cc5d537c47c7723a1fe76411b99373eb55c487045dfd076c1956e87389a","impliedFormat":99},{"version":"bcbd3becd08b4515225880abea0dbfbbf0d1181ce3af8f18f72f61edbe4febfb","impliedFormat":99},{"version":"a86701e56b10a6d1ef9b2ecaeedbab94ed7b957a646cd71fd09d02b323c6d3d7","impliedFormat":99},{"version":"b3f0791a73b6521da68107c5ba1bfed4bc21ff7099b892700fd65670e88ef6ee","impliedFormat":99},{"version":"d0411dddbef50f9ad568ee9d24b108153bcb8f0db1094de6dfbadf02feb3aa70","impliedFormat":99},{"version":"25249ca5fe64ca60d7bfb7fbbf0cb084324853b03a265dbbbc45fb4949de7567","impliedFormat":99},{"version":"b481de4ab5379bd481ca12fc0b255cdc47341629a22c240a89cdb4e209522be2","impliedFormat":99},{"version":"bdd14f07b4eca0b4b5203b85b8dbc4d084c749fa590bee5ea613e1641dcd3b29","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"31d5fb0aeb0368909fbe8cd9b893c16350aa94d48a2f909fdd393982ceb4814d","affectsGlobalScope":true,"impliedFormat":99},{"version":"90fe5875e2c7519711442683a9489416819c6cec8d395e48ff568e94254533e7","impliedFormat":99},{"version":"e666e31d323fef5642f87db0da48a83e58f0aaf9e3823e87eabd8ec7e0441a36","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":1},{"version":"6987dfb4b0c4e02112cc4e548e7a77b3d9ddfeffa8c8a2db13ceac361a4567d9","impliedFormat":99},{"version":"72a863bc6c0fc7a6263d8e07279167d86467a3869b5f002b1df6eaf5000ccc7b","impliedFormat":99},{"version":"5e2ba3d18d78aebbde1f34bde356e41e9c76eeaeaeee56a37036596a9eff4211","impliedFormat":99},{"version":"8280ae8ccc0493b32d1742d585357ab9f0a508ea050af25a5a20d64010d0a5cf","impliedFormat":99},{"version":"7adfd9f9056ecd4ae6c65fde2a98654960c662714c73f048478959d04c09e144","impliedFormat":99},{"version":"32b35cf0dc3a1b1a7118b61c34ce2ad1a29695851679f9ec34e0776f2ece2a69","impliedFormat":99},{"version":"b413fbc6658fe2774f8bf9a15cf4c53e586fc38a2d5256b3b9647da242c14389","impliedFormat":99},{"version":"42f0f7e74d73ae5873ed666373e09a367d62232ca378677094d0dc06020d6e00","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"ebb9b9fa684d70aef64614a59b7582f46f4982139b8b632b911ef98e10c4d117","impliedFormat":99},"2a2d7681383dd288562cc4d463b86fe49d87c7de89cf8f3ff18ac97fa7d05691","5e142dc22df20a3bf149623b8ffa12597374b0b1daf755879868410017858e9e",{"version":"8d7cbeea0454e05a3cdf3370c5df267072c4f1dc6c48a45a9ad750d7890443d7","affectsGlobalScope":true,"impliedFormat":99}],"root":[92,93],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":1,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":7},"referencedMap":[[73,1],[74,2],[56,3],[55,4],[75,3],[76,5],[60,6],[62,7],[61,8],[54,9],[53,10],[47,11],[49,12],[51,13],[52,11],[88,14],[90,15],[89,16],[87,17],[78,18],[67,19],[63,20],[64,6],[79,21],[65,22],[83,23],[66,24],[91,25],[85,26],[94,27],[81,28],[82,29],[93,30]],"affectedFilesPendingEmit":[[93,51],[92,51]],"emitSignatures":[92,93],"version":"5.9.3"} \ No newline at end of file diff --git a/packages/protocol/vitest.config.ts b/packages/protocol/vitest.config.ts new file mode 100644 index 0000000..8b54002 --- /dev/null +++ b/packages/protocol/vitest.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + exclude: [ + 'node_modules/', + 'dist/', + '**/*.test.ts', + '**/*.spec.ts', + ], + }, + }, +}); diff --git a/packages/relay-server/src/error-handling.test.ts b/packages/relay-server/src/error-handling.test.ts deleted file mode 100644 index 73e899b..0000000 --- a/packages/relay-server/src/error-handling.test.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { broadcastToMobileClients, mobileClients } from './index'; -import { SyncFullContextMessage, FileContextPayload } from '@codelink/protocol'; -import { Socket } from 'socket.io'; - -describe('Relay Server Error Handling', () => { - beforeEach(() => { - mobileClients.clear(); - vi.clearAllMocks(); - }); - - describe('Broadcast Error Handling', () => { - it('should handle client emit error gracefully', () => { - const errorClient = { - id: 'error-client', - connected: true, - emit: vi.fn(() => { - throw new Error('Socket emit failed'); - }), - } as unknown as Socket; - - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: false, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-123', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - mobileClients.add(errorClient); - - // Should not throw, should handle error gracefully - expect(() => broadcastToMobileClients(message)).not.toThrow(); - - // Error client should be removed - expect(mobileClients.has(errorClient)).toBe(false); - }); - - it('should continue broadcasting to other clients after one fails', () => { - const errorClient = { - id: 'error-client', - connected: true, - emit: vi.fn(() => { - throw new Error('Network error'); - }), - } as unknown as Socket; - - const successClient1 = { - id: 'success-1', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const successClient2 = { - id: 'success-2', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const payload: FileContextPayload = { - fileName: 'src/app.ts', - originalFile: '', - modifiedFile: 'content', - isDirty: true, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-456', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - mobileClients.add(errorClient); - mobileClients.add(successClient1); - mobileClients.add(successClient2); - - broadcastToMobileClients(message); - - // Success clients should still receive the message - expect(successClient1.emit).toHaveBeenCalledWith('message', JSON.stringify(message)); - expect(successClient2.emit).toHaveBeenCalledWith('message', JSON.stringify(message)); - - // Error client should be removed - expect(mobileClients.has(errorClient)).toBe(false); - expect(mobileClients.has(successClient1)).toBe(true); - expect(mobileClients.has(successClient2)).toBe(true); - }); - - it('should handle multiple client errors', () => { - const errorClient1 = { - id: 'error-1', - connected: true, - emit: vi.fn(() => { - throw new Error('Error 1'); - }), - } as unknown as Socket; - - const errorClient2 = { - id: 'error-2', - connected: true, - emit: vi.fn(() => { - throw new Error('Error 2'); - }), - } as unknown as Socket; - - const successClient = { - id: 'success', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const payload: FileContextPayload = { - fileName: 'src/index.ts', - originalFile: 'a', - modifiedFile: 'b', - isDirty: false, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-789', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - mobileClients.add(errorClient1); - mobileClients.add(errorClient2); - mobileClients.add(successClient); - - expect(() => broadcastToMobileClients(message)).not.toThrow(); - - // Success client should receive message - expect(successClient.emit).toHaveBeenCalled(); - - // Error clients should be removed - expect(mobileClients.has(errorClient1)).toBe(false); - expect(mobileClients.has(errorClient2)).toBe(false); - expect(mobileClients.has(successClient)).toBe(true); - }); - - it('should handle disconnected clients during broadcast', () => { - const disconnectedClient = { - id: 'disconnected', - connected: false, - emit: vi.fn(), - } as unknown as Socket; - - const connectedClient = { - id: 'connected', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const payload: FileContextPayload = { - fileName: 'src/file.ts', - originalFile: 'x', - modifiedFile: 'y', - isDirty: true, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-disconnect', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - mobileClients.add(disconnectedClient); - mobileClients.add(connectedClient); - - broadcastToMobileClients(message); - - // Only connected client should receive message - expect(connectedClient.emit).toHaveBeenCalled(); - expect(disconnectedClient.emit).not.toHaveBeenCalled(); - - // Disconnected client should be removed - expect(mobileClients.has(disconnectedClient)).toBe(false); - expect(mobileClients.has(connectedClient)).toBe(true); - }); - - it('should handle empty mobile clients set', () => { - const payload: FileContextPayload = { - fileName: 'src/empty.ts', - originalFile: '', - modifiedFile: '', - isDirty: false, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-empty', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - // Should not throw with empty set - expect(() => broadcastToMobileClients(message)).not.toThrow(); - }); - - it('should handle JSON serialization errors', () => { - const client = { - id: 'client', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - // Create a payload with circular reference (will cause JSON.stringify to fail) - const circularPayload: any = { - fileName: 'src/circular.ts', - originalFile: '', - modifiedFile: '', - isDirty: false, - timestamp: Date.now(), - }; - circularPayload.self = circularPayload; - - const message: any = { - id: 'msg-circular', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: circularPayload, - }; - - mobileClients.add(client); - - // Should throw during JSON.stringify, but we test that the function handles it - expect(() => broadcastToMobileClients(message)).toThrow(); - }); - }); -}); diff --git a/packages/relay-server/src/index.properties.test.ts b/packages/relay-server/src/index.properties.test.ts deleted file mode 100644 index d92fd86..0000000 --- a/packages/relay-server/src/index.properties.test.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import * as fc from 'fast-check'; -import { broadcastToMobileClients, mobileClients } from './index'; -import { SyncFullContextMessage, FileContextPayload } from '@codelink/protocol'; -import { Socket } from 'socket.io'; - -describe('Relay Server - Property-Based Tests', () => { - beforeEach(() => { - mobileClients.clear(); - }); - - // Feature: git-integration-diffing, Property 14: Message routing - it('Property 14: should route any SYNC_FULL_CONTEXT message to all connected mobile clients', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }), - fc.integer({ min: 0 }), - fc.string({ minLength: 1 }), - fc.string(), - fc.string(), - fc.boolean(), - fc.integer({ min: 1, max: 10 }), - (id, timestamp, fileName, originalFile, modifiedFile, isDirty, numClients) => { - // Clear clients before each property test - mobileClients.clear(); - - // Create mock clients - const mockClients: Socket[] = []; - for (let i = 0; i < numClients; i++) { - const mockClient = { - id: `mobile-${i}`, - connected: true, - emit: vi.fn(), - } as unknown as Socket; - mockClients.push(mockClient); - mobileClients.add(mockClient); - } - - // Create a SYNC_FULL_CONTEXT message - const payload: FileContextPayload = { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp, - }; - - const message: SyncFullContextMessage = { - id, - timestamp, - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - // Broadcast the message - broadcastToMobileClients(message); - - // Verify all clients received the message - const expectedMessage = JSON.stringify(message); - mockClients.forEach(client => { - expect(client.emit).toHaveBeenCalledWith('message', expectedMessage); - expect(client.emit).toHaveBeenCalledTimes(1); - }); - - // Verify all clients are still in the set - expect(mobileClients.size).toBe(numClients); - } - ), - { numRuns: 100 } - ); - }); - - // Additional property: Disconnected clients are removed - it('Property: should remove any disconnected client from the set', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }), - fc.integer({ min: 0 }), - fc.string({ minLength: 1 }), - fc.string(), - fc.string(), - fc.boolean(), - fc.integer({ min: 2, max: 10 }), - fc.integer({ min: 1, max: 5 }), - (id, timestamp, fileName, originalFile, modifiedFile, isDirty, numClients, numDisconnected) => { - // Ensure we don't try to disconnect more clients than we have - const actualDisconnected = Math.min(numDisconnected, numClients - 1); - - mobileClients.clear(); - - // Create mock clients - const mockClients: Socket[] = []; - for (let i = 0; i < numClients; i++) { - const isDisconnected = i < actualDisconnected; - const mockClient = { - id: `mobile-${i}`, - connected: !isDisconnected, - emit: vi.fn(), - } as unknown as Socket; - mockClients.push(mockClient); - mobileClients.add(mockClient); - } - - const payload: FileContextPayload = { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp, - }; - - const message: SyncFullContextMessage = { - id, - timestamp, - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - const initialSize = mobileClients.size; - broadcastToMobileClients(message); - - // Verify disconnected clients were removed - expect(mobileClients.size).toBe(initialSize - actualDisconnected); - - // Verify only connected clients received the message - mockClients.forEach((client, index) => { - if (index < actualDisconnected) { - expect(client.emit).not.toHaveBeenCalled(); - expect(mobileClients.has(client)).toBe(false); - } else { - expect(client.emit).toHaveBeenCalled(); - expect(mobileClients.has(client)).toBe(true); - } - }); - } - ), - { numRuns: 100 } - ); - }); - - // Additional property: Error handling doesn't crash - it('Property: should handle any client error without throwing', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }), - fc.integer({ min: 0 }), - fc.string({ minLength: 1 }), - fc.string(), - fc.string(), - fc.boolean(), - fc.integer({ min: 2, max: 10 }), - fc.integer({ min: 1, max: 5 }), - (id, timestamp, fileName, originalFile, modifiedFile, isDirty, numClients, numErrorClients) => { - const actualErrorClients = Math.min(numErrorClients, numClients - 1); - - mobileClients.clear(); - - // Create mock clients - const mockClients: Socket[] = []; - for (let i = 0; i < numClients; i++) { - const shouldError = i < actualErrorClients; - const mockClient = { - id: `mobile-${i}`, - connected: true, - emit: shouldError ? vi.fn(() => { throw new Error('Network error'); }) : vi.fn(), - } as unknown as Socket; - mockClients.push(mockClient); - mobileClients.add(mockClient); - } - - const payload: FileContextPayload = { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp, - }; - - const message: SyncFullContextMessage = { - id, - timestamp, - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - // Should not throw - expect(() => broadcastToMobileClients(message)).not.toThrow(); - - // Error clients should be removed - expect(mobileClients.size).toBe(numClients - actualErrorClients); - - // Verify error clients were removed - mockClients.forEach((client, index) => { - if (index < actualErrorClients) { - expect(mobileClients.has(client)).toBe(false); - } else { - expect(mobileClients.has(client)).toBe(true); - } - }); - } - ), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/relay-server/src/index.test.ts b/packages/relay-server/src/index.test.ts deleted file mode 100644 index 20fee8c..0000000 --- a/packages/relay-server/src/index.test.ts +++ /dev/null @@ -1,322 +0,0 @@ -import { describe, it, expect, vi } from 'vitest'; -import { parseMessage, createPongMessage, broadcastToMobileClients, mobileClients } from './index'; -import { PingMessage, SyncFullContextMessage, FileContextPayload } from '@codelink/protocol'; -import { Socket } from 'socket.io'; - -describe('Message Parsing', () => { - describe('parseMessage', () => { - it('should parse valid PingMessage JSON correctly', () => { - const validPing = { - id: 'test-id-123', - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - - const jsonString = JSON.stringify(validPing); - const parsed = parseMessage(jsonString); - - expect(parsed.id).toBe('test-id-123'); - expect(parsed.type).toBe('ping'); - expect(parsed.timestamp).toBe(validPing.timestamp); - if (parsed.type === 'ping') { - expect(parsed.source).toBe('extension'); - } - }); - - it('should parse valid PingMessage with mobile source', () => { - const validPing = { - id: 'mobile-id-456', - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - - const jsonString = JSON.stringify(validPing); - const parsed = parseMessage(jsonString); - - expect(parsed.id).toBe('mobile-id-456'); - expect(parsed.type).toBe('ping'); - if (parsed.type === 'ping') { - expect(parsed.source).toBe('mobile'); - } - }); - - it('should throw error for invalid JSON', () => { - const invalidJson = 'not valid json {'; - - expect(() => parseMessage(invalidJson)).toThrow(); - }); - - it('should throw error for message missing required fields', () => { - const missingId = JSON.stringify({ - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }); - - expect(() => parseMessage(missingId)).toThrow( - 'Invalid message format: missing required fields' - ); - }); - - it('should throw error for message missing type field', () => { - const missingType = JSON.stringify({ - id: 'test-id', - timestamp: Date.now(), - source: 'extension', - }); - - expect(() => parseMessage(missingType)).toThrow( - 'Invalid message format: missing required fields' - ); - }); - - it('should throw error for message missing timestamp field', () => { - const missingTimestamp = JSON.stringify({ - id: 'test-id', - type: 'ping', - source: 'extension', - }); - - expect(() => parseMessage(missingTimestamp)).toThrow( - 'Invalid message format: missing required fields' - ); - }); - }); - - describe('createPongMessage', () => { - it('should create PongMessage from PingMessage', () => { - const ping: PingMessage = { - id: 'ping-id-789', - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - - const pong = createPongMessage(ping); - - expect(pong.type).toBe('pong'); - expect(pong.originalId).toBe('ping-id-789'); - expect(typeof pong.id).toBe('string'); - expect(pong.id).not.toBe(ping.id); - expect(typeof pong.timestamp).toBe('number'); - }); - - it('should generate unique ID for PongMessage', () => { - const ping: PingMessage = { - id: 'ping-id-unique', - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - - const pong1 = createPongMessage(ping); - const pong2 = createPongMessage(ping); - - expect(pong1.id).not.toBe(pong2.id); - expect(pong1.originalId).toBe(ping.id); - expect(pong2.originalId).toBe(ping.id); - }); - - it('should set current timestamp for PongMessage', () => { - const ping: PingMessage = { - id: 'ping-id', - timestamp: Date.now() - 1000, // 1 second ago - type: 'ping', - source: 'extension', - }; - - const before = Date.now(); - const pong = createPongMessage(ping); - const after = Date.now(); - - expect(pong.timestamp).toBeGreaterThanOrEqual(before); - expect(pong.timestamp).toBeLessThanOrEqual(after); - expect(pong.timestamp).toBeGreaterThan(ping.timestamp); - }); - }); -}); - -describe('Relay Server Routing', () => { - describe('broadcastToMobileClients', () => { - it('should route SYNC_FULL_CONTEXT messages correctly', () => { - // Create mock mobile clients - const mockClient1 = { - id: 'mobile-1', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const mockClient2 = { - id: 'mobile-2', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - // Create a SYNC_FULL_CONTEXT message - const payload: FileContextPayload = { - fileName: 'src/test.ts', - originalFile: 'original content', - modifiedFile: 'modified content', - isDirty: true, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-123', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - // Manually add clients to the mobileClients set - mobileClients.clear(); - mobileClients.add(mockClient1); - mobileClients.add(mockClient2); - - // Broadcast the message - broadcastToMobileClients(message); - - // Verify both clients received the message - expect(mockClient1.emit).toHaveBeenCalledWith('message', JSON.stringify(message)); - expect(mockClient2.emit).toHaveBeenCalledWith('message', JSON.stringify(message)); - expect(mockClient1.emit).toHaveBeenCalledTimes(1); - expect(mockClient2.emit).toHaveBeenCalledTimes(1); - }); - - it('should broadcast to all connected mobile clients', () => { - const mockClient1 = { - id: 'mobile-1', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const mockClient2 = { - id: 'mobile-2', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const mockClient3 = { - id: 'mobile-3', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const payload: FileContextPayload = { - fileName: 'src/app.ts', - originalFile: '', - modifiedFile: 'new file content', - isDirty: false, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-456', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - mobileClients.clear(); - mobileClients.add(mockClient1); - mobileClients.add(mockClient2); - mobileClients.add(mockClient3); - - broadcastToMobileClients(message); - - expect(mockClient1.emit).toHaveBeenCalled(); - expect(mockClient2.emit).toHaveBeenCalled(); - expect(mockClient3.emit).toHaveBeenCalled(); - }); - - it('should skip disconnected clients', () => { - const connectedClient = { - id: 'mobile-connected', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const disconnectedClient = { - id: 'mobile-disconnected', - connected: false, - emit: vi.fn(), - } as unknown as Socket; - - const payload: FileContextPayload = { - fileName: 'src/index.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: true, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-789', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - mobileClients.clear(); - mobileClients.add(connectedClient); - mobileClients.add(disconnectedClient); - - broadcastToMobileClients(message); - - // Only connected client should receive the message - expect(connectedClient.emit).toHaveBeenCalledWith('message', JSON.stringify(message)); - expect(disconnectedClient.emit).not.toHaveBeenCalled(); - - // Disconnected client should be removed from the set - expect(mobileClients.has(disconnectedClient)).toBe(false); - expect(mobileClients.has(connectedClient)).toBe(true); - }); - - it('should handle errors during broadcast', () => { - const workingClient = { - id: 'mobile-working', - connected: true, - emit: vi.fn(), - } as unknown as Socket; - - const errorClient = { - id: 'mobile-error', - connected: true, - emit: vi.fn(() => { - throw new Error('Network error'); - }), - } as unknown as Socket; - - const payload: FileContextPayload = { - fileName: 'src/error.ts', - originalFile: 'content', - modifiedFile: 'content', - isDirty: false, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: 'msg-error', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - mobileClients.clear(); - mobileClients.add(workingClient); - mobileClients.add(errorClient); - - // Should not throw, should handle error gracefully - expect(() => broadcastToMobileClients(message)).not.toThrow(); - - // Working client should still receive the message - expect(workingClient.emit).toHaveBeenCalled(); - - // Error client should be removed from the set - expect(mobileClients.has(errorClient)).toBe(false); - expect(mobileClients.has(workingClient)).toBe(true); - }); - }); -}); diff --git a/packages/relay-server/src/index.ts b/packages/relay-server/src/index.ts index b3f2da4..2817411 100644 --- a/packages/relay-server/src/index.ts +++ b/packages/relay-server/src/index.ts @@ -1,5 +1,12 @@ import { Server, Socket } from 'socket.io'; -import { ProtocolMessage, PingMessage, PongMessage, SyncFullContextMessage, InjectPromptMessage, InjectPromptResponseMessage } from '@codelink/protocol'; +import { + ProtocolMessage, + PingMessage, + PongMessage, + SyncFullContextMessage, + InjectPromptMessage, + InjectPromptResponse, +} from '@codelink/protocol'; // Track connected clients by type export const extensionClients = new Set(); @@ -29,41 +36,53 @@ export function startServer(port: number = 8080): Server { const pong = createPongMessage(message); socket.emit('message', JSON.stringify(pong)); console.log(`[RelayServer] Sent pong to ${socket.id}`); - + // Track client type based on ping source if (message.source === 'extension') { extensionClients.add(socket); - console.log(`[RelayServer] Registered extension client: ${socket.id} (total: ${extensionClients.size})`); + console.log( + `[RelayServer] Registered extension client: ${socket.id} (total: ${extensionClients.size})` + ); } else if (message.source === 'mobile') { mobileClients.add(socket); - console.log(`[RelayServer] Registered mobile client: ${socket.id} (total: ${mobileClients.size})`); + console.log( + `[RelayServer] Registered mobile client: ${socket.id} (total: ${mobileClients.size})` + ); } } else if (message.type === 'SYNC_FULL_CONTEXT') { - console.log(`[RelayServer] Routing SYNC_FULL_CONTEXT message to ${mobileClients.size} mobile clients`); + console.log( + `[RelayServer] Routing SYNC_FULL_CONTEXT message to ${mobileClients.size} mobile clients` + ); broadcastToMobileClients(message as SyncFullContextMessage); } else if (message.type === 'INJECT_PROMPT') { - console.log(`[RelayServer] Routing INJECT_PROMPT message to ${extensionClients.size} extension clients`); + console.log( + `[RelayServer] Routing INJECT_PROMPT message to ${extensionClients.size} extension clients` + ); // Track which mobile client sent this request pendingPromptRequests.set(message.id, socket); routeToExtensionClients(message as InjectPromptMessage, socket); } else if (message.type === 'INJECT_PROMPT_RESPONSE') { console.log(`[RelayServer] Routing INJECT_PROMPT_RESPONSE back to mobile client`); - const response = message as InjectPromptResponseMessage; - + const response = message as InjectPromptResponse; + // Find the mobile client that sent the original request - if (response.originalRequestId && pendingPromptRequests.has(response.originalRequestId)) { - const mobileSocket = pendingPromptRequests.get(response.originalRequestId)!; - pendingPromptRequests.delete(response.originalRequestId); - + if (response.originalId && pendingPromptRequests.has(response.originalId)) { + const mobileSocket = pendingPromptRequests.get(response.originalId)!; + pendingPromptRequests.delete(response.originalId); + if (mobileSocket.connected) { mobileSocket.emit('message', JSON.stringify(response)); console.log(`[RelayServer] Routed response to mobile client ${mobileSocket.id}`); } else { - console.log(`[RelayServer] Mobile client ${mobileSocket.id} disconnected, cannot send response`); + console.log( + `[RelayServer] Mobile client ${mobileSocket.id} disconnected, cannot send response` + ); } } else { // Fallback: broadcast to all mobile clients if we can't find the original requester - console.log(`[RelayServer] No original request ID found, broadcasting to all mobile clients`); + console.log( + `[RelayServer] No original request ID found, broadcasting to all mobile clients` + ); broadcastResponseToMobileClients(response); } } @@ -76,7 +95,9 @@ export function startServer(port: number = 8080): Server { console.log(`[RelayServer] Client disconnected: ${socket.id}`); extensionClients.delete(socket); mobileClients.delete(socket); - console.log(`[RelayServer] Active clients - Extensions: ${extensionClients.size}, Mobile: ${mobileClients.size}`); + console.log( + `[RelayServer] Active clients - Extensions: ${extensionClients.size}, Mobile: ${mobileClients.size}` + ); }); socket.on('error', (error) => { @@ -110,13 +131,15 @@ export function broadcastToMobileClients(message: SyncFullContextMessage): void } }); - console.log(`[RelayServer] Broadcast complete: ${successCount} successful, ${errorCount} errors, ${mobileClients.size} total mobile clients`); + console.log( + `[RelayServer] Broadcast complete: ${successCount} successful, ${errorCount} errors, ${mobileClients.size} total mobile clients` + ); } /** * Broadcast INJECT_PROMPT_RESPONSE to all mobile clients (fallback when original requester is unknown) */ -export function broadcastResponseToMobileClients(message: InjectPromptResponseMessage): void { +export function broadcastResponseToMobileClients(message: InjectPromptResponse): void { const messageStr = JSON.stringify(message); let successCount = 0; @@ -141,14 +164,17 @@ export function broadcastResponseToMobileClients(message: InjectPromptResponseMe export function routeToExtensionClients(message: InjectPromptMessage, originSocket: Socket): void { if (extensionClients.size === 0) { // No extension clients available - send error response back to mobile - const errorResponse: InjectPromptResponseMessage = { + const errorResponse: InjectPromptResponse = { id: crypto.randomUUID(), timestamp: Date.now(), type: 'INJECT_PROMPT_RESPONSE', - success: false, - error: 'No extension client is connected. Please ensure the VS Code extension is running.', + originalId: message.id, + payload: { + success: false, + error: 'No extension client is connected. Please ensure the VS Code extension is running.', + }, }; - + originSocket.emit('message', JSON.stringify(errorResponse)); console.log(`[RelayServer] No extension clients available for prompt injection`); return; @@ -179,14 +205,17 @@ export function routeToExtensionClients(message: InjectPromptMessage, originSock if (!routed) { // All extension clients were disconnected - send error response - const errorResponse: InjectPromptResponseMessage = { + const errorResponse: InjectPromptResponse = { id: crypto.randomUUID(), timestamp: Date.now(), type: 'INJECT_PROMPT_RESPONSE', - success: false, - error: 'All extension clients are disconnected. Please check your VS Code extension.', + originalId: message.id, + payload: { + success: false, + error: 'All extension clients are disconnected. Please check your VS Code extension.', + }, }; - + originSocket.emit('message', JSON.stringify(errorResponse)); console.log(`[RelayServer] Failed to route INJECT_PROMPT - all extension clients disconnected`); } diff --git a/packages/relay-server/tsconfig.tsbuildinfo b/packages/relay-server/tsconfig.tsbuildinfo index c43ac12..ee8aaa5 100644 --- a/packages/relay-server/tsconfig.tsbuildinfo +++ b/packages/relay-server/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@vitest/utils/dist/types.d.ts","../../node_modules/@vitest/utils/dist/helpers.d.ts","../../node_modules/@sinclair/typebox/typebox.d.ts","../../node_modules/@jest/schemas/build/index.d.ts","../../node_modules/pretty-format/build/index.d.ts","../../node_modules/@vitest/utils/dist/index.d.ts","../../node_modules/@vitest/runner/dist/tasks-K5XERDtv.d.ts","../../node_modules/@vitest/utils/dist/types-9l4niLY8.d.ts","../../node_modules/@vitest/utils/dist/diff.d.ts","../../node_modules/@vitest/utils/diff.d.ts","../../node_modules/@vitest/runner/dist/types.d.ts","../../node_modules/@vitest/utils/dist/error.d.ts","../../node_modules/@vitest/utils/error.d.ts","../../node_modules/@vitest/runner/dist/index.d.ts","../../node_modules/@vitest/runner/dist/utils.d.ts","../../node_modules/@vitest/runner/utils.d.ts","../../node_modules/@types/node/compatibility/disposable.d.ts","../../node_modules/@types/node/compatibility/indexable.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/compatibility/index.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../node_modules/@types/node/web-globals/domexception.d.ts","../../node_modules/@types/node/web-globals/events.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/file.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/filereader.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/web-globals/fetch.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.generated.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/@types/estree/index.d.ts","../../node_modules/rollup/dist/rollup.d.ts","../../node_modules/vite/types/hmrPayload.d.ts","../../node_modules/vite/types/customEvent.d.ts","../../node_modules/vite/types/hot.d.ts","../../node_modules/vite/dist/node/types.d-aGj9QkWt.d.ts","../../node_modules/esbuild/lib/main.d.ts","../../node_modules/source-map-js/source-map.d.ts","../../node_modules/postcss/lib/previous-map.d.ts","../../node_modules/postcss/lib/input.d.ts","../../node_modules/postcss/lib/css-syntax-error.d.ts","../../node_modules/postcss/lib/declaration.d.ts","../../node_modules/postcss/lib/root.d.ts","../../node_modules/postcss/lib/warning.d.ts","../../node_modules/postcss/lib/lazy-result.d.ts","../../node_modules/postcss/lib/no-work-result.d.ts","../../node_modules/postcss/lib/processor.d.ts","../../node_modules/postcss/lib/result.d.ts","../../node_modules/postcss/lib/document.d.ts","../../node_modules/postcss/lib/rule.d.ts","../../node_modules/postcss/lib/node.d.ts","../../node_modules/postcss/lib/comment.d.ts","../../node_modules/postcss/lib/container.d.ts","../../node_modules/postcss/lib/at-rule.d.ts","../../node_modules/postcss/lib/list.d.ts","../../node_modules/postcss/lib/postcss.d.ts","../../node_modules/vite/dist/node/runtime.d.ts","../../node_modules/vite/types/importGlob.d.ts","../../node_modules/vite/types/metadata.d.ts","../../node_modules/vite/dist/node/index.d.ts","../../node_modules/vite-node/dist/trace-mapping.d-xyIfZtPm.d.ts","../../node_modules/vite-node/dist/index-O2IrwHKf.d.ts","../../node_modules/vite-node/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment-cMiGIVXz.d.ts","../../node_modules/@vitest/snapshot/dist/index-S94ASl6q.d.ts","../../node_modules/@vitest/snapshot/dist/index.d.ts","../../node_modules/@vitest/expect/dist/chai.d.cts","../../node_modules/@vitest/expect/dist/index.d.ts","../../node_modules/@vitest/expect/index.d.ts","../../node_modules/tinybench/dist/index.d.cts","../../node_modules/vite-node/dist/client.d.ts","../../node_modules/@vitest/snapshot/dist/manager.d.ts","../../node_modules/@vitest/snapshot/manager.d.ts","../../node_modules/vite-node/dist/server.d.ts","../../node_modules/vitest/dist/reporters-w_64AS5f.d.ts","../../node_modules/vitest/dist/suite-dWqIFb_-.d.ts","../../node_modules/@vitest/spy/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment.d.ts","../../node_modules/@vitest/snapshot/environment.d.ts","../../node_modules/vitest/dist/index.d.ts","../../node_modules/engine.io-parser/build/esm/commons.d.ts","../../node_modules/engine.io-parser/build/esm/encodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/decodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/index.d.ts","../../node_modules/engine.io/build/parser-v3/index.d.ts","../../node_modules/engine.io/build/transport.d.ts","../../node_modules/engine.io/build/socket.d.ts","../../node_modules/@types/cors/index.d.ts","../../node_modules/engine.io/build/contrib/types.cookie.d.ts","../../node_modules/engine.io/build/server.d.ts","../../node_modules/engine.io/build/transports/polling.d.ts","../../node_modules/engine.io/build/transports/websocket.d.ts","../../node_modules/engine.io/build/transports/webtransport.d.ts","../../node_modules/engine.io/build/transports/index.d.ts","../../node_modules/engine.io/build/userver.d.ts","../../node_modules/engine.io/build/engine.io.d.ts","../../node_modules/@socket.io/component-emitter/lib/cjs/index.d.ts","../../node_modules/socket.io-parser/build/esm/index.d.ts","../../node_modules/socket.io/dist/typed-events.d.ts","../../node_modules/socket.io/dist/client.d.ts","../../node_modules/socket.io-adapter/dist/in-memory-adapter.d.ts","../../node_modules/socket.io-adapter/dist/cluster-adapter.d.ts","../../node_modules/socket.io-adapter/dist/index.d.ts","../../node_modules/socket.io/dist/socket-types.d.ts","../../node_modules/socket.io/dist/broadcast-operator.d.ts","../../node_modules/socket.io/dist/socket.d.ts","../../node_modules/socket.io/dist/namespace.d.ts","../../node_modules/socket.io/dist/index.d.ts","../protocol/dist/index.d.ts","./src/index.ts","./src/error-handling.test.ts","../../node_modules/fast-check/lib/types/check/precondition/Pre.d.ts","../../node_modules/pure-rand/lib/types/generator/RandomGenerator.d.ts","../../node_modules/pure-rand/lib/types/generator/LinearCongruential.d.ts","../../node_modules/pure-rand/lib/types/generator/MersenneTwister.d.ts","../../node_modules/pure-rand/lib/types/generator/XorShift.d.ts","../../node_modules/pure-rand/lib/types/generator/XoroShiro.d.ts","../../node_modules/pure-rand/lib/types/distribution/Distribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/internals/ArrayInt.d.ts","../../node_modules/pure-rand/lib/types/distribution/UniformArrayIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UniformBigIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UniformIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UnsafeUniformArrayIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UnsafeUniformBigIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UnsafeUniformIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/pure-rand-default.d.ts","../../node_modules/pure-rand/lib/types/pure-rand.d.ts","../../node_modules/fast-check/lib/types/random/generator/Random.d.ts","../../node_modules/fast-check/lib/types/stream/Stream.d.ts","../../node_modules/fast-check/lib/types/check/arbitrary/definition/Value.d.ts","../../node_modules/fast-check/lib/types/check/arbitrary/definition/Arbitrary.d.ts","../../node_modules/fast-check/lib/types/check/precondition/PreconditionFailure.d.ts","../../node_modules/fast-check/lib/types/check/property/IRawProperty.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/MaxLengthFromMinLength.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/RandomType.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/VerbosityLevel.d.ts","../../node_modules/fast-check/lib/types/check/runner/reporter/ExecutionStatus.d.ts","../../node_modules/fast-check/lib/types/check/runner/reporter/ExecutionTree.d.ts","../../node_modules/fast-check/lib/types/check/runner/reporter/RunDetails.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/Parameters.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/GlobalParameters.d.ts","../../node_modules/fast-check/lib/types/check/property/AsyncProperty.generic.d.ts","../../node_modules/fast-check/lib/types/check/property/AsyncProperty.d.ts","../../node_modules/fast-check/lib/types/check/property/Property.generic.d.ts","../../node_modules/fast-check/lib/types/check/property/Property.d.ts","../../node_modules/fast-check/lib/types/check/runner/Runner.d.ts","../../node_modules/fast-check/lib/types/check/runner/Sampler.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/builders/GeneratorValueBuilder.d.ts","../../node_modules/fast-check/lib/types/arbitrary/gen.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/DepthContext.d.ts","../../node_modules/fast-check/lib/types/arbitrary/array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigInt.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigIntN.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigUint.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigUintN.d.ts","../../node_modules/fast-check/lib/types/arbitrary/boolean.d.ts","../../node_modules/fast-check/lib/types/arbitrary/falsy.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ascii.d.ts","../../node_modules/fast-check/lib/types/arbitrary/base64.d.ts","../../node_modules/fast-check/lib/types/arbitrary/char.d.ts","../../node_modules/fast-check/lib/types/arbitrary/char16bits.d.ts","../../node_modules/fast-check/lib/types/arbitrary/fullUnicode.d.ts","../../node_modules/fast-check/lib/types/arbitrary/hexa.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicode.d.ts","../../node_modules/fast-check/lib/types/arbitrary/constant.d.ts","../../node_modules/fast-check/lib/types/arbitrary/constantFrom.d.ts","../../node_modules/fast-check/lib/types/arbitrary/context.d.ts","../../node_modules/fast-check/lib/types/arbitrary/date.d.ts","../../node_modules/fast-check/lib/types/arbitrary/clone.d.ts","../../node_modules/fast-check/lib/types/arbitrary/dictionary.d.ts","../../node_modules/fast-check/lib/types/arbitrary/emailAddress.d.ts","../../node_modules/fast-check/lib/types/arbitrary/double.d.ts","../../node_modules/fast-check/lib/types/arbitrary/float.d.ts","../../node_modules/fast-check/lib/types/arbitrary/compareBooleanFunc.d.ts","../../node_modules/fast-check/lib/types/arbitrary/compareFunc.d.ts","../../node_modules/fast-check/lib/types/arbitrary/func.d.ts","../../node_modules/fast-check/lib/types/arbitrary/domain.d.ts","../../node_modules/fast-check/lib/types/arbitrary/integer.d.ts","../../node_modules/fast-check/lib/types/arbitrary/maxSafeInteger.d.ts","../../node_modules/fast-check/lib/types/arbitrary/maxSafeNat.d.ts","../../node_modules/fast-check/lib/types/arbitrary/nat.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ipV4.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ipV4Extended.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ipV6.d.ts","../../node_modules/fast-check/lib/types/arbitrary/letrec.d.ts","../../node_modules/fast-check/lib/types/arbitrary/lorem.d.ts","../../node_modules/fast-check/lib/types/arbitrary/mapToConstant.d.ts","../../node_modules/fast-check/lib/types/arbitrary/memo.d.ts","../../node_modules/fast-check/lib/types/arbitrary/mixedCase.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_shared/StringSharedConstraints.d.ts","../../node_modules/fast-check/lib/types/arbitrary/string.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/QualifiedObjectConstraints.d.ts","../../node_modules/fast-check/lib/types/arbitrary/object.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/JsonConstraintsBuilder.d.ts","../../node_modules/fast-check/lib/types/arbitrary/json.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicodeJson.d.ts","../../node_modules/fast-check/lib/types/arbitrary/anything.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicodeJsonValue.d.ts","../../node_modules/fast-check/lib/types/arbitrary/jsonValue.d.ts","../../node_modules/fast-check/lib/types/arbitrary/oneof.d.ts","../../node_modules/fast-check/lib/types/arbitrary/option.d.ts","../../node_modules/fast-check/lib/types/arbitrary/record.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uniqueArray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/infiniteStream.d.ts","../../node_modules/fast-check/lib/types/arbitrary/asciiString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/base64String.d.ts","../../node_modules/fast-check/lib/types/arbitrary/fullUnicodeString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/hexaString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/string16bits.d.ts","../../node_modules/fast-check/lib/types/arbitrary/stringOf.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicodeString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/subarray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/shuffledSubarray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/tuple.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ulid.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uuid.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uuidV.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webAuthority.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webFragments.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webPath.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webQueryParameters.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webSegment.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webUrl.d.ts","../../node_modules/fast-check/lib/types/check/model/command/ICommand.d.ts","../../node_modules/fast-check/lib/types/check/model/command/AsyncCommand.d.ts","../../node_modules/fast-check/lib/types/check/model/command/Command.d.ts","../../node_modules/fast-check/lib/types/check/model/commands/CommandsContraints.d.ts","../../node_modules/fast-check/lib/types/arbitrary/commands.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/interfaces/Scheduler.d.ts","../../node_modules/fast-check/lib/types/arbitrary/scheduler.d.ts","../../node_modules/fast-check/lib/types/check/model/ModelRunner.d.ts","../../node_modules/fast-check/lib/types/check/symbols.d.ts","../../node_modules/fast-check/lib/types/utils/hash.d.ts","../../node_modules/fast-check/lib/types/utils/stringify.d.ts","../../node_modules/fast-check/lib/types/check/runner/utils/RunDetailsFormatter.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/builders/TypedIntArrayArbitraryBuilder.d.ts","../../node_modules/fast-check/lib/types/arbitrary/int8Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/int16Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/int32Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint8Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint8ClampedArray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint16Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint32Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/float32Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/float64Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/sparseArray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigInt64Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigUint64Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/stringMatching.d.ts","../../node_modules/fast-check/lib/types/arbitrary/noShrink.d.ts","../../node_modules/fast-check/lib/types/arbitrary/noBias.d.ts","../../node_modules/fast-check/lib/types/arbitrary/limitShrink.d.ts","../../node_modules/fast-check/lib/types/fast-check-default.d.ts","../../node_modules/fast-check/lib/types/fast-check.d.ts","./src/index.properties.test.ts","./src/index.test.ts","../../node_modules/vitest/globals.d.ts"],"fileIdsList":[[48,67,113],[67,113],[67,113,127,161],[67,110,113],[67,112,113],[113],[67,113,118,146],[67,113,114,119,124,132,143,154],[67,113,114,115,124,132],[62,63,64,67,113],[67,113,116,155],[67,113,117,118,125,133],[67,113,118,143,151],[67,113,119,121,124,132],[67,112,113,120],[67,113,121,122],[67,113,123,124],[67,112,113,124],[67,113,124,125,126,143,154],[67,113,124,125,126,139,143,146],[67,113,121,124,127,132,143,154],[67,113,124,125,127,128,132,143,151,154],[67,113,127,129,143,151,154],[65,66,67,68,69,70,71,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160],[67,113,124,130],[67,113,131,154,159],[67,113,121,124,132,143],[67,113,133],[67,113,134],[67,112,113,135],[67,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160],[67,113,137],[67,113,138],[67,113,124,139,140],[67,113,139,141,155,157],[67,113,124,143,144,146],[67,113,145,146],[67,113,143,144],[67,113,146],[67,113,147],[67,110,113,143,148],[67,113,124,149,150],[67,113,149,150],[67,113,118,132,143,151],[67,113,152],[67,113,132,153],[67,113,127,138,154],[67,113,118,155],[67,113,143,156],[67,113,131,157],[67,113,158],[67,108,113],[67,108,113,124,126,135,143,146,154,157,159],[67,113,143,160],[51,55,67,113],[67,113,199],[51,52,55,56,58,67,113],[51,67,113],[51,52,55,67,113],[51,52,67,113],[60,67,113],[67,113,195],[50,67,113,195],[50,67,113,195,196],[67,113,209],[67,113,203],[54,67,113],[50,53,67,113],[46,67,113],[46,47,50,67,113],[50,67,113],[57,67,113],[67,113,212],[67,113,212,213,214],[67,113,127,215,217,218,221,225,226],[67,113,124,127,143,217,218,219,220],[67,113,124,127,215,217,221],[67,113,124,127,215,216],[67,113,217,222,223,224],[67,113,215,217],[67,113,217],[67,113,217,221],[67,113,262],[67,113,265],[67,113,265,322],[67,113,262,265,322],[67,113,262,323],[67,113,262,265,281],[67,113,262,321],[67,113,262,367],[67,113,262,356,357,358],[67,113,262,265],[67,113,262,265,304],[67,113,262,265,303],[67,113,262,279],[67,113,260,262],[67,113,262,325],[67,113,262,360],[67,113,262,265,349],[67,113,259,260,261],[67,113,356,357,361],[67,113,355],[67,113,262,273],[67,113,264,272],[67,113,259,260,261,263],[67,113,262,275],[67,113,264,270,271,274,276],[67,113,262,264,271],[67,113,265,271],[67,113,258,266,267,270],[67,113,268],[67,113,267,269,271],[67,113,270],[67,113,243,259,260,261,262,263,264,265,266,267,268,269,270,271,272,274,276,277,278,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,322,324,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383],[67,113,384],[67,113,258],[67,113,184],[67,113,182,184],[67,113,173,181,182,183,185,187],[67,113,171],[67,113,174,179,184,187],[67,113,170,187],[67,113,174,175,178,179,180,187],[67,113,174,175,176,178,179,187],[67,113,171,172,173,174,175,179,180,181,183,184,185,187],[67,113,169,171,172,173,174,175,176,178,179,180,181,182,183,184,185,186],[67,113,169,187],[67,113,174,176,177,179,180,187],[67,113,178,187],[67,113,179,180,184,187],[67,113,172,182],[49,67,113],[67,113,244],[67,113,244,249,250],[67,113,244,249],[67,113,244,250],[67,113,244,245,246,247,248,249,251,252,253,254,255,256],[67,113,257],[67,113,162,163],[67,113,232],[67,113,124],[67,113,232,233],[67,113,228],[67,113,230,234,235],[67,113,127,227,229,230,237,239],[67,113,127,128,129,227,229,230,234,235,236,237,238],[67,113,230,231,234,236,237,239],[67,113,127,138],[67,113,127,227,229,230,231,234,235,236,238],[67,80,84,113,154],[67,80,113,143,154],[67,75,113],[67,77,80,113,151,154],[67,113,132,151],[67,113,161],[67,75,113,161],[67,77,80,113,132,154],[67,72,73,76,79,113,124,143,154],[67,80,87,113],[67,72,78,113],[67,80,101,102,113],[67,76,80,113,146,154,161],[67,101,113,161],[67,74,75,113,161],[67,80,113],[67,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,102,103,104,105,106,107,113],[67,80,95,113],[67,80,87,88,113],[67,78,80,88,89,113],[67,79,113],[67,72,75,80,113],[67,80,84,88,89,113],[67,84,113],[67,78,80,83,113,154],[67,72,77,80,87,113],[67,113,143],[67,75,80,101,113,159,161],[67,113,192,193],[67,113,192],[67,113,191,192,193,206],[67,113,124,125,127,128,129,132,143,151,154,160,161,163,164,165,166,167,168,187,188,189,190],[67,113,164,165,166,167],[67,113,164,165,166],[67,113,164],[67,113,165],[67,113,163],[51,55,59,61,67,113,125,143,159,191,194,197,198,200,201,202,204,205,206,207,208,210],[51,59,61,67,113,125,143,159,191,194,197,198,200,201,202,204,205,206],[59,61,67,113,201,206],[67,113,211],[67,113,211,239,240,241],[67,113,211,239,240,241,385],[67,113,239,240]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"3deed5e2a5f1e7590d44e65a5b61900158a3c38bac9048462d38b1bc8098bb2e","impliedFormat":99},{"version":"d435a43f89ed8794744c59d72ce71e43c1953338303f6be9ef99086faa8591d7","impliedFormat":99},{"version":"c085e9aa62d1ae1375794c1fb927a445fa105fed891a7e24edbb1c3300f7384a","impliedFormat":1},{"version":"f315e1e65a1f80992f0509e84e4ae2df15ecd9ef73df975f7c98813b71e4c8da","impliedFormat":1},{"version":"5b9586e9b0b6322e5bfbd2c29bd3b8e21ab9d871f82346cb71020e3d84bae73e","impliedFormat":1},{"version":"a4f64e674903a21e1594a24c3fc8583f3a587336d17d41ade46aa177a8ab889b","impliedFormat":99},{"version":"b6f69984ffcd00a7cbcef9c931b815e8872c792ed85d9213cb2e2c14c50ca63a","impliedFormat":99},{"version":"2bbc5abe5030aa07a97aabd6d3932ed2e8b7a241cf3923f9f9bf91a0addbe41f","impliedFormat":99},{"version":"1e5e5592594e16bcf9544c065656293374120eb8e78780fb6c582cc710f6db11","impliedFormat":99},{"version":"05c7aef6a4e496b93c2e682cced8903c0dfe6340d04f3fe616176e2782193435","impliedFormat":99},{"version":"4abf1e884eecb0bf742510d69d064e33d53ac507991d6c573958356f920c3de4","impliedFormat":99},{"version":"44f1d2dd522c849ca98c4f95b8b2bc84b64408d654f75eb17ec78b8ceb84da11","impliedFormat":99},{"version":"500a67e158e4025f27570ab6a99831680852bb45a44d4c3647ab7567feb1fb4c","impliedFormat":99},{"version":"89edc5e1739692904fdf69edcff9e1023d2213e90372ec425b2f17e3aecbaa4a","impliedFormat":99},{"version":"e7d5bcffc98eded65d620bc0b6707c307b79c21d97a5fb8601e8bdf2296026b6","impliedFormat":99},{"version":"e666e31d323fef5642f87db0da48a83e58f0aaf9e3823e87eabd8ec7e0441a36","impliedFormat":99},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"2fd4c143eff88dabb57701e6a40e02a4dbc36d5eb1362e7964d32028056a782b","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e456fd5b101271183d99a9087875a282323e3a3ff0d7bcf1881537eaa8b8e63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"0225ecb9ed86bdb7a2c7fd01f1556906902929377b44483dc4b83e03b3ef227d","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"ddc734b4fae82a01d247e9e342d020976640b5e93b4e9b3a1e30e5518883a060","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"05db535df8bdc30d9116fe754a3473d1b6479afbc14ae8eb18b605c62677d518","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"4e741b9c88e80c9e4cedf07b5a698e8e3a3bd73cf649f664d6dd3f868c05c2f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","impliedFormat":1},{"version":"6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","impliedFormat":1},{"version":"cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","impliedFormat":1},{"version":"8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87","impliedFormat":99},{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true,"impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","impliedFormat":1},{"version":"333caa2bfff7f06017f114de738050dd99a765c7eb16571c6d25a38c0d5365dc","impliedFormat":1},{"version":"e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","impliedFormat":1},{"version":"459920181700cec8cbdf2a5faca127f3f17fd8dd9d9e577ed3f5f3af5d12a2e4","impliedFormat":1},{"version":"4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","impliedFormat":1},{"version":"7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","impliedFormat":1},{"version":"70790a7f0040993ca66ab8a07a059a0f8256e7bb57d968ae945f696cbff4ac7a","impliedFormat":1},{"version":"d1b9a81e99a0050ca7f2d98d7eedc6cda768f0eb9fa90b602e7107433e64c04c","impliedFormat":1},{"version":"a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","impliedFormat":1},{"version":"b215c4f0096f108020f666ffcc1f072c81e9f2f95464e894a5d5f34c5ea2a8b1","impliedFormat":1},{"version":"644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","impliedFormat":1},{"version":"dfe54dab1fa4961a6bcfba68c4ca955f8b5bbeb5f2ab3c915aa7adaa2eabc03a","impliedFormat":1},{"version":"1251d53755b03cde02466064260bb88fd83c30006a46395b7d9167340bc59b73","impliedFormat":1},{"version":"47865c5e695a382a916b1eedda1b6523145426e48a2eae4647e96b3b5e52024f","impliedFormat":1},{"version":"4cdf27e29feae6c7826cdd5c91751cc35559125e8304f9e7aed8faef97dcf572","impliedFormat":1},{"version":"331b8f71bfae1df25d564f5ea9ee65a0d847c4a94baa45925b6f38c55c7039bf","impliedFormat":1},{"version":"2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","impliedFormat":1},{"version":"0146fd6262c3fd3da51cb0254bb6b9a4e42931eb2f56329edd4c199cb9aaf804","impliedFormat":1},{"version":"82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","impliedFormat":99},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","impliedFormat":1},{"version":"257b83faa134d971c738a6b9e4c47e59bb7b23274719d92197580dd662bfafc3","impliedFormat":99},{"version":"4a27c79c57a6692abb196711f82b8b07a27908c94652148d5469887836390116","impliedFormat":99},{"version":"f42400484f181c2c2d7557c0ed3b8baaace644a9e943511f3d35ac6be6eb5257","impliedFormat":99},{"version":"54b381d36b35df872159a8d3b52e8d852659ee805695a867a388c8ccbf57521b","impliedFormat":99},{"version":"c67b4c864ec9dcde25f7ad51b90ae9fe1f6af214dbd063d15db81194fe652223","impliedFormat":99},{"version":"7a4aa00aaf2160278aeae3cf0d2fc6820cf22b86374efa7a00780fbb965923ff","impliedFormat":99},{"version":"66e3ee0a655ff3698be0aef05f7b76ac34c349873e073cde46d43db795b79f04","impliedFormat":99},{"version":"48c411efce1848d1ed55de41d7deb93cbf7c04080912fd87aa517ed25ef42639","affectsGlobalScope":true,"impliedFormat":1},{"version":"28e065b6fb60a04a538b5fbf8c003d7dac3ae9a49eddc357c2a14f2ffe9b3185","affectsGlobalScope":true,"impliedFormat":99},{"version":"fe2d63fcfdde197391b6b70daf7be8c02a60afa90754a5f4a04bdc367f62793d","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":1},{"version":"0d87708dafcde5468a130dfe64fac05ecad8328c298a4f0f2bd86603e5fd002e","impliedFormat":99},{"version":"a3f2554ba6726d0da0ffdc15b675b8b3de4aea543deebbbead845680b740a7fd","impliedFormat":99},{"version":"b7e28e06011460436d5c2ec2996846ac0c451e135357fc5a7269e5665a32fbd7","impliedFormat":99},{"version":"93dda0982b139b27b85dd2924d23e07ee8b4ca36a10be7bdf361163e4ffcc033","impliedFormat":99},{"version":"d7b652822e2a387fd2bcf0b78bcf2b7a9a9e73c4a71c12c5d0bbbb367aea6a87","affectsGlobalScope":true,"impliedFormat":99},{"version":"cb80558784fc93165b64809b3ba66266d10585d838709ebf5e4576f63f9f2929","impliedFormat":99},{"version":"dfa6bb848807bc5e01e84214d4ec13ee8ffe5e1142546dcbb32065783a5db468","impliedFormat":99},{"version":"2f1ffc29f9ba7b005c0c48e6389536a245837264c99041669e0b768cfab6711d","impliedFormat":99},{"version":"f2d1a59a658165341b0e2b7879aa2e19ea6a709146b2d3f70ee8a07159d3d08e","impliedFormat":99},{"version":"b4270f889835e50044bf80e479fef2482edd69daf4b168f9e3ee34cf817ae41a","impliedFormat":99},{"version":"569e762cf47aafdad508360a443c6c757e56c61db3b652b65458a7d168d139c4","impliedFormat":99},{"version":"02ed2766d79a00719ac3cc77851d54bd7197c1b12085ea12126bc2a65068223e","impliedFormat":99},{"version":"4b84373e192b7e0f8569b65eb16857098a6ee279b75d49223db2a751fdd7efde","impliedFormat":99},{"version":"5aeea312cd1d3cc5d72fc8a9c964439d771bdf41d9cce46667471b896b997473","impliedFormat":99},{"version":"cfa7bf135cafc5aad7cf544bc1cebf65a1fdb4373223cc85ea7d7196e18be151","impliedFormat":1},{"version":"f2c4a36eb216aadb0d9c79862a31b922ccfa1eaaa38d2124cc9192d40eda4779","impliedFormat":1},{"version":"cb5bb1db16ff4b534f56f7741e7ffd0a007ce36d387a377d4c196036e0932423","impliedFormat":1},{"version":"25be1eb939c9c63242c7a45446edb20c40541da967f43f1aa6a00ed53c0552db","impliedFormat":1},{"version":"08c2bb524b8ed271f194e1c7cc6ad0bcc773f596c41f68a207d0ec02c9727060","impliedFormat":1},{"version":"012b69bc8a16a21aa0863502339c49258c579723f9e7a54faa5f0d5c2b1ae1b7","impliedFormat":1},{"version":"29ad73d9e365d7b046f3168c6a510477bfe30d84a71cd7eb2f0e555b1d63f5f6","impliedFormat":1},{"version":"d99e9f5aa43397599fe824e38c33d13d3a9e19198806a4363114bd7ac58b29cc","impliedFormat":1},{"version":"440099416057789b14f85af057d4924915f27043399c10d4ca67409d94b963cf","impliedFormat":1},{"version":"ac44995fc7d0781d77927bae7dd41a31f0309e695fd2694b175c0ce3bc4b3b50","impliedFormat":1},{"version":"0c1f802f7a60ca8084e5188ac7952accdfc00f39ded3ebbbd3cdcc9da51b9a7b","impliedFormat":1},{"version":"a32e3fc530d8d1a18bf54678d8d55714827a50c9fabdd4ede7155a56be7d1dcb","impliedFormat":1},{"version":"14ecfc29e0c44ad4c5e50f9b597492cd8f45a2a635db8b5fe911a5da83e26cf8","impliedFormat":1},{"version":"06e9dc3f7549e194e0ed6e46e4ac52dee84bb5973f1e96edc2adff83ff6e6e5f","impliedFormat":99},{"version":"c2f041fe0e7ae2d5a19c477d19e8ec13de3d65ef45e442fa081cf6098cdcbe2d","impliedFormat":1},{"version":"0cef678147928ef223ff7f2aae3442cc9f4e9996956e9ac92434e626d0e147f8","impliedFormat":1},{"version":"198ae766bb698feb66d3188cfce59fb33696c951b10f901aa3fc3db4847ce76a","impliedFormat":1},{"version":"6dc488fd3d01e4269f0492b3e0ee7961eec79f4fc3ae997c7d28cde0572dbd91","impliedFormat":1},{"version":"a09b706f16bda9372761bd70cf59814b6f0a0c2970d62a5b2976e2fd157b920f","impliedFormat":1},{"version":"70da4bfde55d1ec74e3aa7635eae741f81ced44d3c344e2d299e677404570ca9","impliedFormat":1},{"version":"bf4f6b0d2ae8d11dc940c20891f9a4a558be906a530b9d9a8ff1032afa1962cd","impliedFormat":1},{"version":"9975431639f84750a914333bd3bfa9af47f86f54edbaa975617f196482cfee31","impliedFormat":1},{"version":"70a5cb56f988602271e772c65cb6735039148d5e90a4c270e5806f59fc51d3a0","impliedFormat":1},{"version":"e083384623f90cfa7e8d2aa7efe78c51095a04ad51d1f82c3e4052689666895d","impliedFormat":1},"5903e5db3aa79385274da245d1970fe1b124eb2f686c13335fffedbc843af701",{"version":"e28c60a97d5a0c15d2c834a7529851a7f6228a3f4cb704621d08f6d19e036e80","signature":"ba35cabd1a1ff6c4fd84abbc905a068cf397223f042a4e7a79900b47bb7f2b95"},{"version":"ee955b13b6c50de83292df8263971992ce81dc33463cde09efcc043d0fdacf0a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"b98cbe170e5774f6d9c364eef2a71dff38705390eada04670643271d436e44cd","impliedFormat":1},{"version":"2c1c7ebb6588ca14ec62bc2a19497b6378de25ab5d6a6241f4b8973f5f314faf","impliedFormat":1},{"version":"cefbdbc7607e7d32560385e018b991e18075f9b3b5b952f3b5f20478e4d15c43","impliedFormat":1},{"version":"72339629fd17518e8de4e495b0d91908a938fc4774457f09896789d40eb238b5","impliedFormat":1},{"version":"d0e5421dc798ee8146f82eddd6b96135f662e9a905c3afe400a029eea5b405a8","impliedFormat":1},{"version":"7a0a70d6f7ba13c11bb570a45000e6e428210ec2e1bdb8cbac46c90dfef698e8","impliedFormat":1},{"version":"b375d410108bcc3dab93dbc1de2b64777efac618025dbe675f1b2bfb63a91462","impliedFormat":1},{"version":"e352c35e7a226a5ff81bc9139e6e41bd5990f291a123de224987f5da34e2f725","impliedFormat":1},{"version":"3b416138214e8f4213e911723cf7f383ebdaa97e369687819452b53576980caf","impliedFormat":1},{"version":"faaed6dc3c93ac12afa83fc1a8ac384820437272622308b07f250650e16de120","impliedFormat":1},{"version":"16c28b35bb61fd8937b9ac446744601840e4d135ee863459259973e43d9ac458","impliedFormat":1},{"version":"4dd9018777b9b3feb8a7705841e3322000b3fa9dbb52aeaa7f189a4a408312f5","impliedFormat":1},{"version":"b91e472a9547e0d6e75b114c6d08d2e916174528f71c7473922d74018b9f9b93","impliedFormat":1},{"version":"c04a9cc39d447fa332a52e687b3ecd55165626c4305c1037d02afffd7020867c","impliedFormat":1},{"version":"e41e2bc86051b0f41d5ec99e728127e461b48152b6fb4735822b7fa4b4b0bc77","impliedFormat":1},{"version":"b49e721e29f8bb94b61bf8121a13965cced1b57cd088fb511c25a93c4ddfc1ac","impliedFormat":1},{"version":"24ff411ed19b006ec0efbdc5d56abd5f8a2a605eff97eb3db0941719c19e0844","impliedFormat":1},{"version":"190123e7b32a1a44dcc6b5b397cfd61c452606ea287576679d18f046b9296bf0","impliedFormat":1},{"version":"aeb54b9213fe90552e5e032abd0485d7ed21d505e59782b5e15c344a4ee54db6","impliedFormat":1},{"version":"51a201487cc0049e538a406c884d28b6d2ab141dd9c0650190b791c63803cae8","impliedFormat":1},{"version":"cb37d06c94592039ce1fa54d73ed241115494d886ee84800f3639cce48d0f832","impliedFormat":1},{"version":"82120a297fdf2f0bd9fa877f0c82b26bd9a94635536aa0ab59fe3ec78086f219","impliedFormat":1},{"version":"63aa0a9aa26aced773af0a69efe0cb58e12c7fc1257d1dcf951e9c301da67aee","impliedFormat":1},{"version":"fe9157ed26e6ab75adeead0164445d4ef49978baf2f9d2a5e635faf684d070d4","impliedFormat":1},{"version":"d0a02c12e4fb6b7c666773485e1ea53cdaa02b5b7c9483f370dccf1c815ff385","impliedFormat":1},{"version":"554edc2633760ba1c6ced5ce1e65586fe45f37c1f9f76052f68eadc4a06007b4","impliedFormat":1},{"version":"7c3335010a48156bb5eaa5866aeda1f0bf9a2402500e3cd3d047ca7b34f42dda","impliedFormat":1},{"version":"5d62771188e40ff7468d7f28ea5ed207ec0bce364e59e0fbf3e0c3ec794ddbf8","impliedFormat":1},{"version":"e6affb59098efce161ef8874843ecb1ebfed74f7374af0ce36ec4c9d1a370790","impliedFormat":1},{"version":"16cb0961a5f64defa068e4ce8482ed2e081bf1db2593205cca16f89f7d607b17","impliedFormat":1},{"version":"03bf2b2eee330dd7583c915349d75249ea3e4e2e90c9cc707957c22a37072f38","impliedFormat":1},{"version":"30ba32b82c39057e1f67f0ba14784836148a16d0c6feb5346d17b89559aadacc","impliedFormat":1},{"version":"f68437efcfd89bb312891b1e85e2ff4aa8fafcf0b648fc8d4726158aa4071252","impliedFormat":1},{"version":"dafb6d7587402ec60c4dd7129c8f84eb4af66c9f6b20c286b9dde8f316b9c7f2","impliedFormat":1},{"version":"598c2c581e6bd9171a59ef6ec9ce60d0eddcab49bd9db53a90d169c2387ec908","impliedFormat":1},{"version":"95ba818edf3770e357e9bbe6f55c9227a0041cb2460fff50e9d9e35ce7d23718","impliedFormat":1},{"version":"29a04903692cd5533c3c48c669361876522bde9f594f56d27589886157ad4894","impliedFormat":1},{"version":"d0e6175eb404f3de20b6e7168742eb3c9af55306209b3874ac0f946ac62158d3","impliedFormat":1},{"version":"3e8cfafb493180ef840f481750b49452001e5d80942a2a5d5151deae67b21465","impliedFormat":1},{"version":"d75c6765136563e3155b55220801379cbf1488eb42d7950afe1f94e1c8fde3e8","impliedFormat":1},{"version":"0126291175f486dcb5d8fceb57718c71c9ace7403987724127f373fd6696d067","impliedFormat":1},{"version":"01196174fb4b03fc4cba712a6e5150336b14d232d850dca2c9576d005f434715","impliedFormat":1},{"version":"16a8a7425362ec7531791fc18d2350f9801c483180cc93266c04b66e9676c464","impliedFormat":1},{"version":"63461bf37e9ef045b528e4f2182000922166e1c9729621f56984171cf49f2a8a","impliedFormat":1},{"version":"905fcafee4ebea900d9beec4fbff2b4c2551442da865733e1583085a4dc906d6","impliedFormat":1},{"version":"fe8165682f31b1f82cb93d62a759f1a26eaea745c361fbe2884134b73094d738","impliedFormat":1},{"version":"9b5d632d6f656382a85d3e77330cbf1eb27ed7290e9b3db0cd2663cf9251c6b8","impliedFormat":1},{"version":"2fc74eb5983a1a5986374eac99302432698a97186e577e91aa59b3ff91e657ec","impliedFormat":1},{"version":"ec767f9a0beefc9fc710bb0e5fc77f67468bb3b3fa34b9ebb8f72cd4f9fe2209","impliedFormat":1},{"version":"5fda99f644f00fb41efe3dfe936dc66d6f1d8d4abec93bf9735c4af3f70233dd","impliedFormat":1},{"version":"ceda7e9320a5a86ea760bb70c3c3b2278e01977b2cf30050ac9dfa80528e3442","impliedFormat":1},{"version":"d492ee06385287cce63b4173f7e553b7877464789598b03cec6b35ca2a64f9dd","impliedFormat":1},{"version":"2a0d3ddee69590b52ddec7eecfe8385fc2c54b3e2fd402439abe6b1c962434a6","impliedFormat":1},{"version":"55e6253bf987f95c86280b7bbb40500b5f5a21bfe890f166e647b864d3a7b8c5","impliedFormat":1},{"version":"efc4c4273bdda552afb3425998d95d87cb57a9e119734109c2282b3a378b305a","impliedFormat":1},{"version":"afb6cc0af49d24e5d787de77d5b46f05ecaea444f73829d60fcf6ceb76e608eb","impliedFormat":1},{"version":"882e89116341394e371cd8f24bc2e38239400276da03d3c38c9c9fe6b244fb1f","impliedFormat":1},{"version":"7d17be79ca035a9b8e02ba11f6351cea1bafd38c27a8004a401474ac2aa6695e","impliedFormat":1},{"version":"8e89f4377964cc23d5fe3bed390e5a415926f124a7cc7963d5e7bbce823e9887","impliedFormat":1},{"version":"7f6cdf4d7129c667eabf8c87b1798d5578623e39c42a3ff1aad742561e863858","impliedFormat":1},{"version":"ea5885ba5e792e0b88dc39f51b6b6c6c789d8fe2116bce3905f01d790f59c10d","impliedFormat":1},{"version":"0e09f1810ab7821d9d3c967323ec9cfa042cd9a1d8c3e8af4ed9b6dae4e63f86","impliedFormat":1},{"version":"f089bbeb3f2f0c528d3382fdea9cbb282ce252c918497e7abb974804f4faae1e","impliedFormat":1},{"version":"e57ad5997f573113f39391e780098560a341556b8d55d07b02675afbd72d82cf","impliedFormat":1},{"version":"896ed9bc9650a9ad6ead21583c007463217edeb58a4f45d1d019c1926b684643","impliedFormat":1},{"version":"7976b4472cfda91c462250daf51eae6e1121c2d725e4812d5c89019bb00e9551","impliedFormat":1},{"version":"901807bd11ececb52f0a2586689dacabf0e14f15e5e0604a673c9e1ff8186412","impliedFormat":1},{"version":"c9ebb2be9fc78b6df354c69b646c37945da54464389ce4342a0fd9cebc731f19","impliedFormat":1},{"version":"3f9a0317283412268b02f47fb3c83920a3b6a6c506898cef7e6ed42d5aff8d45","impliedFormat":1},{"version":"9de11c7d313d848291ec1a850637cc23dc7978f7350541af3314f7b343287d11","impliedFormat":1},{"version":"23f76b69848fe41a4801c7df41cf22bb380ad3fefc5adf2f7026d60f9f0451ba","impliedFormat":1},{"version":"ec17da14f94c8fddb8adeb4277b2cdd75f592095c4236db613853fe569ddb7b9","impliedFormat":1},{"version":"48ade6580bd1b0730427316352920606ff854f6a4548d2dee073fab4eecc6e62","impliedFormat":1},{"version":"5975ac1e6043d47f6771a0219b66530c23f05d1a27743091203ee7f6ea0f3a7b","impliedFormat":1},{"version":"e84b43d807d525da4dcd996ecf63e17245649672c2f620e84faed87e518ad639","impliedFormat":1},{"version":"2dbf4764d09250ec5850b5cd5ab47f72c9a16add6c73bd1f1ebfb55aefbb35d7","impliedFormat":1},{"version":"d147d653b19c446e14cc941c2a96eb111512702f765e086a450c5b720d2128b6","impliedFormat":1},{"version":"e9f2adc30882f676aa8109beeb32f2229da408f3ff25cd66b18e0d65fc162e51","impliedFormat":1},{"version":"1cc2419f7786055521ea0985b44dd961563a645dad471de3d6a45b83e686121f","impliedFormat":1},{"version":"9feba5111ddcd564d317f8a5fddd361f451b90fef6a17278134db450febc03a2","impliedFormat":1},{"version":"0b0ab6bb2cce3b6398ea9e01980e3a0d8dd341c6c83fffbcf4b33d3065fdeb76","impliedFormat":1},{"version":"31c5e0d467794830f02766351f8d5e9c2b08e6cc4e739478f798fb243e3eb8ce","impliedFormat":1},{"version":"7855b568645d7fa99b22eb48070c5174cf45c198b9f81abb5cbed6f4e6051a7b","impliedFormat":1},{"version":"fe01241cd36b45f1673814120a682aaa41ee12b62509c46535925ce991cca196","impliedFormat":1},{"version":"e2a3d01be6c9004bb660546b244d0bc3aba49ea6e42af5490afa6bb9eacaf03b","impliedFormat":1},{"version":"d46410a523d938fae1c998fd4317867ea4fd09c90f548070317570682e5fb144","impliedFormat":1},{"version":"3eb7886b8771bb649de71937d1d06a56277f9aa4705d4748ab10e2549cb90051","impliedFormat":1},{"version":"e1b882923b064f7ec2cec07f9ba2c2027d43502eb7fca3ce5444f5b4de8d812b","impliedFormat":1},{"version":"e05f866a0711a3a6059be95921a6c25b4a5a4190c295341ed4958950e491f9c4","impliedFormat":1},{"version":"a2fec5fe18ee1eea9782074951c366b9952f7dfd8282104cf8002821daddd07b","impliedFormat":1},{"version":"a4cf0ab697cbab80d76105244792d400e37a789cc3e783e94afc62290f4524e1","impliedFormat":1},{"version":"cd279bc48f9d44eb6cc4e98155ffbc29489d2ecc0ad8f83fee2956b62b0fbe47","impliedFormat":1},{"version":"b5f586144570a0e7cfb3efa1ae88c5f8b49d3429a0c63b7eecf7e521bffb6ab2","impliedFormat":1},{"version":"d78bef98f2833243f79ec5a6a2b09dc7ff5fc8d02916404c6599eb8596e5c17c","impliedFormat":1},{"version":"fdd66ca2430dd3eb6463f385c3898291d97b64f2e575ab53c101ee92ba073a5b","impliedFormat":1},{"version":"7b8326615d6ba6f85d6eec78447b5734839572075e053f01972e386569eb7cf9","impliedFormat":1},{"version":"5e1fca4ecd38a7a5194bffefb713460610521d1db4835f715d8b7e5132a451ae","impliedFormat":1},{"version":"e008e16c64ee65759e1336db16e538f2360bda6eee86303b7f9875f93566926a","impliedFormat":1},{"version":"4bf01b353ef24f6daf68d4ed15a40d079dbc8402824e41f9b11444c366c87e46","impliedFormat":1},{"version":"47d370c23aae9d4a46d108fbd241c2f4c4293934348fe67c09275863c663ba28","impliedFormat":1},{"version":"4e37aea128d8ee55192de216ec9b5c19b6f5469f2f3888965e878387b87d82ce","impliedFormat":1},{"version":"e0a26715db09e01d895767dad26409fe282b457fb937087066a83cdf7ed1510d","impliedFormat":1},{"version":"5bbc28e15ffe9c3b553b351da50907f3dace4b8f2698e8c633957ccca79f1587","impliedFormat":1},{"version":"d8605eab739e6eff9e5a810953bc8f110c18d4767915070122d8de270d93a539","impliedFormat":1},{"version":"159559d509aee31c698353bf9d021defadfc017acbcaaa979b03e8b9ea4fcdbe","impliedFormat":1},{"version":"ef830fa9b8ac8e1c7d328e632e1f37251c5f178157e0172b7f91bf82a249ae48","impliedFormat":1},{"version":"029c0ae6486c8247533c321d7769087178efe4f339344ed33ccc919d4645a65c","impliedFormat":1},{"version":"c85cc7e94c2b24b4fef57afb0ab6ecfe6d8fd54f8743f8e761ec1b5b2682d147","impliedFormat":1},{"version":"ba833bb474b4778dd0e708e12e5078a0044fdf872b130c23eee4d4d80cf59c1a","impliedFormat":1},{"version":"b22d90f2d362bb4b0ab09d42b5504a9ef1c3f768336c7676d75208cb9bf44fe1","impliedFormat":1},{"version":"ea725cf858cce0fa4c30b1957eebeb3b84c42c87721dc3a9212738adbdad3e47","impliedFormat":1},{"version":"556dc97b6164b18b1ace4ca474da27bc7ec07ed62d2e1f1e5feec7db34ea85e7","impliedFormat":1},{"version":"34f4a5e5abcb889bd4a1c070db50d102facc8d438bc12fbcd28cf10106e5dec8","impliedFormat":1},{"version":"b278e3030409d79aa0587a1327e4a9bc5333e1c6297f13e61e60117d49bac5a7","impliedFormat":1},{"version":"dcb93b7edd87a93bbda3480a506c636243c43849e28c209294f326080acfb4fd","impliedFormat":1},{"version":"f3179b329e1e7c7b8e9879597daa8d08d1a7c0e3409195b3db5adf0c8a972662","impliedFormat":1},{"version":"19d91a46dc5dff804b67c502c0d08348efa8e841b6eaefb938e4e4258b626882","impliedFormat":1},{"version":"550b1bcee751b496b5c54a4de7a747a186487e74971da1a2fb6488df24234dc5","impliedFormat":1},{"version":"6d54746945b9c2b2c88cd64dc22e5c642971dd39c221ba2ad9a602f46c260c31","impliedFormat":1},{"version":"00677cf86a3e8b5b64ac5a3963be34dd4f6e7b4e52fed9332e190b4a41877fba","impliedFormat":1},{"version":"7cae95b5b65941db32f44820159fa81605097327070ce7abc0508084e88d9366","impliedFormat":1},{"version":"82ea80af29aab4e0c39b6198d3b373ab6431b3f30ee02fdb8513fb1d80da2f98","impliedFormat":1},{"version":"6252c4e1c67faebb31907262e329975c9c9574e662b8e1f29a9e1c65f4933fc1","impliedFormat":1},{"version":"7dd32c136b356b80e648966b457bd5dba81e86a7a5e10118e5dc62a91e5d8dff","impliedFormat":1},{"version":"ff2807d90505df16875eb8beb04e6379d751ea5a6412a612aacc1779dc834f6f","impliedFormat":1},{"version":"707d69e35a457a02df69e407bf45c7c2bd770230e61fba69897c706373efda3d","impliedFormat":1},{"version":"ee3f3159fb0eb04322dc08ca0344cada9b1afdbff4bf021ed229ea33418c02bf","impliedFormat":1},{"version":"60a10874f1445d12af58ec3d7d26711b11b95d2432d7a67d591eed8ac42aeecb","impliedFormat":1},{"version":"6b54b93dee5a1c4f2432571fcb8b6846c224e5fa8a3e1d02a08760d202ba24bf","impliedFormat":1},{"version":"5b5af36f2494858b01f8bc22f08a90e7687fb20fe5b89aec9f05fea56ce2f4a7","impliedFormat":1},{"version":"01dc1755f60d10971b43d71562a7ee05deffc7317a88476becef9b30686fcf5d","impliedFormat":1},{"version":"d0e653d9a5f4970098dfd3bf7ff515fcde909d3599cabadd168b49dd3786c1d3","impliedFormat":1},{"version":"2170cbd9e9feba37765aac36f6bced8349b51b70149b96c359ef6e4e581d29cb","impliedFormat":1},{"version":"e5a7066c96dd80d71293afb5c694142d66abc6a649be4bd6bcdf8629f80bd647","impliedFormat":1},{"version":"d144a03dc18068dc788da021f34b96cd0011aa767f0c811fd16e17e0fabafac4","impliedFormat":1},{"version":"41d4348127cac62f18177bfbd6673d7227d08df3c834808b7bbf623220854dcb","impliedFormat":1},{"version":"82f83d1c59621504a282813d2079d319d14134acb9a4e753bc661286b760d93f","impliedFormat":1},{"version":"320f2403a8976b11068464b8c031e9a7418d01e2b226f4a75dbddba2ea071e02","impliedFormat":1},{"version":"2df0f708ce3ca701d9ecb1ad865337b6ece0a464c1db0a4d7beaef0e6c1431c7","impliedFormat":1},{"version":"d0c23c27ab25f8298fbdb57f90d7c9555dd9dedf6c65910491f0502149296bc3","impliedFormat":1},{"version":"a9dc1a642ec16c8b9c319d886b8e4a5bf3737879794b17a6e3c3a8a20b9a8084","impliedFormat":1},{"version":"8d7416be7127d2bcea8591a0a8aeac9ef14e400cb67cba14f93ad2efd78abed8","impliedFormat":1},{"version":"4f76cabb92d767cc8f854a5c26a1ecfa068b6095bb7abf45803f91e16ee817b4","impliedFormat":1},{"version":"64581a01977d10ca789f9308212aa17b1b2bbe1b917d7effa151c4e1d3a85b81","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"1880534145d801e01e892d1b78f954760216e794883483729a91519faa56ed00","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"381d27c35f5a5bf6c09dd238ec26fef30a03d12ea84589c621ebc208d7dc8378","affectsGlobalScope":true,"impliedFormat":99}],"root":[241,242,386,387],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":1,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":7},"referencedMap":[[49,1],[48,2],[228,2],[219,3],[162,2],[110,4],[111,4],[112,5],[67,6],[113,7],[114,8],[115,9],[62,2],[65,10],[63,2],[64,2],[116,11],[117,12],[118,13],[119,14],[120,15],[121,16],[122,16],[123,17],[124,18],[125,19],[126,20],[68,2],[66,2],[127,21],[128,22],[129,23],[161,24],[130,25],[131,26],[132,27],[133,28],[134,29],[135,30],[136,31],[137,32],[138,33],[139,34],[140,34],[141,35],[142,2],[143,36],[145,37],[144,38],[146,39],[147,40],[148,41],[149,42],[150,43],[151,44],[152,45],[153,46],[154,47],[155,48],[156,49],[157,50],[158,51],[69,2],[70,2],[71,2],[109,52],[159,53],[160,54],[198,2],[199,55],[200,56],[59,57],[52,58],[56,59],[60,60],[61,61],[195,2],[209,62],[196,63],[197,64],[203,64],[210,65],[204,66],[208,2],[55,67],[54,68],[57,68],[47,69],[51,70],[53,71],[46,2],[58,72],[212,2],[214,73],[213,73],[215,74],[220,2],[227,75],[216,2],[221,76],[218,77],[217,78],[225,79],[222,80],[223,80],[224,81],[226,82],[168,2],[279,83],[367,84],[281,2],[325,85],[265,2],[323,86],[360,2],[321,84],[328,87],[282,88],[289,83],[336,89],[290,83],[337,89],[283,83],[378,90],[284,83],[285,83],[379,90],[286,83],[287,83],[291,83],[292,83],[300,83],[359,91],[305,83],[306,83],[296,83],[297,83],[298,83],[299,83],[301,88],[308,92],[303,83],[302,92],[288,83],[304,83],[375,93],[376,94],[293,83],[338,89],[307,83],[280,95],[294,83],[339,89],[335,96],[369,90],[370,90],[368,90],[309,83],[313,83],[314,83],[315,83],[326,97],[330,97],[316,83],[383,83],[317,92],[318,83],[310,83],[311,83],[319,83],[320,83],[312,83],[382,83],[381,83],[324,87],[331,88],[332,88],[333,83],[361,98],[344,83],[377,88],[322,89],[340,89],[380,92],[341,89],[343,83],[345,83],[373,90],[374,90],[371,90],[372,90],[346,83],[295,83],[327,97],[329,97],[342,89],[334,88],[347,83],[348,83],[349,92],[350,92],[351,92],[352,92],[353,92],[354,99],[262,100],[261,2],[362,101],[356,102],[357,102],[355,2],[358,84],[243,2],[263,2],[274,103],[273,104],[264,105],[276,106],[275,104],[277,107],[278,108],[272,109],[271,110],[266,2],[267,2],[268,2],[269,111],[270,112],[366,113],[363,2],[384,114],[385,115],[259,116],[260,2],[364,2],[365,2],[185,117],[183,118],[184,119],[172,120],[173,118],[180,121],[171,122],[176,123],[186,2],[177,124],[182,125],[187,126],[170,127],[178,128],[179,129],[174,130],[181,117],[175,131],[50,132],[249,133],[251,134],[252,135],[253,135],[254,136],[255,133],[256,133],[250,2],[245,133],[246,133],[244,2],[247,133],[248,133],[257,137],[258,138],[163,139],[233,140],[232,141],[234,142],[229,143],[236,144],[231,145],[239,146],[238,147],[235,148],[237,149],[230,141],[169,2],[201,2],[44,2],[45,2],[9,2],[8,2],[2,2],[10,2],[11,2],[12,2],[13,2],[14,2],[15,2],[16,2],[17,2],[3,2],[18,2],[19,2],[4,2],[20,2],[24,2],[21,2],[22,2],[23,2],[25,2],[26,2],[27,2],[5,2],[28,2],[29,2],[30,2],[31,2],[6,2],[35,2],[32,2],[33,2],[34,2],[36,2],[7,2],[37,2],[42,2],[43,2],[38,2],[39,2],[40,2],[41,2],[1,2],[87,150],[97,151],[86,150],[107,152],[78,153],[77,154],[106,155],[100,156],[105,157],[80,158],[94,159],[79,160],[103,161],[75,162],[74,155],[104,163],[76,164],[81,165],[82,2],[85,165],[72,2],[108,166],[98,167],[89,168],[90,169],[92,170],[88,171],[91,172],[101,155],[83,173],[84,174],[93,175],[73,176],[96,167],[95,165],[99,2],[102,177],[202,178],[193,179],[194,178],[205,180],[192,2],[191,181],[188,182],[167,183],[165,184],[164,2],[166,185],[189,2],[190,186],[211,187],[206,188],[207,189],[388,190],[240,2],[242,191],[386,192],[387,191],[241,193]],"latestChangedDtsFile":"./dist/index.d.ts","version":"5.9.3"} \ No newline at end of file +{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/engine.io-parser/build/esm/commons.d.ts","../../node_modules/engine.io-parser/build/esm/encodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/decodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/index.d.ts","../../node_modules/engine.io/build/parser-v3/index.d.ts","../../node_modules/engine.io/build/transport.d.ts","../../node_modules/engine.io/build/socket.d.ts","../../node_modules/@types/node/compatibility/disposable.d.ts","../../node_modules/@types/node/compatibility/indexable.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/compatibility/index.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../node_modules/@types/node/web-globals/domexception.d.ts","../../node_modules/@types/node/web-globals/events.d.ts","../../node_modules/buffer/index.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/file.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/filereader.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/web-globals/fetch.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.generated.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/@types/cors/index.d.ts","../../node_modules/engine.io/build/contrib/types.cookie.d.ts","../../node_modules/engine.io/build/server.d.ts","../../node_modules/engine.io/build/transports/polling.d.ts","../../node_modules/engine.io/build/transports/websocket.d.ts","../../node_modules/engine.io/build/transports/webtransport.d.ts","../../node_modules/engine.io/build/transports/index.d.ts","../../node_modules/engine.io/build/userver.d.ts","../../node_modules/engine.io/build/engine.io.d.ts","../../node_modules/@socket.io/component-emitter/lib/cjs/index.d.ts","../../node_modules/socket.io-parser/build/esm/index.d.ts","../../node_modules/socket.io/dist/typed-events.d.ts","../../node_modules/socket.io/dist/client.d.ts","../../node_modules/socket.io-adapter/dist/in-memory-adapter.d.ts","../../node_modules/socket.io-adapter/dist/cluster-adapter.d.ts","../../node_modules/socket.io-adapter/dist/index.d.ts","../../node_modules/socket.io/dist/socket-types.d.ts","../../node_modules/socket.io/dist/broadcast-operator.d.ts","../../node_modules/socket.io/dist/socket.d.ts","../../node_modules/socket.io/dist/namespace.d.ts","../../node_modules/socket.io/dist/index.d.ts","../protocol/dist/index.d.ts","./src/index.ts","../../node_modules/@vitest/utils/node_modules/@vitest/pretty-format/dist/index.d.ts","../../node_modules/@vitest/utils/dist/display.d.ts","../../node_modules/@vitest/utils/dist/types.d.ts","../../node_modules/@vitest/utils/dist/helpers.d.ts","../../node_modules/@vitest/utils/dist/timers.d.ts","../../node_modules/@vitest/utils/dist/index.d.ts","../../node_modules/@vitest/utils/dist/types.d-BCElaP-c.d.ts","../../node_modules/@vitest/utils/dist/diff.d.ts","../../node_modules/@vitest/utils/diff.d.ts","../../node_modules/@vitest/runner/dist/tasks.d-D2GKpdwQ.d.ts","../../node_modules/@vitest/runner/dist/index.d.ts","../../node_modules/vitest/dist/chunks/traces.d.402V_yFI.d.ts","../../node_modules/vitest/node_modules/@vitest/pretty-format/dist/index.d.ts","../../node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment.d-DOJxxZV9.d.ts","../../node_modules/@vitest/snapshot/dist/rawSnapshot.d-U2kJUxDr.d.ts","../../node_modules/@vitest/snapshot/dist/index.d.ts","../../node_modules/vitest/dist/chunks/config.d.EJLVE3es.d.ts","../../node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts","../../node_modules/vitest/dist/chunks/rpc.d.BFMWpdph.d.ts","../../node_modules/vitest/dist/chunks/worker.d.B84sVRy0.d.ts","../../node_modules/vitest/dist/chunks/browser.d.X3SXoOCV.d.ts","../../node_modules/@vitest/spy/dist/index.d.ts","../../node_modules/tinyrainbow/dist/index.d.ts","../../node_modules/@standard-schema/spec/dist/index.d.ts","../../node_modules/@types/deep-eql/index.d.ts","../../node_modules/@types/chai/node_modules/assertion-error/index.d.ts","../../node_modules/@types/chai/index.d.ts","../../node_modules/@vitest/expect/dist/index.d.ts","../../node_modules/@vitest/runner/dist/utils.d.ts","../../node_modules/@vitest/runner/utils.d.ts","../../node_modules/tinybench/dist/index.d.cts","../../node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts","../../node_modules/vitest/dist/chunks/global.d.x-ILCfAE.d.ts","../../node_modules/vitest/node_modules/@vitest/mocker/dist/types.d-BjI5eAwu.d.ts","../../node_modules/vitest/node_modules/@vitest/mocker/dist/index.d-B41z0AuW.d.ts","../../node_modules/vitest/node_modules/@vitest/mocker/dist/index.d.ts","../../node_modules/vitest/dist/chunks/suite.d.udJtyAgw.d.ts","../../node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts","../../node_modules/vitest/dist/runners.d.ts","../../node_modules/expect-type/dist/utils.d.ts","../../node_modules/expect-type/dist/overloads.d.ts","../../node_modules/expect-type/dist/branding.d.ts","../../node_modules/expect-type/dist/messages.d.ts","../../node_modules/expect-type/dist/index.d.ts","../../node_modules/vitest/dist/index.d.ts","../../node_modules/vitest/globals.d.ts"],"fileIdsList":[[58,105],[58,105,202,203],[58,105,119,153],[58,102,105],[58,104,105],[105],[58,105,110,138],[58,105,106,111,116,124,135,146],[58,105,106,107,116,124],[53,54,55,58,105],[58,105,108,147],[58,105,109,110,117,125],[58,105,110,135,143],[58,105,111,113,116,124],[58,104,105,112],[58,105,113,114],[58,105,115,116],[58,104,105,116],[58,105,116,117,118,135,146],[58,105,116,117,118,131,135,138],[58,105,113,116,119,124,135,146],[58,105,116,117,119,120,124,135,143,146],[58,105,119,121,135,143,146],[56,57,58,59,60,61,62,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152],[58,105,116,122],[58,105,123,146,151],[58,105,113,116,124,135],[58,105,125],[58,105,126],[58,104,105,127],[58,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152],[58,105,129],[58,105,130],[58,105,116,131,132],[58,105,131,133,147,149],[58,105,116,135,136,138],[58,105,137,138],[58,105,135,136],[58,105,138],[58,105,139],[58,102,105,135,140],[58,105,116,141,142],[58,105,141,142],[58,105,110,124,135,143],[58,105,144],[58,105,124,145],[58,105,119,130,146],[58,105,110,147],[58,105,135,148],[58,105,123,149],[58,105,150],[58,100,105],[58,100,105,116,118,127,135,138,146,149,151],[58,105,135,152],[58,105,185,187,199,200,201,204,210],[58,105,182,185,186],[58,105,182,185],[58,105,206],[58,105,182],[58,105,177,182,191,192],[58,105,177,191],[58,105,184],[58,105,177,183],[58,105,177],[58,105,179],[58,105,177,178,179,180,181],[46,58,105],[46,47,48,58,105],[49,51,52,58,105,119,156,160,161],[51,52,58,105,116,119,135,154,155],[49,51,58,105,116,119,156],[49,50,58,105,116,119],[51,58,105,157,158,159],[49,51,58,105],[51,58,105],[51,58,105,156],[58,105,217,218],[58,105,217,218,219,220],[58,105,217,219],[58,105,217],[58,105,167],[58,105,116],[58,105,167,168],[58,105,163],[58,105,165,169,170],[58,105,119,162,164,165,172,174],[58,105,119,120,121,162,164,165,169,170,171,172,173],[58,105,165,166,169,171,172,174],[58,105,119,130],[58,105,119,162,164,165,166,169,170,171,173],[58,72,76,105,146],[58,72,105,135,146],[58,67,105],[58,69,72,105,143,146],[58,105,124,143],[58,105,153],[58,67,105,153],[58,69,72,105,124,146],[58,64,65,68,71,105,116,135,146],[58,72,79,105],[58,64,70,105],[58,72,93,94,105],[58,68,72,105,138,146,153],[58,93,105,153],[58,66,67,105,153],[58,72,105],[58,66,67,68,69,70,71,72,73,74,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,94,95,96,97,98,99,105],[58,72,87,105],[58,72,79,80,105],[58,70,72,80,81,105],[58,71,105],[58,64,67,72,105],[58,72,76,80,81,105],[58,76,105],[58,70,72,75,105,146],[58,64,69,72,79,105],[58,105,135],[58,67,72,93,105,151,153],[58,105,187,207,208,210],[58,105,187,188,197,210],[58,105,177,185,187,193,210],[58,105,177,187,193,196,205,209,210],[58,105,187,188,193,210],[58,105,187,207,208,209,210],[58,105,187,194,195,196,210],[58,105,177,182,185,187,188,193,194,195,196,197,198,199,205,207,208,209,210,213,214,215,216,221],[58,105,177,185,187,188,193,194,207,208,209,210,214],[58,105,222],[58,105,211],[58,105,211,212],[58,105,174,175]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"569e762cf47aafdad508360a443c6c757e56c61db3b652b65458a7d168d139c4","impliedFormat":99},{"version":"02ed2766d79a00719ac3cc77851d54bd7197c1b12085ea12126bc2a65068223e","impliedFormat":99},{"version":"4b84373e192b7e0f8569b65eb16857098a6ee279b75d49223db2a751fdd7efde","impliedFormat":99},{"version":"5aeea312cd1d3cc5d72fc8a9c964439d771bdf41d9cce46667471b896b997473","impliedFormat":99},{"version":"cfa7bf135cafc5aad7cf544bc1cebf65a1fdb4373223cc85ea7d7196e18be151","impliedFormat":1},{"version":"f2c4a36eb216aadb0d9c79862a31b922ccfa1eaaa38d2124cc9192d40eda4779","impliedFormat":1},{"version":"cb5bb1db16ff4b534f56f7741e7ffd0a007ce36d387a377d4c196036e0932423","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"2fd4c143eff88dabb57701e6a40e02a4dbc36d5eb1362e7964d32028056a782b","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e456fd5b101271183d99a9087875a282323e3a3ff0d7bcf1881537eaa8b8e63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"0225ecb9ed86bdb7a2c7fd01f1556906902929377b44483dc4b83e03b3ef227d","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"ddc734b4fae82a01d247e9e342d020976640b5e93b4e9b3a1e30e5518883a060","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"05db535df8bdc30d9116fe754a3473d1b6479afbc14ae8eb18b605c62677d518","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"25be1eb939c9c63242c7a45446edb20c40541da967f43f1aa6a00ed53c0552db","impliedFormat":1},{"version":"08c2bb524b8ed271f194e1c7cc6ad0bcc773f596c41f68a207d0ec02c9727060","impliedFormat":1},{"version":"012b69bc8a16a21aa0863502339c49258c579723f9e7a54faa5f0d5c2b1ae1b7","impliedFormat":1},{"version":"29ad73d9e365d7b046f3168c6a510477bfe30d84a71cd7eb2f0e555b1d63f5f6","impliedFormat":1},{"version":"d99e9f5aa43397599fe824e38c33d13d3a9e19198806a4363114bd7ac58b29cc","impliedFormat":1},{"version":"440099416057789b14f85af057d4924915f27043399c10d4ca67409d94b963cf","impliedFormat":1},{"version":"ac44995fc7d0781d77927bae7dd41a31f0309e695fd2694b175c0ce3bc4b3b50","impliedFormat":1},{"version":"0c1f802f7a60ca8084e5188ac7952accdfc00f39ded3ebbbd3cdcc9da51b9a7b","impliedFormat":1},{"version":"a32e3fc530d8d1a18bf54678d8d55714827a50c9fabdd4ede7155a56be7d1dcb","impliedFormat":1},{"version":"14ecfc29e0c44ad4c5e50f9b597492cd8f45a2a635db8b5fe911a5da83e26cf8","impliedFormat":1},{"version":"ba0badf6398010ef0ba77947d4b52078fc84cb4f209f6b70194b3b2cfb1823d8","impliedFormat":99},{"version":"c2f041fe0e7ae2d5a19c477d19e8ec13de3d65ef45e442fa081cf6098cdcbe2d","impliedFormat":1},{"version":"0cef678147928ef223ff7f2aae3442cc9f4e9996956e9ac92434e626d0e147f8","impliedFormat":1},{"version":"198ae766bb698feb66d3188cfce59fb33696c951b10f901aa3fc3db4847ce76a","impliedFormat":1},{"version":"6dc488fd3d01e4269f0492b3e0ee7961eec79f4fc3ae997c7d28cde0572dbd91","impliedFormat":1},{"version":"a09b706f16bda9372761bd70cf59814b6f0a0c2970d62a5b2976e2fd157b920f","impliedFormat":1},{"version":"70da4bfde55d1ec74e3aa7635eae741f81ced44d3c344e2d299e677404570ca9","impliedFormat":1},{"version":"bf4f6b0d2ae8d11dc940c20891f9a4a558be906a530b9d9a8ff1032afa1962cd","impliedFormat":1},{"version":"9975431639f84750a914333bd3bfa9af47f86f54edbaa975617f196482cfee31","impliedFormat":1},{"version":"70a5cb56f988602271e772c65cb6735039148d5e90a4c270e5806f59fc51d3a0","impliedFormat":1},{"version":"e083384623f90cfa7e8d2aa7efe78c51095a04ad51d1f82c3e4052689666895d","impliedFormat":1},"002aaa2b5c035f279742899379e4b7194ed6bdd846f27cfb1489c3aad1e6d9d5",{"version":"d7c36c8da2c9749ed0bc7a5eeb2e9c137fffd94527d750ff5a65accc4f6d0a7b","signature":"eb5109c25a3aa6426353ac76dffb4e45ba153232262bf25c1ec63e2e3e7f5bec"},{"version":"cadeb2c96f1c964d7e49c0f17d6805e1b4dee62f0862c49bb178dae6ab277e8e","impliedFormat":99},{"version":"0528f6d21f7a02d4092895090d2dd86104bd5a3e79eced96d5a1a7dd90943d17","impliedFormat":99},{"version":"b5ce343886d23392be9c8280e9f24a87f1d7d3667f6672c2fe4aa61fa4ece7d4","impliedFormat":99},{"version":"eb64a68249f1ee45e496a23cd0be8fe8c84aecb4c038b86d4abcc765c5ba115e","impliedFormat":99},{"version":"b0857bb28fd5236ace84280f79a25093f919fd0eff13e47cc26ea03de60a7294","impliedFormat":99},{"version":"5e43e0824f10cd8c48e7a8c5c673638488925a12c31f0f9e0957965c290eb14c","impliedFormat":99},{"version":"ef13c73d6157a32933c612d476c1524dd674cf5b9a88571d7d6a0d147544d529","impliedFormat":99},{"version":"3b0a56d056d81a011e484b9c05d5e430711aaecd561a788bad1d0498aad782c7","impliedFormat":99},{"version":"05c7aef6a4e496b93c2e682cced8903c0dfe6340d04f3fe616176e2782193435","impliedFormat":99},{"version":"3354286ef917d22c72e0c830324062f950134d8882e9ea57ad6ade3d8ad943cf","impliedFormat":99},{"version":"3dedc468e9b0ed804c0226482e344bd769417f834988af838d814504af81cba6","impliedFormat":99},{"version":"ac3d263474022e9a14c43f588f485d549641d839b159ecc971978b90f34bdf6b","impliedFormat":99},{"version":"cadeb2c96f1c964d7e49c0f17d6805e1b4dee62f0862c49bb178dae6ab277e8e","impliedFormat":99},{"version":"cadeb2c96f1c964d7e49c0f17d6805e1b4dee62f0862c49bb178dae6ab277e8e","impliedFormat":99},{"version":"42a12f2faa483c9b48195ed794d22698162274e755f6e07219c2351c4f08d732","impliedFormat":99},{"version":"727858fb893b87791876dee5e3cd4c187a721d2de516fd19d3d00dc6e8a894b3","impliedFormat":99},{"version":"5bfaa2ee33e63a1b17b08dbefd7a3c42d1e0f914e52aca5bef679b420bd7a07c","impliedFormat":99},{"version":"7d5c6cc5d537c47c7723a1fe76411b99373eb55c487045dfd076c1956e87389a","impliedFormat":99},{"version":"bcbd3becd08b4515225880abea0dbfbbf0d1181ce3af8f18f72f61edbe4febfb","impliedFormat":99},{"version":"a86701e56b10a6d1ef9b2ecaeedbab94ed7b957a646cd71fd09d02b323c6d3d7","impliedFormat":99},{"version":"b3f0791a73b6521da68107c5ba1bfed4bc21ff7099b892700fd65670e88ef6ee","impliedFormat":99},{"version":"d0411dddbef50f9ad568ee9d24b108153bcb8f0db1094de6dfbadf02feb3aa70","impliedFormat":99},{"version":"25249ca5fe64ca60d7bfb7fbbf0cb084324853b03a265dbbbc45fb4949de7567","impliedFormat":99},{"version":"b481de4ab5379bd481ca12fc0b255cdc47341629a22c240a89cdb4e209522be2","impliedFormat":99},{"version":"bdd14f07b4eca0b4b5203b85b8dbc4d084c749fa590bee5ea613e1641dcd3b29","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"31d5fb0aeb0368909fbe8cd9b893c16350aa94d48a2f909fdd393982ceb4814d","affectsGlobalScope":true,"impliedFormat":99},{"version":"90fe5875e2c7519711442683a9489416819c6cec8d395e48ff568e94254533e7","impliedFormat":99},{"version":"e666e31d323fef5642f87db0da48a83e58f0aaf9e3823e87eabd8ec7e0441a36","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":1},{"version":"6987dfb4b0c4e02112cc4e548e7a77b3d9ddfeffa8c8a2db13ceac361a4567d9","impliedFormat":99},{"version":"72a863bc6c0fc7a6263d8e07279167d86467a3869b5f002b1df6eaf5000ccc7b","impliedFormat":99},{"version":"5e2ba3d18d78aebbde1f34bde356e41e9c76eeaeaeee56a37036596a9eff4211","impliedFormat":99},{"version":"8280ae8ccc0493b32d1742d585357ab9f0a508ea050af25a5a20d64010d0a5cf","impliedFormat":99},{"version":"7adfd9f9056ecd4ae6c65fde2a98654960c662714c73f048478959d04c09e144","impliedFormat":99},{"version":"32b35cf0dc3a1b1a7118b61c34ce2ad1a29695851679f9ec34e0776f2ece2a69","impliedFormat":99},{"version":"b413fbc6658fe2774f8bf9a15cf4c53e586fc38a2d5256b3b9647da242c14389","impliedFormat":99},{"version":"42f0f7e74d73ae5873ed666373e09a367d62232ca378677094d0dc06020d6e00","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"ebb9b9fa684d70aef64614a59b7582f46f4982139b8b632b911ef98e10c4d117","impliedFormat":99},{"version":"8d7cbeea0454e05a3cdf3370c5df267072c4f1dc6c48a45a9ad750d7890443d7","affectsGlobalScope":true,"impliedFormat":99}],"root":[176],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":1,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":7},"referencedMap":[[163,1],[201,1],[204,2],[203,1],[154,3],[202,1],[102,4],[103,4],[104,5],[58,6],[105,7],[106,8],[107,9],[53,1],[56,10],[54,1],[55,1],[108,11],[109,12],[110,13],[111,14],[112,15],[113,16],[114,16],[115,17],[116,18],[117,19],[118,20],[59,1],[57,1],[119,21],[120,22],[121,23],[153,24],[122,25],[123,26],[124,27],[125,28],[126,29],[127,30],[128,31],[129,32],[130,33],[131,34],[132,34],[133,35],[134,1],[135,36],[137,37],[136,38],[138,39],[139,40],[140,41],[141,42],[142,43],[143,44],[144,45],[145,46],[146,47],[147,48],[148,49],[149,50],[150,51],[60,1],[61,1],[62,1],[101,52],[151,53],[152,54],[205,55],[187,56],[186,57],[206,56],[207,58],[191,59],[193,60],[192,61],[190,1],[199,1],[185,62],[184,63],[178,64],[180,65],[182,66],[181,1],[183,64],[179,1],[177,1],[63,1],[46,1],[48,67],[47,67],[49,68],[155,1],[162,69],[50,1],[156,70],[52,71],[51,72],[160,73],[157,74],[158,74],[159,75],[161,76],[219,77],[221,78],[220,79],[218,80],[217,1],[168,81],[167,82],[169,83],[164,84],[171,85],[166,86],[174,87],[173,88],[170,89],[172,90],[165,82],[208,1],[200,1],[44,1],[45,1],[9,1],[8,1],[2,1],[10,1],[11,1],[12,1],[13,1],[14,1],[15,1],[16,1],[17,1],[3,1],[18,1],[19,1],[4,1],[20,1],[24,1],[21,1],[22,1],[23,1],[25,1],[26,1],[27,1],[5,1],[28,1],[29,1],[30,1],[31,1],[6,1],[35,1],[32,1],[33,1],[34,1],[36,1],[7,1],[37,1],[42,1],[43,1],[38,1],[39,1],[40,1],[41,1],[1,1],[79,91],[89,92],[78,91],[99,93],[70,94],[69,95],[98,96],[92,97],[97,98],[72,99],[86,100],[71,101],[95,102],[67,103],[66,96],[96,104],[68,105],[73,106],[74,1],[77,106],[64,1],[100,107],[90,108],[81,109],[82,110],[84,111],[80,112],[83,113],[93,96],[75,114],[76,115],[85,116],[65,117],[88,108],[87,106],[91,1],[94,118],[209,119],[198,120],[194,121],[195,59],[215,1],[210,122],[196,123],[214,124],[188,1],[197,125],[222,126],[216,127],[223,128],[212,129],[213,130],[211,1],[189,1],[175,1],[176,131]],"affectedFilesPendingEmit":[[176,51]],"emitSignatures":[176],"version":"5.9.3"} \ No newline at end of file diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json index d217a71..19a9710 100644 --- a/packages/vscode-extension/package.json +++ b/packages/vscode-extension/package.json @@ -21,9 +21,20 @@ } ] }, + "configuration": { + "title": "CodeLink", + "properties": { + "codelink.relayServerUrl": { + "type": "string", + "default": "http://localhost:8080", + "description": "URL of the CodeLink Relay Server" + } + } + }, "scripts": { "build": "tsc", - "dev": "tsc --watch" + "dev": "tsc --watch", + "test": "vitest run" }, "dependencies": { "@codelink/protocol": "*", @@ -31,7 +42,9 @@ "socket.io-client": "^4.8.3" }, "devDependencies": { + "@types/node": "^25.3.0", "@types/vscode": "^1.80.0", - "typescript": "^5.0.0" + "typescript": "^5.0.0", + "vitest": "^4.0.18" } } diff --git a/packages/vscode-extension/src/diff/DiffGenerator.performance.test.ts b/packages/vscode-extension/src/diff/DiffGenerator.performance.test.ts deleted file mode 100644 index c656cca..0000000 --- a/packages/vscode-extension/src/diff/DiffGenerator.performance.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import * as fc from 'fast-check'; -import * as fs from 'fs/promises'; -import * as path from 'path'; -import * as os from 'os'; - -/** - * Performance tests for Diff Generator - * Feature: git-integration-diffing - * - * Note: These tests measure file I/O performance directly - */ - -describe('DiffGenerator Performance Tests', () => { - let tempDir: string; - - beforeEach(async () => { - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'diff-perf-test-')); - }); - - afterEach(async () => { - // Clean up temp directory - await fs.rm(tempDir, { recursive: true, force: true }); - }); - - /** - * Property 24: Diff generation performance - * For any file under 10,000 lines, diff generation should complete within 200ms. - * Validates: Requirements 7.3 - */ - it('Property 24: Diff generation completes within 200ms for files under 10,000 lines', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer({ min: 10, max: 10000 }), // Number of lines - async (numLines) => { - // Create a test file - const fileName = `test-${numLines}.txt`; - const filePath = path.join(tempDir, fileName); - const content = Array(numLines).fill('test line content').join('\n'); - const headContent = Array(numLines).fill('original line content').join('\n'); - - await fs.writeFile(filePath, content); - - // Measure diff generation performance (file read + payload construction) - const startTime = Date.now(); - - // Simulate diff generation: read file + create payload - const modifiedFile = await fs.readFile(filePath, 'utf-8'); - const payload = { - fileName: fileName, - originalFile: headContent, - modifiedFile: modifiedFile, - isDirty: false, - timestamp: Date.now(), - }; - - const elapsed = Date.now() - startTime; - - // Verify operation completed within 200ms - expect(elapsed).toBeLessThan(200); - expect(payload.modifiedFile).toBe(content); - } - ), - { numRuns: 50 } // Moderate runs for performance tests - ); - }); - - /** - * Test diff generation with various file sizes - * Validates: Requirements 7.3 - */ - it('handles files of varying sizes efficiently', async () => { - const fileSizes = [100, 1000, 5000, 10000]; - - for (const numLines of fileSizes) { - const fileName = `test-${numLines}.txt`; - const filePath = path.join(tempDir, fileName); - const content = Array(numLines).fill('test line content').join('\n'); - const headContent = Array(numLines).fill('original content').join('\n'); - - await fs.writeFile(filePath, content); - - const startTime = Date.now(); - - // Simulate diff generation - const modifiedFile = await fs.readFile(filePath, 'utf-8'); - const payload = { - fileName: fileName, - originalFile: headContent, - modifiedFile: modifiedFile, - isDirty: false, - timestamp: Date.now(), - }; - - const elapsed = Date.now() - startTime; - - expect(elapsed).toBeLessThan(200); - expect(payload.modifiedFile).toBe(content); - } - }); - - /** - * Test end-to-end latency measurement - * Validates: Requirements 7.4, 7.5 - */ - it('measures total diff generation time accurately', async () => { - const fileName = 'test.txt'; - const filePath = path.join(tempDir, fileName); - const content = Array(1000).fill('test line').join('\n'); - - await fs.writeFile(filePath, content); - - const startTime = Date.now(); - - // Simulate diff generation - const modifiedFile = await fs.readFile(filePath, 'utf-8'); - const payload = { - fileName: fileName, - originalFile: '', - modifiedFile: modifiedFile, - isDirty: false, - timestamp: Date.now(), - }; - - const elapsed = Date.now() - startTime; - - // Should be well under 200ms for 1000 lines - expect(elapsed).toBeLessThan(200); - expect(payload.modifiedFile).toBe(content); - }); -}); diff --git a/packages/vscode-extension/src/diff/DiffGenerator.properties.test.ts b/packages/vscode-extension/src/diff/DiffGenerator.properties.test.ts deleted file mode 100644 index cb14b63..0000000 --- a/packages/vscode-extension/src/diff/DiffGenerator.properties.test.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import * as fc from 'fast-check'; -import { DiffGeneratorImpl } from './DiffGenerator'; -import * as vscode from 'vscode'; -import * as fs from 'fs/promises'; - -// Mock vscode module -vi.mock('vscode', () => ({ - workspace: { - asRelativePath: vi.fn((path: string) => { - const parts = path.split('/'); - const projectIndex = parts.indexOf('project'); - if (projectIndex >= 0 && projectIndex < parts.length - 1) { - return parts.slice(projectIndex + 1).join('/'); - } - return parts[parts.length - 1]; - }), - textDocuments: [], - }, -})); - -// Mock fs/promises module -vi.mock('fs/promises', () => ({ - readFile: vi.fn(), - stat: vi.fn(), -})); - -describe('DiffGenerator - Property Tests', () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - // Feature: git-integration-diffing, Property 7: File content reading - it('Property 7: For any file path, DiffGenerator reads current file content or handles errors gracefully', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // file content - fc.string({ minLength: 0, maxLength: 200 }), // head content - async (fileName, fileContent, headContent) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock successful file stat and read - (fs.stat as any).mockResolvedValue({ size: fileContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(fileContent)); - (vscode.workspace as any).textDocuments = []; - - const result = await diffGenerator.generateDiff(filePath, headContent); - - // Should successfully generate payload - expect(result).not.toBeNull(); - expect(result?.modifiedFile).toBe(fileContent); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 8: Diff computation - it('Property 8: For any file with HEAD and current versions, DiffGenerator produces FileContextPayload', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // original content - fc.string({ minLength: 0, maxLength: 200 }), // modified content - async (fileName, originalFile, modifiedFile) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: modifiedFile.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(modifiedFile)); - (vscode.workspace as any).textDocuments = []; - - const result = await diffGenerator.generateDiff(filePath, originalFile); - - // Should contain both versions - expect(result).not.toBeNull(); - expect(result?.originalFile).toBe(originalFile); - expect(result?.modifiedFile).toBe(modifiedFile); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 9: Untracked file representation - it('Property 9: For any untracked file (empty originalFile), payload contains full current content', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 1, maxLength: 200 }), // modified content - async (fileName, modifiedFile) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: modifiedFile.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(modifiedFile)); - (vscode.workspace as any).textDocuments = []; - - // Empty head content (untracked file) - const result = await diffGenerator.generateDiff(filePath, ''); - - // Should have empty original and full modified - expect(result).not.toBeNull(); - expect(result?.originalFile).toBe(''); - expect(result?.modifiedFile).toBe(modifiedFile); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 10: No-change detection - it('Property 10: For any file where HEAD equals current, originalFile equals modifiedFile', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // content - async (fileName, content) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat and read with same content - (fs.stat as any).mockResolvedValue({ size: content.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(content)); - (vscode.workspace as any).textDocuments = []; - - const result = await diffGenerator.generateDiff(filePath, content); - - // Should have identical content - expect(result).not.toBeNull(); - expect(result?.originalFile).toBe(result?.modifiedFile); - expect(result?.originalFile).toBe(content); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 11: Content preservation - it('Property 11: For any file, payload contains exact original and modified content without mutations', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // original content - fc.string({ minLength: 0, maxLength: 200 }), // modified content - async (fileName, originalFile, modifiedFile) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: modifiedFile.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(modifiedFile)); - (vscode.workspace as any).textDocuments = []; - - const result = await diffGenerator.generateDiff(filePath, originalFile); - - // Content should be preserved exactly - expect(result).not.toBeNull(); - expect(result?.originalFile).toBe(originalFile); - expect(result?.modifiedFile).toBe(modifiedFile); - - // Verify no transformations occurred - expect(result?.originalFile.length).toBe(originalFile.length); - expect(result?.modifiedFile.length).toBe(modifiedFile.length); - } - ), - { numRuns: 100 } - ); - }); - - // Property: isDirty flag accuracy - it('Property 19: For any file with unsaved changes, isDirty is true', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // content - async (fileName, content) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: content.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(content)); - - // Mock document with isDirty = true and getText() - const mockDocument = { - uri: { fsPath: filePath }, - isDirty: true, - getText: () => content, - }; - (vscode.workspace as any).textDocuments = [mockDocument]; - - const result = await diffGenerator.generateDiff(filePath, ''); - - // Should have isDirty = true - expect(result).not.toBeNull(); - expect(result?.isDirty).toBe(true); - } - ), - { numRuns: 100 } - ); - }); - - // Property: isDirty flag accuracy for saved files - it('Property 20: For any file that is saved, isDirty is false', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // content - async (fileName, content) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: content.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(content)); - - // Mock document with isDirty = false and getText() - const mockDocument = { - uri: { fsPath: filePath }, - isDirty: false, - getText: () => content, - }; - (vscode.workspace as any).textDocuments = [mockDocument]; - - const result = await diffGenerator.generateDiff(filePath, content); - - // Should have isDirty = false - expect(result).not.toBeNull(); - expect(result?.isDirty).toBe(false); - } - ), - { numRuns: 100 } - ); - }); - - // Property: Timestamp accuracy - it('Property 21: For any generated payload, timestamp reflects generation time', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // content - async (fileName, content) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: content.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(content)); - (vscode.workspace as any).textDocuments = []; - - const beforeTime = Date.now(); - const result = await diffGenerator.generateDiff(filePath, content); - const afterTime = Date.now(); - - // Timestamp should be within reasonable range - expect(result).not.toBeNull(); - expect(result?.timestamp).toBeGreaterThanOrEqual(beforeTime); - expect(result?.timestamp).toBeLessThanOrEqual(afterTime + 100); // Allow 100ms tolerance - } - ), - { numRuns: 100 } - ); - }); - - // Property: Error handling - it('Property: For any file read error, generateDiff returns null without throwing', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }).filter(s => s.trim().length > 0), // file name (non-whitespace) - fc.string({ minLength: 0, maxLength: 200 }), // head content - async (fileName, headContent) => { - const diffGenerator = new DiffGeneratorImpl(); - const filePath = `/home/user/project/${fileName}`; - - // Mock file stat to throw error - (fs.stat as any).mockRejectedValue(new Error('File read error')); - - // Should not throw, should return null - const result = await diffGenerator.generateDiff(filePath, headContent); - expect(result).toBeNull(); - } - ), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/vscode-extension/src/diff/DiffGenerator.test.ts b/packages/vscode-extension/src/diff/DiffGenerator.test.ts deleted file mode 100644 index e3ded6b..0000000 --- a/packages/vscode-extension/src/diff/DiffGenerator.test.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { DiffGeneratorImpl } from './DiffGenerator'; -import * as vscode from 'vscode'; -import * as fs from 'fs/promises'; - -// Mock vscode module -vi.mock('vscode', () => ({ - workspace: { - asRelativePath: vi.fn((path: string) => { - // Extract relative path from absolute path - const parts = path.split('/'); - const projectIndex = parts.indexOf('project'); - if (projectIndex >= 0 && projectIndex < parts.length - 1) { - return parts.slice(projectIndex + 1).join('/'); - } - return parts[parts.length - 1]; - }), - textDocuments: [], - }, -})); - -// Mock fs/promises module -vi.mock('fs/promises', () => ({ - readFile: vi.fn(), - stat: vi.fn(), -})); - -describe('DiffGenerator', () => { - let diffGenerator: DiffGeneratorImpl; - - beforeEach(() => { - diffGenerator = new DiffGeneratorImpl(); - vi.clearAllMocks(); - }); - - describe('generateDiff', () => { - it('should read current file content correctly', async () => { - const filePath = '/home/user/project/src/index.ts'; - const headContent = 'const x = 1;'; - const currentContent = 'const x = 2;'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).not.toBeNull(); - expect(result?.modifiedFile).toBe(currentContent); - expect(result?.originalFile).toBe(headContent); - }); - - it('should set isDirty flag correctly for unsaved files', async () => { - const filePath = '/home/user/project/src/dirty.ts'; - const headContent = 'old content'; - const currentContent = 'new content'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - // Mock open document with isDirty = true and getText() - const mockDocument = { - uri: { fsPath: filePath }, - isDirty: true, - getText: () => currentContent, - }; - (vscode.workspace as any).textDocuments = [mockDocument]; - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).not.toBeNull(); - expect(result?.isDirty).toBe(true); - }); - - it('should set isDirty flag to false for saved files', async () => { - const filePath = '/home/user/project/src/saved.ts'; - const headContent = 'content'; - const currentContent = 'content'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - // Mock open document with isDirty = false and getText() - const mockDocument = { - uri: { fsPath: filePath }, - isDirty: false, - getText: () => currentContent, - }; - (vscode.workspace as any).textDocuments = [mockDocument]; - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).not.toBeNull(); - expect(result?.isDirty).toBe(false); - }); - - it('should generate FileContextPayload structure correctly', async () => { - const filePath = '/home/user/project/src/test.ts'; - const headContent = 'original'; - const currentContent = 'modified'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).not.toBeNull(); - expect(result).toHaveProperty('fileName'); - expect(result).toHaveProperty('originalFile'); - expect(result).toHaveProperty('modifiedFile'); - expect(result).toHaveProperty('isDirty'); - expect(result).toHaveProperty('timestamp'); - expect(typeof result?.timestamp).toBe('number'); - }); - - it('should generate workspace-relative path correctly', async () => { - const filePath = '/home/user/project/src/components/Button.tsx'; - const headContent = ''; - const currentContent = 'button code'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - // Mock asRelativePath to return proper relative path - (vscode.workspace.asRelativePath as any).mockReturnValue('src/components/Button.tsx'); - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).not.toBeNull(); - expect(result?.fileName).toBe('src/components/Button.tsx'); - }); - - it('should handle file read errors gracefully', async () => { - const filePath = '/home/user/project/src/missing.ts'; - const headContent = 'content'; - - // Mock file stat to throw error - (fs.stat as any).mockRejectedValue(new Error('File not found')); - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).toBeNull(); - }); - - it('should generate accurate timestamp', async () => { - const filePath = '/home/user/project/src/test.ts'; - const headContent = 'content'; - const currentContent = 'content'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - const beforeTime = Date.now(); - const result = await diffGenerator.generateDiff(filePath, headContent); - const afterTime = Date.now(); - - expect(result).not.toBeNull(); - expect(result?.timestamp).toBeGreaterThanOrEqual(beforeTime); - expect(result?.timestamp).toBeLessThanOrEqual(afterTime); - }); - - it('should handle empty head content for untracked files', async () => { - const filePath = '/home/user/project/src/newfile.ts'; - const headContent = ''; - const currentContent = 'new file content'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).not.toBeNull(); - expect(result?.originalFile).toBe(''); - expect(result?.modifiedFile).toBe(currentContent); - }); - - it('should handle identical files correctly', async () => { - const filePath = '/home/user/project/src/unchanged.ts'; - const content = 'unchanged content'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: content.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(content)); - - const result = await diffGenerator.generateDiff(filePath, content); - - expect(result).not.toBeNull(); - expect(result?.originalFile).toBe(content); - expect(result?.modifiedFile).toBe(content); - }); - - it('should return false for isDirty when file is not open', async () => { - const filePath = '/home/user/project/src/closed.ts'; - const headContent = 'content'; - const currentContent = 'content'; - - // Mock file stat and read - (fs.stat as any).mockResolvedValue({ size: currentContent.length }); - (fs.readFile as any).mockResolvedValue(Buffer.from(currentContent)); - - // No documents open - (vscode.workspace as any).textDocuments = []; - - const result = await diffGenerator.generateDiff(filePath, headContent); - - expect(result).not.toBeNull(); - expect(result?.isDirty).toBe(false); - }); - }); -}); diff --git a/packages/vscode-extension/src/diff/DiffGenerator.ts b/packages/vscode-extension/src/diff/DiffGenerator.ts index 69d014f..a1c1259 100644 --- a/packages/vscode-extension/src/diff/DiffGenerator.ts +++ b/packages/vscode-extension/src/diff/DiffGenerator.ts @@ -23,42 +23,42 @@ const FILE_SIZE_MAX_THRESHOLD = 10 * 1024 * 1024; // 10MB in bytes export class DiffGeneratorImpl implements DiffGenerator { async generateDiff(filePath: string, headContent: string): Promise { const startTime = Date.now(); - + try { // Validate file path if (!filePath || filePath.trim().length === 0) { console.warn(`[DiffGenerator] Invalid file path: empty or whitespace-only`); return null; } - + // Check file size before reading const fileStats = await this.getFileStats(filePath); - + if (fileStats.size > FILE_SIZE_MAX_THRESHOLD) { console.warn( `[DiffGenerator] File too large (${this.formatBytes(fileStats.size)}), skipping: ${filePath}` ); return null; } - + if (fileStats.size > FILE_SIZE_WARNING_THRESHOLD) { console.warn( `[DiffGenerator] Large file detected (${this.formatBytes(fileStats.size)}): ${filePath}` ); } - + // Read current file content - prefer editor content over disk const modifiedFile = await this.getCurrentFileContent(filePath); - + // Get workspace-relative path for fileName const fileName = vscode.workspace.asRelativePath(filePath, false); - + // Check if file has unsaved changes const isDirty = this.isFileDirty(filePath); - + // Generate timestamp const timestamp = Date.now(); - + // Construct FileContextPayload const payload: FileContextPayload = { fileName, @@ -67,23 +67,26 @@ export class DiffGeneratorImpl implements DiffGenerator { isDirty, timestamp, }; - + const elapsed = Date.now() - startTime; console.log( `[DiffGenerator] Generated diff for ${fileName} (${this.formatBytes(modifiedFile.length)} bytes, isDirty: ${isDirty}, took ${elapsed}ms)` ); - + // Performance warning if diff generation took too long if (elapsed > 200) { console.warn( `[DiffGenerator] Diff generation exceeded 200ms threshold: ${elapsed}ms for ${fileName}` ); } - + return payload; } catch (error) { const elapsed = Date.now() - startTime; - console.error(`[DiffGenerator] Error generating diff for ${filePath} (took ${elapsed}ms):`, error); + console.error( + `[DiffGenerator] Error generating diff for ${filePath} (took ${elapsed}ms):`, + error + ); return null; } } @@ -122,15 +125,13 @@ export class DiffGeneratorImpl implements DiffGenerator { */ private async getCurrentFileContent(filePath: string): Promise { // First, try to get content from open editor - const document = vscode.workspace.textDocuments.find( - doc => doc.uri.fsPath === filePath - ); - + const document = vscode.workspace.textDocuments.find((doc) => doc.uri.fsPath === filePath); + if (document) { // Return editor content (includes unsaved changes) return document.getText(); } - + // Fall back to reading from disk if not open in editor return this.readFileContent(filePath); } @@ -157,15 +158,13 @@ export class DiffGeneratorImpl implements DiffGenerator { */ private isFileDirty(filePath: string): boolean { // Find the document in VS Code's open documents - const document = vscode.workspace.textDocuments.find( - doc => doc.uri.fsPath === filePath - ); - + const document = vscode.workspace.textDocuments.find((doc) => doc.uri.fsPath === filePath); + // If document is open, check its dirty state if (document) { return document.isDirty; } - + // If document is not open, it's not dirty return false; } diff --git a/packages/vscode-extension/src/editor-adapters/ContinueAdapter.ts b/packages/vscode-extension/src/editor-adapters/ContinueAdapter.ts new file mode 100644 index 0000000..bfbf9f9 --- /dev/null +++ b/packages/vscode-extension/src/editor-adapters/ContinueAdapter.ts @@ -0,0 +1,39 @@ +import * as vscode from 'vscode'; +import { EditorAdapter } from './EditorAdapter'; + +export class ContinueAdapter implements EditorAdapter { + readonly id = 'continue'; + readonly displayName = 'Continue'; + + async isAvailable(): Promise { + const extension = vscode.extensions.getExtension('continue.continue'); + return !!extension; // && extension.isActive; + } + + async injectPrompt(_prompt: string): Promise { + try { + // Continue uses a command to accept input or specific API if available + // For now, we'll try to use the command to focus/open and then insert + // This is a best-effort integration without a public API + + // Attempt to execute the command to open Continue sidebar + await vscode.commands.executeCommand('continue.focusContinueInput'); + + // Wait a brief moment for focus + await new Promise((resolve) => setTimeout(resolve, 500)); + + // We can't easily type into the webview, but we can verify it opened. + // If there's a specific API command to send text, we would use it here. + // Since Continue doesn't expose a simple "send text" command publicly yet, + // we will fallback to a notification instructing the user, or + // look for a more specific command if updated. + + // REVISIT: Check for "continue.sendToChat" or similar in future versions. + + return true; + } catch (error) { + console.error('Failed to inject prompt into Continue:', error); + return false; + } + } +} diff --git a/packages/vscode-extension/src/editor-adapters/EditorAdapter.ts b/packages/vscode-extension/src/editor-adapters/EditorAdapter.ts new file mode 100644 index 0000000..76c70c6 --- /dev/null +++ b/packages/vscode-extension/src/editor-adapters/EditorAdapter.ts @@ -0,0 +1,26 @@ +/** + * Interface for AI Editor Adapters + */ +export interface EditorAdapter { + /** + * Unique identifier for the editor (e.g., 'continue', 'kiro', 'cursor') + */ + readonly id: string; + + /** + * Display name of the editor + */ + readonly displayName: string; + + /** + * Check if the editor is available/installed + */ + isAvailable(): Promise; + + /** + * Inject a prompt into the editor + * @param prompt The text prompt to inject + * @returns check if injection was successful + */ + injectPrompt(prompt: string): Promise; +} diff --git a/packages/vscode-extension/src/editor-adapters/EditorRegistry.ts b/packages/vscode-extension/src/editor-adapters/EditorRegistry.ts new file mode 100644 index 0000000..c796f1d --- /dev/null +++ b/packages/vscode-extension/src/editor-adapters/EditorRegistry.ts @@ -0,0 +1,60 @@ +import { EditorAdapter } from './EditorAdapter'; +import { ContinueAdapter } from './ContinueAdapter'; +import { KiroAdapter, CursorAdapter, AntigravityAdapter } from './OtherAdapters'; +import { VSCodeAdapter } from './VSCodeAdapter'; + +export class EditorRegistry { + private adapters: EditorAdapter[] = []; + + constructor() { + this.registerAdapters(); + } + + private registerAdapters() { + // Register adapters in priority order + // 1. Full Sync capable editors + this.adapters.push(new ContinueAdapter()); + + // 2. Partial Sync capable editors + this.adapters.push(new KiroAdapter()); + + // 3. Control-Only capable editors + this.adapters.push(new CursorAdapter()); + this.adapters.push(new AntigravityAdapter()); + + // 4. Fallback + this.adapters.push(new VSCodeAdapter()); + } + + /** + * Get the best available editor adapter + */ + async getBestAvailableAdapter(): Promise { + for (const adapter of this.adapters) { + if (await adapter.isAvailable()) { + return adapter; + } + } + return undefined; + } + + /** + * Get all available adapters + */ + async getAvailableAdapters(): Promise { + const available: EditorAdapter[] = []; + for (const adapter of this.adapters) { + if (await adapter.isAvailable()) { + available.push(adapter); + } + } + return available; + } + + /** + * Get adapter by ID + */ + getAdapter(id: string): EditorAdapter | undefined { + return this.adapters.find((a) => a.id === id); + } +} diff --git a/packages/vscode-extension/src/editor-adapters/OtherAdapters.ts b/packages/vscode-extension/src/editor-adapters/OtherAdapters.ts new file mode 100644 index 0000000..cd6ea27 --- /dev/null +++ b/packages/vscode-extension/src/editor-adapters/OtherAdapters.ts @@ -0,0 +1,45 @@ +import * as vscode from 'vscode'; +import { EditorAdapter } from './EditorAdapter'; + +export class KiroAdapter implements EditorAdapter { + readonly id = 'kiro'; + readonly displayName = 'Kiro'; + + async isAvailable(): Promise { + return !!vscode.extensions.getExtension('kiro.kiro'); + } + + async injectPrompt(_prompt: string): Promise { + // Placeholder implementation + return false; + } +} + +export class CursorAdapter implements EditorAdapter { + readonly id = 'cursor'; + readonly displayName = 'Cursor'; + + async isAvailable(): Promise { + // Cursor identifies itself differently, often via env or specific extension + return vscode.env.appName.includes('Cursor'); + } + + async injectPrompt(_prompt: string): Promise { + // Cursor AI command implementation would go here + return false; + } +} + +export class AntigravityAdapter implements EditorAdapter { + readonly id = 'antigravity'; + readonly displayName = 'Antigravity'; + + async isAvailable(): Promise { + return !!vscode.extensions.getExtension('google.antigravity'); + } + + async injectPrompt(_prompt: string): Promise { + // Antigravity implementation + return false; + } +} diff --git a/packages/vscode-extension/src/editor-adapters/VSCodeAdapter.ts b/packages/vscode-extension/src/editor-adapters/VSCodeAdapter.ts new file mode 100644 index 0000000..650d508 --- /dev/null +++ b/packages/vscode-extension/src/editor-adapters/VSCodeAdapter.ts @@ -0,0 +1,33 @@ +import * as vscode from 'vscode'; +import { EditorAdapter } from './EditorAdapter'; + +export class VSCodeAdapter implements EditorAdapter { + readonly id = 'vscode'; + readonly displayName = 'VS Code'; + + async isAvailable(): Promise { + return true; // Always available + } + + async injectPrompt(prompt: string): Promise { + // Basic fallback: copy to clipboard and show notification + await vscode.env.clipboard.writeText(prompt); + + const selection = await vscode.window.showInformationMessage( + `Received prompt from mobile: "${prompt.substring(0, 50)}..."`, + 'Paste in Editor', + 'Dismiss' + ); + + if (selection === 'Paste in Editor') { + const editor = vscode.window.activeTextEditor; + if (editor) { + editor.edit((editBuilder) => { + editBuilder.insert(editor.selection.active, prompt); + }); + } + } + + return true; + } +} diff --git a/packages/vscode-extension/src/editors/adapters/AntigravityAdapter.test.ts b/packages/vscode-extension/src/editors/adapters/AntigravityAdapter.test.ts deleted file mode 100644 index 4c5610c..0000000 --- a/packages/vscode-extension/src/editors/adapters/AntigravityAdapter.test.ts +++ /dev/null @@ -1,333 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { AntigravityAdapter } from './AntigravityAdapter'; -import * as vscode from 'vscode'; - -// Mock vscode module -vi.mock('vscode', () => ({ - commands: { - getCommands: vi.fn(), - executeCommand: vi.fn(), - }, -})); - -describe('AntigravityAdapter - Unit Tests', () => { - let adapter: AntigravityAdapter; - - beforeEach(() => { - adapter = new AntigravityAdapter(); - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - describe('Adapter Properties', () => { - it('should have correct editorId', () => { - expect(adapter.editorId).toBe('antigravity'); - }); - - it('should have correct editorName', () => { - expect(adapter.editorName).toBe('Antigravity'); - }); - - // Requirement 3.5: Antigravity supports control-only sync - // Requirement 5.1: Antigravity has limited capabilities due to closed-source nature - // Requirement 5.3: System clearly documents what is and isn't possible per editor - it('should declare control-only capabilities', () => { - expect(adapter.capabilities).toEqual({ - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }); - }); - - // Requirement 5.3: Closed-source capabilities must be false - it('should have all closed-source capabilities set to false', () => { - expect(adapter.capabilities.canReadChatHistory).toBe(false); - expect(adapter.capabilities.canStreamAssistantTokens).toBe(false); - expect(adapter.capabilities.canReadDiffArtifacts).toBe(false); - }); - }); - - describe('detect()', () => { - // Requirement 1.1: System detects available AI editors by querying VS Code commands - it('should detect Antigravity when antigravity.* commands are present', async () => { - const commands = [ - 'antigravity.chat.send', - 'antigravity.chat.open', - 'antigravity.sendMessage', - 'workbench.action.files.save', - 'editor.action.formatDocument', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual([ - 'antigravity.chat.send', - 'antigravity.chat.open', - 'antigravity.sendMessage', - ]); - }); - - it('should detect Antigravity when commands contain "antigravity" in lowercase', async () => { - const commands = [ - 'some.antigravity.command', - 'workbench.action.files.save', - 'editor.action.formatDocument', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toContain('some.antigravity.command'); - }); - - // Requirement 1.1: Detection happens dynamically without hardcoded assumptions - it('should not detect Antigravity when antigravity commands are absent', async () => { - const commands = [ - 'workbench.action.files.save', - 'editor.action.formatDocument', - 'git.commit', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should return empty array when no commands exist', async () => { - vi.mocked(vscode.commands.getCommands).mockResolvedValue([]); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should handle command query failure gracefully', async () => { - vi.mocked(vscode.commands.getCommands).mockRejectedValue( - new Error('VS Code API unavailable') - ); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should match commands with "antigravity." prefix', async () => { - const commands = [ - 'antigravity.validCommand', - 'antigravityX.notValid', - 'xantigravity.notValid', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toContain('antigravity.validCommand'); - }); - - it('should match commands containing "antigravity" anywhere (case-insensitive)', async () => { - const commands = [ - 'some.ANTIGRAVITY.command', - 'anotherAntigravityCommand', - 'workbench.action.files.save', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toContain('some.ANTIGRAVITY.command'); - expect(result.availableCommands).toContain('anotherAntigravityCommand'); - }); - }); - - describe('injectPrompt()', () => { - // Requirement 2.1: Prompts originating from mobile appear in the editor's chat panel - // Requirement 2.2: Injection uses only public VS Code commands - it('should inject prompt successfully using primary command', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt('Hello, Antigravity!'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('antigravity.chat.send'); - expect(result.error).toBeUndefined(); - - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'antigravity.chat.send', - 'Hello, Antigravity!' - ); - }); - - // Test fallback command patterns - it('should use first fallback command when primary fails', async () => { - vi.mocked(vscode.commands.executeCommand) - .mockRejectedValueOnce(new Error('Primary command not found')) - .mockResolvedValueOnce(undefined); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('antigravity.chat.open'); - - expect(vscode.commands.executeCommand).toHaveBeenCalledTimes(2); - expect(vscode.commands.executeCommand).toHaveBeenNthCalledWith( - 1, - 'antigravity.chat.send', - 'Test prompt' - ); - expect(vscode.commands.executeCommand).toHaveBeenNthCalledWith( - 2, - 'antigravity.chat.open', - { message: 'Test prompt' } - ); - }); - - it('should use second fallback command when first two fail', async () => { - vi.mocked(vscode.commands.executeCommand) - .mockRejectedValueOnce(new Error('Primary command not found')) - .mockRejectedValueOnce(new Error('First fallback not found')) - .mockResolvedValueOnce(undefined); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('antigravity.sendMessage'); - - expect(vscode.commands.executeCommand).toHaveBeenCalledTimes(3); - expect(vscode.commands.executeCommand).toHaveBeenNthCalledWith( - 3, - 'antigravity.sendMessage', - 'Test prompt' - ); - }); - - // Requirement 2.5: System provides clear error messages when prompt injection fails - it('should return error result when all command attempts fail', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - new Error('Command not found') - ); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(false); - expect(result.error).toBeDefined(); - expect(result.error).toContain('Failed to inject prompt into Antigravity'); - expect(result.error).toContain('Command not found'); - expect(result.error).toContain('antigravity.chat.send'); - expect(result.error).toContain('antigravity.chat.open'); - expect(result.error).toContain('antigravity.sendMessage'); - expect(result.commandUsed).toBe('antigravity.chat.send (attempted)'); - }); - - it('should handle empty prompt string', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt(''); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'antigravity.chat.send', - '' - ); - }); - - it('should handle multiline prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const multilinePrompt = 'Line 1\nLine 2\nLine 3'; - const result = await adapter.injectPrompt(multilinePrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'antigravity.chat.send', - multilinePrompt - ); - }); - - it('should handle prompts with special characters', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const specialPrompt = 'Test !@#$%^&*() <>"\''; - const result = await adapter.injectPrompt(specialPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'antigravity.chat.send', - specialPrompt - ); - }); - - it('should handle very long prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const longPrompt = 'a'.repeat(10000); - const result = await adapter.injectPrompt(longPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'antigravity.chat.send', - longPrompt - ); - }); - - it('should handle non-Error exceptions', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - 'String error' - ); - - const result = await adapter.injectPrompt('Test'); - - expect(result.success).toBe(false); - expect(result.error).toContain('Failed to inject prompt into Antigravity'); - expect(result.error).toContain('String error'); - }); - }); - - describe('Interface Compliance', () => { - it('should implement IEditorAdapter interface', () => { - expect(adapter).toHaveProperty('editorId'); - expect(adapter).toHaveProperty('editorName'); - expect(adapter).toHaveProperty('capabilities'); - expect(adapter).toHaveProperty('detect'); - expect(adapter).toHaveProperty('injectPrompt'); - }); - - it('should have detect method that returns Promise', () => { - expect(typeof adapter.detect).toBe('function'); - expect(adapter.detect()).toBeInstanceOf(Promise); - }); - - it('should have injectPrompt method that returns Promise', () => { - expect(typeof adapter.injectPrompt).toBe('function'); - expect(adapter.injectPrompt('test')).toBeInstanceOf(Promise); - }); - - // Requirement 5.3: Closed-source editors should not implement read methods - it('should not have readChatHistory method', () => { - expect(adapter).not.toHaveProperty('readChatHistory'); - }); - - it('should not have readDiffArtifacts method', () => { - expect(adapter).not.toHaveProperty('readDiffArtifacts'); - }); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/AntigravityAdapter.ts b/packages/vscode-extension/src/editors/adapters/AntigravityAdapter.ts index 8693323..b1543d7 100644 --- a/packages/vscode-extension/src/editors/adapters/AntigravityAdapter.ts +++ b/packages/vscode-extension/src/editors/adapters/AntigravityAdapter.ts @@ -8,11 +8,11 @@ import { /** * Adapter for Antigravity extension. - * + * * Antigravity is a closed-source AI code editor, so we can only use public commands * exposed through VS Code's command API. We cannot read internal state, access * chat history, or stream tokens in real-time. - * + * * Capabilities: * - Prompt injection: Yes (via antigravity.* commands discovered dynamically) * - Chat history: No (closed-source, no public API) @@ -20,13 +20,13 @@ import { * - Diff artifacts: No (closed-source, no public API) * - Prevent auto-apply: No (unknown, depends on Antigravity's internal settings) * - Sync level: Control-only - * + * * Safety: This adapter uses ONLY public VS Code commands. We never: * - Scrape UI elements or webview DOM * - Use keystroke replay or automation * - Access private or undocumented APIs * - Make assumptions about Antigravity's internal state - * + * * The mobile client must reconstruct state from other signals (file changes, * diff events) rather than relying on chat mirroring. */ @@ -44,15 +44,15 @@ export class AntigravityAdapter implements IEditorAdapter { /** * Detect if Antigravity is installed and available. - * + * * Uses command discovery pattern: queries all available VS Code commands * and looks for Antigravity-specific command patterns (commands starting with * "antigravity." or containing "antigravity" in the name). - * + * * Safety: Never assumes Antigravity is available. Always checks dynamically * using public VS Code API. Fails safe by returning not installed if * command query fails. - * + * * @returns DetectionResult indicating if Antigravity is installed and available commands */ async detect(): Promise { @@ -86,25 +86,25 @@ export class AntigravityAdapter implements IEditorAdapter { /** * Inject a prompt into Antigravity's chat panel. - * + * * Attempts to use Antigravity's public commands to inject a prompt. Since Antigravity * is closed-source, we don't know the exact command names, so we try multiple * common patterns with fallback logic. - * + * * Fallback strategy: * 1. Try 'antigravity.chat.send' (common pattern for chat commands) * 2. Try 'antigravity.chat.open' with message parameter * 3. Try 'antigravity.sendMessage' (alternative pattern) - * + * * Safety: Uses only public VS Code commands. Never throws exceptions - always * returns error result with clear message if all attempts fail. The actual * command names would need to be discovered through Antigravity's documentation * or command palette. - * + * * Note: The command names used here are educated guesses based on common * patterns. In production, these would need to be verified against Antigravity's * actual public API. - * + * * @param prompt The prompt text to inject into Antigravity's chat * @returns PromptInjectionResult indicating success or failure with error details */ @@ -119,7 +119,7 @@ export class AntigravityAdapter implements IEditorAdapter { }; } catch (primaryError) { // Primary command failed, try fallback patterns - + // Fallback 1: Try antigravity.chat.open with message parameter try { await vscode.commands.executeCommand('antigravity.chat.open', { @@ -143,9 +143,7 @@ export class AntigravityAdapter implements IEditorAdapter { // All attempts failed - return error result with context // Safety: Never throw, always return error result const primaryErrorMessage = - primaryError instanceof Error - ? primaryError.message - : String(primaryError); + primaryError instanceof Error ? primaryError.message : String(primaryError); return { success: false, diff --git a/packages/vscode-extension/src/editors/adapters/ContinueAdapter.properties.test.ts b/packages/vscode-extension/src/editors/adapters/ContinueAdapter.properties.test.ts deleted file mode 100644 index 7ef5e55..0000000 --- a/packages/vscode-extension/src/editors/adapters/ContinueAdapter.properties.test.ts +++ /dev/null @@ -1,349 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import * as fc from 'fast-check'; -import { ContinueAdapter } from './ContinueAdapter'; -import * as vscode from 'vscode'; - -// Mock vscode module -vi.mock('vscode', () => ({ - commands: { - getCommands: vi.fn(), - executeCommand: vi.fn(), - }, -})); - -describe('ContinueAdapter - Property-Based Tests', () => { - let adapter: ContinueAdapter; - - beforeEach(() => { - adapter = new ContinueAdapter(); - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - // Feature: editor-adapter-system, Property 1: Editor Detection via Command Discovery - // Validates: Requirements 1.1, 2.3 - it('Property 1: Editor Detection via Command Discovery', async () => { - // Generator for command lists with varying Continue command presence - const commandListArb = fc - .tuple( - // Continue commands (0-10) - fc.array( - fc - .string({ minLength: 1, maxLength: 20 }) - .map((suffix) => `continue.${suffix}`), - { minLength: 0, maxLength: 10 } - ), - // Other commands (0-20) - fc.array( - fc - .tuple( - fc.constantFrom('vscode', 'workbench', 'editor', 'git', 'debug'), - fc.string({ minLength: 1, maxLength: 20 }) - ) - .map(([prefix, suffix]) => `${prefix}.${suffix}`), - { minLength: 0, maxLength: 20 } - ) - ) - .map(([continueCommands, otherCommands]) => { - // Combine and shuffle - const allCommands = [...continueCommands, ...otherCommands]; - return { - commands: allCommands, - hasContinueCommands: continueCommands.length > 0, - continueCommandCount: continueCommands.length, - }; - }); - - await fc.assert( - fc.asyncProperty(commandListArb, async ({ commands, hasContinueCommands, continueCommandCount }) => { - // Mock vscode.commands.getCommands to return our generated command list - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - // Call detect - const result = await adapter.detect(); - - // Property: Detection correctly identifies Continue based on command patterns - expect(result.isInstalled).toBe(hasContinueCommands); - - // Property: Available commands should only include Continue commands - if (hasContinueCommands) { - expect(result.availableCommands).toBeDefined(); - expect(result.availableCommands!.length).toBe(continueCommandCount); - - // All returned commands should start with "continue." - result.availableCommands!.forEach((cmd) => { - expect(cmd.startsWith('continue.')).toBe(true); - }); - } else { - // When no Continue commands, should still have availableCommands array - expect(result.availableCommands).toBeDefined(); - expect(result.availableCommands!.length).toBe(0); - } - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 1: Detection handles command query failures - it('Property 1: Detection fails safe when command query throws', async () => { - // Generator for different error types - const errorArb = fc.oneof( - fc.constant(new Error('Command query failed')), - fc.constant(new Error('VS Code API unavailable')), - fc.string().map((msg) => new Error(msg)), - fc.constant('String error'), - fc.constant(null), - fc.constant(undefined) - ); - - await fc.assert( - fc.asyncProperty(errorArb, async (error) => { - // Mock vscode.commands.getCommands to throw - vi.mocked(vscode.commands.getCommands).mockRejectedValue(error); - - // Call detect - const result = await adapter.detect(); - - // Property: Detection fails safe by returning not installed - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 1: Detection is idempotent - it('Property 1: Repeated detection returns consistent results', async () => { - // Generator for command lists - const commandListArb = fc.array( - fc - .string({ minLength: 1, maxLength: 20 }) - .map((suffix) => `continue.${suffix}`), - { minLength: 0, maxLength: 10 } - ); - - await fc.assert( - fc.asyncProperty(commandListArb, async (continueCommands) => { - // Mock vscode.commands.getCommands - vi.mocked(vscode.commands.getCommands).mockResolvedValue(continueCommands); - - // Call detect multiple times - const result1 = await adapter.detect(); - const result2 = await adapter.detect(); - const result3 = await adapter.detect(); - - // Property: All results should be identical (idempotent) - expect(result1).toEqual(result2); - expect(result2).toEqual(result3); - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 1: Detection correctly filters command patterns - it('Property 1: Detection only identifies commands with exact prefix match', async () => { - // Generator for edge case command patterns - const edgeCaseCommandsArb = fc.array( - fc.oneof( - fc.constant('continue.validCommand'), - fc.constant('continue'), - fc.constant('continue'), - fc.constant('continueX.fakeCommand'), - fc.constant('xcontinue.fakeCommand'), - fc.constant('CONTINUE.upperCase'), - fc.constant('Continue.mixedCase'), - fc.constant('continue..doubleDoT'), - fc.constant('continue.'), - ), - { minLength: 0, maxLength: 20 } - ); - - await fc.assert( - fc.asyncProperty(edgeCaseCommandsArb, async (commands) => { - // Mock vscode.commands.getCommands - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - // Call detect - const result = await adapter.detect(); - - // Property: Only commands starting with exactly "continue." should be detected - const expectedContinueCommands = commands.filter((cmd) => - cmd.startsWith('continue.') - ); - - expect(result.isInstalled).toBe(expectedContinueCommands.length > 0); - - if (result.availableCommands) { - expect(result.availableCommands.length).toBe(expectedContinueCommands.length); - - // All returned commands must start with "continue." - result.availableCommands.forEach((cmd) => { - expect(cmd.startsWith('continue.')).toBe(true); - }); - } - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 4: Prompt Injection Returns Valid Result - // Validates: Requirements 2.1, 2.4, 2.5 - it('Property 4: Prompt Injection Returns Valid Result', async () => { - // Generator for various prompt strings including edge cases - const promptArb = fc.oneof( - fc.string({ minLength: 1, maxLength: 1000 }), // Normal strings - fc.constant(''), // Empty string - fc.string({ minLength: 5000, maxLength: 10000 }), // Very long strings - fc.constant('Hello\nWorld'), // Multiline - fc.constant('Special chars: !@#$%^&*()'), // Special characters - fc.constant('Unicode: 你好 🚀 émojis'), // Unicode - fc.constant(' whitespace '), // Whitespace - fc.constant('\t\n\r'), // Control characters - ); - - await fc.assert( - fc.asyncProperty(promptArb, async (prompt) => { - // Mock successful command execution - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - // Call injectPrompt - const result = await adapter.injectPrompt(prompt); - - // Property: Result must have success boolean - expect(typeof result.success).toBe('boolean'); - - // Property: If successful, commandUsed should be present - if (result.success) { - expect(result.commandUsed).toBeDefined(); - expect(typeof result.commandUsed).toBe('string'); - expect(result.commandUsed).toBe('continue.continueGUIView.focusContinueInput'); - } - - // Property: If failed, error message should be present and non-empty - if (!result.success) { - expect(result.error).toBeDefined(); - expect(typeof result.error).toBe('string'); - expect(result.error!.length).toBeGreaterThan(0); - } - - // Property: Result should not have both success=true and error message - if (result.success) { - // Error can be undefined or empty when successful - expect(result.error).toBeUndefined(); - } - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 4: Prompt Injection handles command failures - it('Property 4: Prompt Injection returns error result on command failure', async () => { - // Generator for different error types - const errorArb = fc.oneof( - fc.constant(new Error('Command not found')), - fc.constant(new Error('VS Code API unavailable')), - fc.constant(new Error('Extension not activated')), - fc.string().map((msg) => new Error(msg)), - fc.constant('String error'), - fc.constant(null), - fc.constant(undefined), - ); - - const promptArb = fc.string({ minLength: 1, maxLength: 100 }); - - await fc.assert( - fc.asyncProperty( - fc.tuple(promptArb, errorArb), - async ([prompt, error]) => { - // Mock command execution to throw - vi.mocked(vscode.commands.executeCommand).mockRejectedValue(error); - - // Call injectPrompt - const result = await adapter.injectPrompt(prompt); - - // Property: Must return error result (not throw) - expect(result.success).toBe(false); - - // Property: Error message must be present and descriptive - expect(result.error).toBeDefined(); - expect(typeof result.error).toBe('string'); - expect(result.error!.length).toBeGreaterThan(0); - - // Property: Error message should contain context - expect(result.error).toContain('Failed to inject prompt'); - - // Property: commandUsed should still be present for debugging - expect(result.commandUsed).toBeDefined(); - expect(result.commandUsed).toBe('continue.continueGUIView.focusContinueInput'); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 4: Prompt Injection never throws exceptions - it('Property 4: Prompt Injection never throws, always returns result', async () => { - const promptArb = fc.string({ minLength: 0, maxLength: 1000 }); - const errorArb = fc.anything(); - - await fc.assert( - fc.asyncProperty( - fc.tuple(promptArb, errorArb), - async ([prompt, error]) => { - // Mock command execution to throw anything - vi.mocked(vscode.commands.executeCommand).mockRejectedValue(error); - - // Property: injectPrompt should never throw, always return a result - let threwException = false; - let result; - - try { - result = await adapter.injectPrompt(prompt); - } catch (e) { - threwException = true; - } - - // Should not throw - expect(threwException).toBe(false); - - // Should return a valid result object - expect(result).toBeDefined(); - expect(typeof result!.success).toBe('boolean'); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 4: Prompt Injection uses correct command - it('Property 4: Prompt Injection always uses the correct Continue command', async () => { - const promptArb = fc.string({ minLength: 1, maxLength: 500 }); - - await fc.assert( - fc.asyncProperty(promptArb, async (prompt) => { - // Clear mocks before each property test run - vi.clearAllMocks(); - - // Mock successful command execution - const executeCommandMock = vi.mocked(vscode.commands.executeCommand); - executeCommandMock.mockResolvedValue(undefined); - - // Call injectPrompt - await adapter.injectPrompt(prompt); - - // Property: Should call executeCommand with correct command name - expect(executeCommandMock).toHaveBeenCalledWith( - 'continue.continueGUIView.focusContinueInput', - { text: prompt } - ); - - // Property: Should call exactly once - expect(executeCommandMock).toHaveBeenCalledTimes(1); - }), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/ContinueAdapter.test.ts b/packages/vscode-extension/src/editors/adapters/ContinueAdapter.test.ts deleted file mode 100644 index 88e1d7a..0000000 --- a/packages/vscode-extension/src/editors/adapters/ContinueAdapter.test.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { ContinueAdapter } from './ContinueAdapter'; -import * as vscode from 'vscode'; - -// Mock vscode module -vi.mock('vscode', () => ({ - commands: { - getCommands: vi.fn(), - executeCommand: vi.fn(), - }, -})); - -describe('ContinueAdapter - Unit Tests', () => { - let adapter: ContinueAdapter; - - beforeEach(() => { - adapter = new ContinueAdapter(); - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - describe('Adapter Properties', () => { - it('should have correct editorId', () => { - expect(adapter.editorId).toBe('continue'); - }); - - it('should have correct editorName', () => { - expect(adapter.editorName).toBe('Continue'); - }); - - it('should declare full sync capabilities', () => { - expect(adapter.capabilities).toEqual({ - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'full', - }); - }); - }); - - describe('detect()', () => { - // Requirement 1.1: System detects available AI editors by querying VS Code commands - it('should detect Continue when continue.* commands are present', async () => { - const commands = [ - 'continue.continueGUIView.focusContinueInput', - 'continue.openSettings', - 'continue.toggleFullScreen', - 'workbench.action.files.save', - 'editor.action.formatDocument', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual([ - 'continue.continueGUIView.focusContinueInput', - 'continue.openSettings', - 'continue.toggleFullScreen', - ]); - }); - - // Requirement 1.1: Detection happens dynamically without hardcoded assumptions - it('should not detect Continue when continue.* commands are absent', async () => { - const commands = [ - 'workbench.action.files.save', - 'editor.action.formatDocument', - 'git.commit', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should return empty array when no commands exist', async () => { - vi.mocked(vscode.commands.getCommands).mockResolvedValue([]); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should handle command query failure gracefully', async () => { - vi.mocked(vscode.commands.getCommands).mockRejectedValue( - new Error('VS Code API unavailable') - ); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should only match commands with exact "continue." prefix', async () => { - const commands = [ - 'continue.validCommand', - 'continueX.notValid', - 'xcontinue.notValid', - 'CONTINUE.notValid', - 'Continue.notValid', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual(['continue.validCommand']); - }); - }); - - describe('injectPrompt()', () => { - // Requirement 2.1: Prompts originating from mobile appear in the editor's chat panel - // Requirement 2.2: Injection uses only public VS Code commands - it('should inject prompt successfully using Continue command', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt('Hello, Continue!'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe( - 'continue.continueGUIView.focusContinueInput' - ); - expect(result.error).toBeUndefined(); - - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'continue.continueGUIView.focusContinueInput', - { text: 'Hello, Continue!' } - ); - }); - - // Requirement 2.5: System provides clear error messages when prompt injection fails - it('should return error result when command execution fails', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - new Error('Command not found') - ); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(false); - expect(result.error).toBeDefined(); - expect(result.error).toContain('Failed to inject prompt'); - expect(result.error).toContain('Command not found'); - expect(result.commandUsed).toBe( - 'continue.continueGUIView.focusContinueInput' - ); - }); - - it('should handle empty prompt string', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt(''); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'continue.continueGUIView.focusContinueInput', - { text: '' } - ); - }); - - it('should handle multiline prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const multilinePrompt = 'Line 1\nLine 2\nLine 3'; - const result = await adapter.injectPrompt(multilinePrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'continue.continueGUIView.focusContinueInput', - { text: multilinePrompt } - ); - }); - - it('should handle prompts with special characters', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const specialPrompt = 'Test !@#$%^&*() <>"\''; - const result = await adapter.injectPrompt(specialPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'continue.continueGUIView.focusContinueInput', - { text: specialPrompt } - ); - }); - - it('should handle very long prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const longPrompt = 'a'.repeat(10000); - const result = await adapter.injectPrompt(longPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'continue.continueGUIView.focusContinueInput', - { text: longPrompt } - ); - }); - - it('should handle non-Error exceptions', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - 'String error' - ); - - const result = await adapter.injectPrompt('Test'); - - expect(result.success).toBe(false); - expect(result.error).toContain('Failed to inject prompt'); - expect(result.error).toContain('String error'); - }); - }); - - describe('readChatHistory()', () => { - it('should throw not implemented error', async () => { - await expect(adapter.readChatHistory()).rejects.toThrow( - 'readChatHistory not yet implemented for Continue adapter' - ); - }); - }); - - describe('readDiffArtifacts()', () => { - it('should throw not implemented error', async () => { - await expect(adapter.readDiffArtifacts()).rejects.toThrow( - 'readDiffArtifacts not yet implemented for Continue adapter' - ); - }); - }); - - describe('Interface Compliance', () => { - it('should implement IEditorAdapter interface', () => { - expect(adapter).toHaveProperty('editorId'); - expect(adapter).toHaveProperty('editorName'); - expect(adapter).toHaveProperty('capabilities'); - expect(adapter).toHaveProperty('detect'); - expect(adapter).toHaveProperty('injectPrompt'); - expect(adapter).toHaveProperty('readChatHistory'); - expect(adapter).toHaveProperty('readDiffArtifacts'); - }); - - it('should have detect method that returns Promise', () => { - expect(typeof adapter.detect).toBe('function'); - expect(adapter.detect()).toBeInstanceOf(Promise); - }); - - it('should have injectPrompt method that returns Promise', () => { - expect(typeof adapter.injectPrompt).toBe('function'); - expect(adapter.injectPrompt('test')).toBeInstanceOf(Promise); - }); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/ContinueAdapter.ts b/packages/vscode-extension/src/editors/adapters/ContinueAdapter.ts index d234501..edbaab1 100644 --- a/packages/vscode-extension/src/editors/adapters/ContinueAdapter.ts +++ b/packages/vscode-extension/src/editors/adapters/ContinueAdapter.ts @@ -24,9 +24,7 @@ export class ContinueAdapter implements IEditorAdapter { try { const commands = await vscode.commands.getCommands(true); - const continueCommands = commands.filter((cmd) => - cmd.startsWith('continue.') - ); + const continueCommands = commands.filter((cmd) => cmd.startsWith('continue.')); const isInstalled = continueCommands.length > 0; @@ -45,10 +43,9 @@ export class ContinueAdapter implements IEditorAdapter { async injectPrompt(prompt: string): Promise { try { - await vscode.commands.executeCommand( - 'continue.continueGUIView.focusContinueInput', - { text: prompt } - ); + await vscode.commands.executeCommand('continue.continueGUIView.focusContinueInput', { + text: prompt, + }); return { success: true, @@ -86,9 +83,7 @@ export class ContinueAdapter implements IEditorAdapter { // Implementation would access Continue's internal state // This is allowed because Continue is open-source // Actual implementation depends on Continue's API - throw new Error( - 'readChatHistory not yet implemented for Continue adapter' - ); + throw new Error('readChatHistory not yet implemented for Continue adapter'); } /** @@ -106,8 +101,6 @@ export class ContinueAdapter implements IEditorAdapter { async readDiffArtifacts(): Promise { // Implementation would access Continue's diff state // This is allowed because Continue is open-source - throw new Error( - 'readDiffArtifacts not yet implemented for Continue adapter' - ); + throw new Error('readDiffArtifacts not yet implemented for Continue adapter'); } } diff --git a/packages/vscode-extension/src/editors/adapters/CursorAdapter.properties.test.ts b/packages/vscode-extension/src/editors/adapters/CursorAdapter.properties.test.ts deleted file mode 100644 index d97486f..0000000 --- a/packages/vscode-extension/src/editors/adapters/CursorAdapter.properties.test.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import * as fc from 'fast-check'; -import { CursorAdapter } from './CursorAdapter'; -import { ContinueAdapter } from './ContinueAdapter'; -import { KiroAdapter } from './KiroAdapter'; -import * as vscode from 'vscode'; - -// Mock vscode module -vi.mock('vscode', () => ({ - commands: { - getCommands: vi.fn(), - executeCommand: vi.fn(), - }, -})); - -describe('CursorAdapter - Property-Based Tests', () => { - let adapter: CursorAdapter; - - beforeEach(() => { - adapter = new CursorAdapter(); - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - // Feature: editor-adapter-system, Property 6: Capability Honesty - // Validates: Requirements 5.3 - it('Property 6: Capability Honesty - Closed-source editors cannot claim read capabilities', () => { - fc.assert( - fc.property(fc.constant(null), () => { - // Test Cursor adapter (closed-source) - const cursorAdapter = new CursorAdapter(); - const cursorCaps = cursorAdapter.capabilities; - - // Property: Closed-source editors must not claim they can read internal state - expect(cursorCaps.canReadChatHistory).toBe(false); - expect(cursorCaps.canStreamAssistantTokens).toBe(false); - expect(cursorCaps.canReadDiffArtifacts).toBe(false); - - // Property: Closed-source editors should have control-only or partial sync - expect(['control-only', 'partial']).toContain(cursorCaps.syncLevel); - - // Property: Cursor specifically should be control-only - expect(cursorCaps.syncLevel).toBe('control-only'); - - // Property: Cursor can inject prompts (control capability) - expect(cursorCaps.canInjectPrompt).toBe(true); - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 6: Capability Honesty - Compare with open-source - it('Property 6: Closed-source adapters have fewer capabilities than open-source', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const cursorAdapter = new CursorAdapter(); - const continueAdapter = new ContinueAdapter(); - - const cursorCaps = cursorAdapter.capabilities; - const continueCaps = continueAdapter.capabilities; - - // Property: Open-source (Continue) should have more read capabilities - expect(continueCaps.canReadChatHistory).toBe(true); - expect(cursorCaps.canReadChatHistory).toBe(false); - - expect(continueCaps.canStreamAssistantTokens).toBe(true); - expect(cursorCaps.canStreamAssistantTokens).toBe(false); - - expect(continueCaps.canReadDiffArtifacts).toBe(true); - expect(cursorCaps.canReadDiffArtifacts).toBe(false); - - // Property: Open-source should have higher sync level - const syncLevelPriority = { - 'full': 3, - 'partial': 2, - 'control-only': 1, - }; - - expect(syncLevelPriority[continueCaps.syncLevel]).toBeGreaterThan( - syncLevelPriority[cursorCaps.syncLevel] - ); - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 6: Capability Honesty - No methods for unsupported capabilities - it('Property 6: Cursor adapter does not implement methods for unsupported capabilities', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const cursorAdapter = new CursorAdapter(); - - // Property: If canReadChatHistory is false, readChatHistory should not be implemented - if (!cursorAdapter.capabilities.canReadChatHistory) { - expect((cursorAdapter as any).readChatHistory).toBeUndefined(); - } - - // Property: If canReadDiffArtifacts is false, readDiffArtifacts should not be implemented - if (!cursorAdapter.capabilities.canReadDiffArtifacts) { - expect((cursorAdapter as any).readDiffArtifacts).toBeUndefined(); - } - - // Property: injectPrompt should always be implemented when canInjectPrompt is true - if (cursorAdapter.capabilities.canInjectPrompt) { - expect(cursorAdapter.injectPrompt).toBeDefined(); - expect(typeof cursorAdapter.injectPrompt).toBe('function'); - } - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 6: Capability Honesty - All closed-source adapters follow same rules - it('Property 6: All closed-source adapters consistently declare limited capabilities', () => { - fc.assert( - fc.property(fc.constant(null), () => { - // Test all closed-source adapters we have - const closedSourceAdapters = [new CursorAdapter()]; - - closedSourceAdapters.forEach((adapter) => { - const caps = adapter.capabilities; - - // Property: All closed-source adapters cannot read chat history - expect(caps.canReadChatHistory).toBe(false); - - // Property: All closed-source adapters cannot stream tokens - expect(caps.canStreamAssistantTokens).toBe(false); - - // Property: All closed-source adapters cannot read diffs - expect(caps.canReadDiffArtifacts).toBe(false); - - // Property: All closed-source adapters should not have full sync - expect(caps.syncLevel).not.toBe('full'); - }); - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 6: Capability structure is valid - it('Property 6: Cursor adapter has valid capability structure', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const caps = adapter.capabilities; - - // Property: All required capability fields must be present - expect(caps).toHaveProperty('canInjectPrompt'); - expect(caps).toHaveProperty('canReadChatHistory'); - expect(caps).toHaveProperty('canStreamAssistantTokens'); - expect(caps).toHaveProperty('canReadDiffArtifacts'); - expect(caps).toHaveProperty('canPreventAutoApply'); - expect(caps).toHaveProperty('syncLevel'); - - // Property: All boolean fields must be actual booleans - expect(typeof caps.canInjectPrompt).toBe('boolean'); - expect(typeof caps.canReadChatHistory).toBe('boolean'); - expect(typeof caps.canStreamAssistantTokens).toBe('boolean'); - expect(typeof caps.canReadDiffArtifacts).toBe('boolean'); - expect(typeof caps.canPreventAutoApply).toBe('boolean'); - - // Property: syncLevel must be one of the valid values - expect(['full', 'partial', 'control-only']).toContain(caps.syncLevel); - }), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/CursorAdapter.test.ts b/packages/vscode-extension/src/editors/adapters/CursorAdapter.test.ts deleted file mode 100644 index 0cd69eb..0000000 --- a/packages/vscode-extension/src/editors/adapters/CursorAdapter.test.ts +++ /dev/null @@ -1,333 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { CursorAdapter } from './CursorAdapter'; -import * as vscode from 'vscode'; - -// Mock vscode module -vi.mock('vscode', () => ({ - commands: { - getCommands: vi.fn(), - executeCommand: vi.fn(), - }, -})); - -describe('CursorAdapter - Unit Tests', () => { - let adapter: CursorAdapter; - - beforeEach(() => { - adapter = new CursorAdapter(); - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - describe('Adapter Properties', () => { - it('should have correct editorId', () => { - expect(adapter.editorId).toBe('cursor'); - }); - - it('should have correct editorName', () => { - expect(adapter.editorName).toBe('Cursor'); - }); - - // Requirement 3.5: Cursor supports control-only sync - // Requirement 5.1: Cursor has limited capabilities due to closed-source nature - // Requirement 5.3: System clearly documents what is and isn't possible per editor - it('should declare control-only capabilities', () => { - expect(adapter.capabilities).toEqual({ - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }); - }); - - // Requirement 5.3: Closed-source capabilities must be false - it('should have all closed-source capabilities set to false', () => { - expect(adapter.capabilities.canReadChatHistory).toBe(false); - expect(adapter.capabilities.canStreamAssistantTokens).toBe(false); - expect(adapter.capabilities.canReadDiffArtifacts).toBe(false); - }); - }); - - describe('detect()', () => { - // Requirement 1.1: System detects available AI editors by querying VS Code commands - it('should detect Cursor when cursor.* commands are present', async () => { - const commands = [ - 'cursor.chat.newMessage', - 'cursor.openChat', - 'cursor.sendMessage', - 'workbench.action.files.save', - 'editor.action.formatDocument', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual([ - 'cursor.chat.newMessage', - 'cursor.openChat', - 'cursor.sendMessage', - ]); - }); - - it('should detect Cursor when commands contain "cursor" in lowercase', async () => { - const commands = [ - 'some.cursor.command', - 'workbench.action.files.save', - 'editor.action.formatDocument', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toContain('some.cursor.command'); - }); - - // Requirement 1.1: Detection happens dynamically without hardcoded assumptions - it('should not detect Cursor when cursor commands are absent', async () => { - const commands = [ - 'workbench.action.files.save', - 'editor.action.formatDocument', - 'git.commit', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should return empty array when no commands exist', async () => { - vi.mocked(vscode.commands.getCommands).mockResolvedValue([]); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should handle command query failure gracefully', async () => { - vi.mocked(vscode.commands.getCommands).mockRejectedValue( - new Error('VS Code API unavailable') - ); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(false); - expect(result.availableCommands).toEqual([]); - }); - - it('should match commands with "cursor." prefix', async () => { - const commands = [ - 'cursor.validCommand', - 'cursorX.notValid', - 'xcursor.notValid', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toContain('cursor.validCommand'); - }); - - it('should match commands containing "cursor" anywhere (case-insensitive)', async () => { - const commands = [ - 'some.CURSOR.command', - 'anotherCursorCommand', - 'workbench.action.files.save', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toContain('some.CURSOR.command'); - expect(result.availableCommands).toContain('anotherCursorCommand'); - }); - }); - - describe('injectPrompt()', () => { - // Requirement 2.1: Prompts originating from mobile appear in the editor's chat panel - // Requirement 2.2: Injection uses only public VS Code commands - it('should inject prompt successfully using primary command', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt('Hello, Cursor!'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('cursor.chat.newMessage'); - expect(result.error).toBeUndefined(); - - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'cursor.chat.newMessage', - 'Hello, Cursor!' - ); - }); - - // Test fallback command patterns - it('should use first fallback command when primary fails', async () => { - vi.mocked(vscode.commands.executeCommand) - .mockRejectedValueOnce(new Error('Primary command not found')) - .mockResolvedValueOnce(undefined); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('cursor.openChat'); - - expect(vscode.commands.executeCommand).toHaveBeenCalledTimes(2); - expect(vscode.commands.executeCommand).toHaveBeenNthCalledWith( - 1, - 'cursor.chat.newMessage', - 'Test prompt' - ); - expect(vscode.commands.executeCommand).toHaveBeenNthCalledWith( - 2, - 'cursor.openChat', - { message: 'Test prompt' } - ); - }); - - it('should use second fallback command when first two fail', async () => { - vi.mocked(vscode.commands.executeCommand) - .mockRejectedValueOnce(new Error('Primary command not found')) - .mockRejectedValueOnce(new Error('First fallback not found')) - .mockResolvedValueOnce(undefined); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('cursor.sendMessage'); - - expect(vscode.commands.executeCommand).toHaveBeenCalledTimes(3); - expect(vscode.commands.executeCommand).toHaveBeenNthCalledWith( - 3, - 'cursor.sendMessage', - 'Test prompt' - ); - }); - - // Requirement 2.5: System provides clear error messages when prompt injection fails - it('should return error result when all command attempts fail', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - new Error('Command not found') - ); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(false); - expect(result.error).toBeDefined(); - expect(result.error).toContain('Failed to inject prompt into Cursor'); - expect(result.error).toContain('Command not found'); - expect(result.error).toContain('cursor.chat.newMessage'); - expect(result.error).toContain('cursor.openChat'); - expect(result.error).toContain('cursor.sendMessage'); - expect(result.commandUsed).toBe('cursor.chat.newMessage (attempted)'); - }); - - it('should handle empty prompt string', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt(''); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'cursor.chat.newMessage', - '' - ); - }); - - it('should handle multiline prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const multilinePrompt = 'Line 1\nLine 2\nLine 3'; - const result = await adapter.injectPrompt(multilinePrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'cursor.chat.newMessage', - multilinePrompt - ); - }); - - it('should handle prompts with special characters', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const specialPrompt = 'Test !@#$%^&*() <>"\''; - const result = await adapter.injectPrompt(specialPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'cursor.chat.newMessage', - specialPrompt - ); - }); - - it('should handle very long prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const longPrompt = 'a'.repeat(10000); - const result = await adapter.injectPrompt(longPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'cursor.chat.newMessage', - longPrompt - ); - }); - - it('should handle non-Error exceptions', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - 'String error' - ); - - const result = await adapter.injectPrompt('Test'); - - expect(result.success).toBe(false); - expect(result.error).toContain('Failed to inject prompt into Cursor'); - expect(result.error).toContain('String error'); - }); - }); - - describe('Interface Compliance', () => { - it('should implement IEditorAdapter interface', () => { - expect(adapter).toHaveProperty('editorId'); - expect(adapter).toHaveProperty('editorName'); - expect(adapter).toHaveProperty('capabilities'); - expect(adapter).toHaveProperty('detect'); - expect(adapter).toHaveProperty('injectPrompt'); - }); - - it('should have detect method that returns Promise', () => { - expect(typeof adapter.detect).toBe('function'); - expect(adapter.detect()).toBeInstanceOf(Promise); - }); - - it('should have injectPrompt method that returns Promise', () => { - expect(typeof adapter.injectPrompt).toBe('function'); - expect(adapter.injectPrompt('test')).toBeInstanceOf(Promise); - }); - - // Requirement 5.3: Closed-source editors should not implement read methods - it('should not have readChatHistory method', () => { - expect(adapter).not.toHaveProperty('readChatHistory'); - }); - - it('should not have readDiffArtifacts method', () => { - expect(adapter).not.toHaveProperty('readDiffArtifacts'); - }); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/CursorAdapter.ts b/packages/vscode-extension/src/editors/adapters/CursorAdapter.ts index cc1515c..fa01c7a 100644 --- a/packages/vscode-extension/src/editors/adapters/CursorAdapter.ts +++ b/packages/vscode-extension/src/editors/adapters/CursorAdapter.ts @@ -8,11 +8,11 @@ import { /** * Adapter for Cursor extension. - * + * * Cursor is a closed-source AI code editor, so we can only use public commands * exposed through VS Code's command API. We cannot read internal state, access * chat history, or stream tokens in real-time. - * + * * Capabilities: * - Prompt injection: Yes (via cursor.* commands discovered dynamically) * - Chat history: No (closed-source, no public API) @@ -20,13 +20,13 @@ import { * - Diff artifacts: No (closed-source, no public API) * - Prevent auto-apply: No (unknown, depends on Cursor's internal settings) * - Sync level: Control-only - * + * * Safety: This adapter uses ONLY public VS Code commands. We never: * - Scrape UI elements or webview DOM * - Use keystroke replay or automation * - Access private or undocumented APIs * - Make assumptions about Cursor's internal state - * + * * The mobile client must reconstruct state from other signals (file changes, * diff events) rather than relying on chat mirroring. */ @@ -44,15 +44,15 @@ export class CursorAdapter implements IEditorAdapter { /** * Detect if Cursor is installed and available. - * + * * Uses command discovery pattern: queries all available VS Code commands * and looks for Cursor-specific command patterns (commands starting with * "cursor." or containing "cursor" in the name). - * + * * Safety: Never assumes Cursor is available. Always checks dynamically * using public VS Code API. Fails safe by returning not installed if * command query fails. - * + * * @returns DetectionResult indicating if Cursor is installed and available commands */ async detect(): Promise { @@ -86,25 +86,25 @@ export class CursorAdapter implements IEditorAdapter { /** * Inject a prompt into Cursor's chat panel. - * + * * Attempts to use Cursor's public commands to inject a prompt. Since Cursor * is closed-source, we don't know the exact command names, so we try multiple * common patterns with fallback logic. - * + * * Fallback strategy: * 1. Try 'cursor.chat.newMessage' (common pattern for chat commands) * 2. Try 'cursor.openChat' with message parameter * 3. Try 'cursor.sendMessage' (alternative pattern) - * + * * Safety: Uses only public VS Code commands. Never throws exceptions - always * returns error result with clear message if all attempts fail. The actual * command names would need to be discovered through Cursor's documentation * or command palette. - * + * * Note: The command names used here are educated guesses based on common * patterns. In production, these would need to be verified against Cursor's * actual public API. - * + * * @param prompt The prompt text to inject into Cursor's chat * @returns PromptInjectionResult indicating success or failure with error details */ @@ -119,7 +119,7 @@ export class CursorAdapter implements IEditorAdapter { }; } catch (primaryError) { // Primary command failed, try fallback patterns - + // Fallback 1: Try cursor.openChat with message parameter try { await vscode.commands.executeCommand('cursor.openChat', { @@ -143,9 +143,7 @@ export class CursorAdapter implements IEditorAdapter { // All attempts failed - return error result with context // Safety: Never throw, always return error result const primaryErrorMessage = - primaryError instanceof Error - ? primaryError.message - : String(primaryError); + primaryError instanceof Error ? primaryError.message : String(primaryError); return { success: false, diff --git a/packages/vscode-extension/src/editors/adapters/EditorRegistry.properties.test.ts b/packages/vscode-extension/src/editors/adapters/EditorRegistry.properties.test.ts deleted file mode 100644 index 1575d2e..0000000 --- a/packages/vscode-extension/src/editors/adapters/EditorRegistry.properties.test.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import * as fc from 'fast-check'; -import { EditorRegistry } from './EditorRegistry'; -import { - IEditorAdapter, - EditorCapabilities, - DetectionResult, - PromptInjectionResult, -} from './types'; - -// Mock adapter factory for testing -class MockAdapter implements IEditorAdapter { - constructor( - public readonly editorId: string, - public readonly editorName: string, - public readonly capabilities: EditorCapabilities, - private isInstalled: boolean = true - ) {} - - async detect(): Promise { - return { - isInstalled: this.isInstalled, - availableCommands: this.isInstalled - ? [`${this.editorId}.command1`, `${this.editorId}.command2`] - : [], - }; - } - - async injectPrompt(prompt: string): Promise { - return { - success: true, - commandUsed: `${this.editorId}.injectPrompt`, - }; - } -} - -// Helper to create adapters with different sync levels -function createAdapter( - id: string, - syncLevel: EditorCapabilities['syncLevel'], - isInstalled: boolean = true -): IEditorAdapter { - return new MockAdapter( - id, - `${id}-editor`, - { - canInjectPrompt: true, - canReadChatHistory: syncLevel === 'full', - canStreamAssistantTokens: syncLevel === 'full', - canReadDiffArtifacts: syncLevel !== 'control-only', - canPreventAutoApply: syncLevel !== 'control-only', - syncLevel, - }, - isInstalled - ); -} - -describe('EditorRegistry - Property-Based Tests', () => { - let registry: EditorRegistry; - - beforeEach(() => { - registry = new EditorRegistry(); - }); - - // Feature: editor-adapter-system, Property 3: Adapter Selection Prefers Higher Fidelity - it('Property 3: getBestAdapter prefers higher sync levels', async () => { - // Generator for sync levels - const syncLevelArb = fc.constantFrom( - 'full', - 'partial', - 'control-only' - ); - - // Generator for arrays of adapters with random sync levels - const adaptersArb = fc - .array( - fc - .tuple(fc.string({ minLength: 1, maxLength: 10 }), syncLevelArb) - .map(([id, syncLevel]: [string, EditorCapabilities['syncLevel']]) => - createAdapter(`adapter-${id}`, syncLevel, true) - ), - { minLength: 1, maxLength: 10 } - ) - .map((adapters: IEditorAdapter[]) => { - // Ensure unique IDs - const seen = new Set(); - return adapters.filter((adapter: IEditorAdapter) => { - if (seen.has(adapter.editorId)) { - return false; - } - seen.add(adapter.editorId); - return true; - }); - }) - .filter((adapters: IEditorAdapter[]) => adapters.length > 0); - - await fc.assert( - fc.asyncProperty(adaptersArb, async (adapters: IEditorAdapter[]) => { - const testRegistry = new EditorRegistry(); - - // Register all adapters - adapters.forEach((adapter: IEditorAdapter) => testRegistry.register(adapter)); - - // Get best adapter - const best = await testRegistry.getBestAdapter(); - - // Best should not be null since all adapters are installed - expect(best).not.toBeNull(); - - if (best) { - // Best should have highest sync level among all adapters - const syncLevelPriority: Record< - EditorCapabilities['syncLevel'], - number - > = { - full: 3, - partial: 2, - 'control-only': 1, - }; - - const bestPriority = syncLevelPriority[best.capabilities.syncLevel]; - - adapters.forEach((adapter: IEditorAdapter) => { - const adapterPriority = - syncLevelPriority[adapter.capabilities.syncLevel]; - expect(bestPriority).toBeGreaterThanOrEqual(adapterPriority); - }); - } - }), - { numRuns: 100 } - ); - }); - - // Feature: editor-adapter-system, Property 9: Registry Maintains Adapter List - it('Property 9: getAllAdapters returns exactly the registered adapters', () => { - // Generator for arrays of unique adapter IDs - const adapterIdsArb = fc - .array(fc.string({ minLength: 1, maxLength: 10 }), { - minLength: 0, - maxLength: 20, - }) - .map((ids) => Array.from(new Set(ids))); // Ensure uniqueness - - fc.assert( - fc.property(adapterIdsArb, (adapterIds) => { - const testRegistry = new EditorRegistry(); - - // Create and register adapters - const adapters = adapterIds.map((id) => - createAdapter(id, 'partial', true) - ); - adapters.forEach((adapter) => testRegistry.register(adapter)); - - // Get all adapters - const retrieved = testRegistry.getAllAdapters(); - - // Should have exactly the same number of adapters - expect(retrieved.length).toBe(adapters.length); - - // Should contain all registered adapter IDs - const retrievedIds = new Set(retrieved.map((a) => a.editorId)); - const registeredIds = new Set(adapters.map((a) => a.editorId)); - - expect(retrievedIds).toEqual(registeredIds); - - // Each registered adapter should be retrievable by ID - adapters.forEach((adapter) => { - const found = testRegistry.getAdapter(adapter.editorId); - expect(found).toBeDefined(); - expect(found?.editorId).toBe(adapter.editorId); - }); - }), - { numRuns: 100 } - ); - }); - - // Additional property: Detection cache consistency - it('Property 10: Detection cache returns consistent results', async () => { - const adapterArb = fc - .tuple( - fc.string({ minLength: 1, maxLength: 10 }), - fc.constantFrom( - 'full', - 'partial', - 'control-only' - ), - fc.boolean() - ) - .map(([id, syncLevel, isInstalled]) => - createAdapter(id, syncLevel, isInstalled) - ); - - await fc.assert( - fc.asyncProperty(adapterArb, async (adapter) => { - const testRegistry = new EditorRegistry(); - testRegistry.register(adapter); - - // First detection - const result1 = await testRegistry.detectAll(); - - // Second detection (should use cache) - const result2 = await testRegistry.detectAll(); - - // Results should be identical - expect(result1.size).toBe(result2.size); - expect(result1.get(adapter.editorId)).toEqual( - result2.get(adapter.editorId) - ); - }), - { numRuns: 100 } - ); - }); - - // Property: getBestAdapter returns null when no editors are installed - it('Property: getBestAdapter returns null when no editors installed', async () => { - const adapterIdsArb = fc - .array(fc.string({ minLength: 1, maxLength: 10 }), { - minLength: 1, - maxLength: 10, - }) - .map((ids) => Array.from(new Set(ids))); - - await fc.assert( - fc.asyncProperty(adapterIdsArb, async (adapterIds) => { - const testRegistry = new EditorRegistry(); - - // Create adapters that are NOT installed - const adapters = adapterIds.map((id) => - createAdapter(id, 'partial', false) - ); - adapters.forEach((adapter) => testRegistry.register(adapter)); - - // Get best adapter - const best = await testRegistry.getBestAdapter(); - - // Should be null since no editors are installed - expect(best).toBeNull(); - }), - { numRuns: 100 } - ); - }); - - // Property: Sync level priority ordering - it('Property: Full sync is preferred over partial, partial over control-only', async () => { - await fc.assert( - fc.asyncProperty( - fc.boolean(), - fc.boolean(), - fc.boolean(), - async (hasFullSync, hasPartialSync, hasControlOnly) => { - // Skip if no adapters would be installed - if (!hasFullSync && !hasPartialSync && !hasControlOnly) { - return; - } - - const testRegistry = new EditorRegistry(); - - if (hasFullSync) { - testRegistry.register(createAdapter('full-editor', 'full', true)); - } - if (hasPartialSync) { - testRegistry.register( - createAdapter('partial-editor', 'partial', true) - ); - } - if (hasControlOnly) { - testRegistry.register( - createAdapter('control-editor', 'control-only', true) - ); - } - - const best = await testRegistry.getBestAdapter(); - - expect(best).not.toBeNull(); - - if (best) { - // Verify priority: full > partial > control-only - if (hasFullSync) { - expect(best.capabilities.syncLevel).toBe('full'); - } else if (hasPartialSync) { - expect(best.capabilities.syncLevel).toBe('partial'); - } else { - expect(best.capabilities.syncLevel).toBe('control-only'); - } - } - } - ), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/EditorRegistry.test.ts b/packages/vscode-extension/src/editors/adapters/EditorRegistry.test.ts deleted file mode 100644 index 02fc505..0000000 --- a/packages/vscode-extension/src/editors/adapters/EditorRegistry.test.ts +++ /dev/null @@ -1,440 +0,0 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { EditorRegistry } from './EditorRegistry'; -import { - IEditorAdapter, - EditorCapabilities, - DetectionResult, - PromptInjectionResult, -} from './types'; - -// Mock adapter for testing -class MockAdapter implements IEditorAdapter { - constructor( - public readonly editorId: string, - public readonly editorName: string, - public readonly capabilities: EditorCapabilities, - private detectResult: DetectionResult - ) {} - - async detect(): Promise { - return this.detectResult; - } - - async injectPrompt(prompt: string): Promise { - return { - success: true, - commandUsed: `${this.editorId}.injectPrompt`, - }; - } -} - -describe('EditorRegistry - Unit Tests', () => { - let registry: EditorRegistry; - - beforeEach(() => { - registry = new EditorRegistry(); - }); - - describe('Registration and Retrieval', () => { - it('should register an adapter and retrieve it by ID', () => { - const adapter = new MockAdapter( - 'test-editor', - 'Test Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - registry.register(adapter); - - const retrieved = registry.getAdapter('test-editor'); - expect(retrieved).toBe(adapter); - expect(retrieved?.editorId).toBe('test-editor'); - expect(retrieved?.editorName).toBe('Test Editor'); - }); - - it('should return undefined for non-existent adapter ID', () => { - const retrieved = registry.getAdapter('non-existent'); - expect(retrieved).toBeUndefined(); - }); - - it('should return all registered adapters', () => { - const adapter1 = new MockAdapter( - 'editor1', - 'Editor 1', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - const adapter2 = new MockAdapter( - 'editor2', - 'Editor 2', - { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'full', - }, - { isInstalled: true } - ); - - registry.register(adapter1); - registry.register(adapter2); - - const allAdapters = registry.getAllAdapters(); - expect(allAdapters).toHaveLength(2); - expect(allAdapters).toContain(adapter1); - expect(allAdapters).toContain(adapter2); - }); - - it('should return empty array when no adapters are registered', () => { - const allAdapters = registry.getAllAdapters(); - expect(allAdapters).toHaveLength(0); - }); - }); - - describe('Detection and Caching', () => { - it('should detect all registered adapters', async () => { - const adapter1 = new MockAdapter( - 'editor1', - 'Editor 1', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { - isInstalled: true, - availableCommands: ['editor1.command1', 'editor1.command2'], - } - ); - - const adapter2 = new MockAdapter( - 'editor2', - 'Editor 2', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'partial', - }, - { - isInstalled: false, - } - ); - - registry.register(adapter1); - registry.register(adapter2); - - const results = await registry.detectAll(); - - expect(results.size).toBe(2); - expect(results.get('editor1')?.isInstalled).toBe(true); - expect(results.get('editor1')?.availableCommands).toEqual([ - 'editor1.command1', - 'editor1.command2', - ]); - expect(results.get('editor2')?.isInstalled).toBe(false); - }); - - it('should cache detection results', async () => { - let detectCallCount = 0; - - class CountingAdapter extends MockAdapter { - async detect(): Promise { - detectCallCount++; - return super.detect(); - } - } - - const adapter = new CountingAdapter( - 'test-editor', - 'Test Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - registry.register(adapter); - - // First detection - await registry.detectAll(); - expect(detectCallCount).toBe(1); - - // Second detection should use cache - await registry.detectAll(); - expect(detectCallCount).toBe(1); - }); - - it('should clear cache and re-detect after clearCache()', async () => { - let detectCallCount = 0; - - class CountingAdapter extends MockAdapter { - async detect(): Promise { - detectCallCount++; - return super.detect(); - } - } - - const adapter = new CountingAdapter( - 'test-editor', - 'Test Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - registry.register(adapter); - - // First detection - await registry.detectAll(); - expect(detectCallCount).toBe(1); - - // Clear cache - registry.clearCache(); - - // Third detection should call detect again - await registry.detectAll(); - expect(detectCallCount).toBe(2); - }); - }); - - describe('Best Adapter Selection', () => { - it('should return null when no editors are installed', async () => { - const adapter = new MockAdapter( - 'test-editor', - 'Test Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: false } - ); - - registry.register(adapter); - - const best = await registry.getBestAdapter(); - expect(best).toBeNull(); - }); - - it('should return the only installed adapter', async () => { - const adapter = new MockAdapter( - 'test-editor', - 'Test Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - registry.register(adapter); - - const best = await registry.getBestAdapter(); - expect(best).toBe(adapter); - }); - - it('should prefer full sync over partial sync', async () => { - const partialAdapter = new MockAdapter( - 'partial-editor', - 'Partial Editor', - { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'partial', - }, - { isInstalled: true } - ); - - const fullAdapter = new MockAdapter( - 'full-editor', - 'Full Editor', - { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'full', - }, - { isInstalled: true } - ); - - registry.register(partialAdapter); - registry.register(fullAdapter); - - const best = await registry.getBestAdapter(); - expect(best).toBe(fullAdapter); - expect(best?.capabilities.syncLevel).toBe('full'); - }); - - it('should prefer partial sync over control-only', async () => { - const controlAdapter = new MockAdapter( - 'control-editor', - 'Control Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - const partialAdapter = new MockAdapter( - 'partial-editor', - 'Partial Editor', - { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'partial', - }, - { isInstalled: true } - ); - - registry.register(controlAdapter); - registry.register(partialAdapter); - - const best = await registry.getBestAdapter(); - expect(best).toBe(partialAdapter); - expect(best?.capabilities.syncLevel).toBe('partial'); - }); - - it('should prefer full sync when all three levels are available', async () => { - const controlAdapter = new MockAdapter( - 'control-editor', - 'Control Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - const partialAdapter = new MockAdapter( - 'partial-editor', - 'Partial Editor', - { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'partial', - }, - { isInstalled: true } - ); - - const fullAdapter = new MockAdapter( - 'full-editor', - 'Full Editor', - { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'full', - }, - { isInstalled: true } - ); - - registry.register(controlAdapter); - registry.register(partialAdapter); - registry.register(fullAdapter); - - const best = await registry.getBestAdapter(); - expect(best).toBe(fullAdapter); - expect(best?.capabilities.syncLevel).toBe('full'); - }); - - it('should only consider installed adapters', async () => { - const installedAdapter = new MockAdapter( - 'installed-editor', - 'Installed Editor', - { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - { isInstalled: true } - ); - - const notInstalledAdapter = new MockAdapter( - 'not-installed-editor', - 'Not Installed Editor', - { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'full', - }, - { isInstalled: false } - ); - - registry.register(installedAdapter); - registry.register(notInstalledAdapter); - - const best = await registry.getBestAdapter(); - expect(best).toBe(installedAdapter); - expect(best?.editorId).toBe('installed-editor'); - }); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/EditorRegistry.ts b/packages/vscode-extension/src/editors/adapters/EditorRegistry.ts index c3fde49..f19ee19 100644 --- a/packages/vscode-extension/src/editors/adapters/EditorRegistry.ts +++ b/packages/vscode-extension/src/editors/adapters/EditorRegistry.ts @@ -1,18 +1,14 @@ -import { - IEditorAdapter, - DetectionResult, - EditorCapabilities, -} from './types'; +import { IEditorAdapter, DetectionResult, EditorCapabilities } from './types'; /** * Registry for managing editor adapters. - * + * * Responsibilities: * - Register adapters at extension activation * - Detect available editors * - Select best adapter based on capabilities * - Provide query interface - * + * * Safety: Registry never assumes an editor is available. All operations * check adapter capabilities before attempting operations. */ @@ -22,7 +18,7 @@ export class EditorRegistry { /** * Register an editor adapter. - * + * * Called during extension activation to register all known adapters. */ register(adapter: IEditorAdapter): void { @@ -31,7 +27,7 @@ export class EditorRegistry { /** * Detect all available editors. - * + * * Returns map of editorId -> DetectionResult. * Results are cached to avoid repeated command queries. */ @@ -56,20 +52,20 @@ export class EditorRegistry { /** * Get the best available adapter based on capabilities. - * + * * Preference order: * 1. Full sync (Continue) * 2. Partial sync (Kiro) * 3. Control-only (Cursor, Antigravity) - * + * * Returns null if no editor is installed. */ async getBestAdapter(): Promise { const available = await this.detectAll(); // Filter to installed editors - const installed = Array.from(this.adapters.values()).filter((adapter) => - available.get(adapter.editorId)?.isInstalled + const installed = Array.from(this.adapters.values()).filter( + (adapter) => available.get(adapter.editorId)?.isInstalled ); if (installed.length === 0) { @@ -77,17 +73,15 @@ export class EditorRegistry { } // Sort by sync level preference - const syncLevelPriority: Record = - { - full: 3, - partial: 2, - 'control-only': 1, - }; + const syncLevelPriority: Record = { + full: 3, + partial: 2, + 'control-only': 1, + }; installed.sort( (a, b) => - syncLevelPriority[b.capabilities.syncLevel] - - syncLevelPriority[a.capabilities.syncLevel] + syncLevelPriority[b.capabilities.syncLevel] - syncLevelPriority[a.capabilities.syncLevel] ); return installed[0]; diff --git a/packages/vscode-extension/src/editors/adapters/KiroAdapter.test.ts b/packages/vscode-extension/src/editors/adapters/KiroAdapter.test.ts deleted file mode 100644 index e5cf2f3..0000000 --- a/packages/vscode-extension/src/editors/adapters/KiroAdapter.test.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { KiroAdapter } from './KiroAdapter'; -import * as vscode from 'vscode'; - -// Mock vscode module -vi.mock('vscode', () => ({ - commands: { - getCommands: vi.fn(), - executeCommand: vi.fn(), - }, -})); - -describe('KiroAdapter - Unit Tests', () => { - let adapter: KiroAdapter; - - beforeEach(() => { - adapter = new KiroAdapter(); - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - describe('Adapter Properties', () => { - it('should have correct editorId', () => { - expect(adapter.editorId).toBe('kiro'); - }); - - it('should have correct editorName', () => { - expect(adapter.editorName).toBe('Kiro'); - }); - - // Requirement 3.4: Kiro supports partial sync - it('should declare partial sync capabilities', () => { - expect(adapter.capabilities).toEqual({ - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - syncLevel: 'partial', - }); - }); - }); - - describe('detect()', () => { - // Requirement 1.1: System detects available AI editors - it('should always detect Kiro as installed', async () => { - const commands = [ - 'kiro.chat.sendMessage', - 'kiro.openSettings', - 'workbench.action.files.save', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual([ - 'kiro.chat.sendMessage', - 'kiro.openSettings', - ]); - }); - - it('should detect Kiro even when no kiro.* commands are found', async () => { - const commands = [ - 'workbench.action.files.save', - 'editor.action.formatDocument', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - // Kiro is always installed since we ARE Kiro - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual([]); - }); - - it('should detect Kiro even when command query fails', async () => { - vi.mocked(vscode.commands.getCommands).mockRejectedValue( - new Error('VS Code API unavailable') - ); - - const result = await adapter.detect(); - - // Kiro is always installed since we ARE Kiro - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual([]); - }); - - it('should only match commands with exact "kiro." prefix', async () => { - const commands = [ - 'kiro.validCommand', - 'kiroX.notValid', - 'xkiro.notValid', - 'KIRO.notValid', - 'Kiro.notValid', - ]; - - vi.mocked(vscode.commands.getCommands).mockResolvedValue(commands); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual(['kiro.validCommand']); - }); - - it('should return empty array when no commands exist', async () => { - vi.mocked(vscode.commands.getCommands).mockResolvedValue([]); - - const result = await adapter.detect(); - - expect(result.isInstalled).toBe(true); - expect(result.availableCommands).toEqual([]); - }); - }); - - describe('injectPrompt()', () => { - // Requirement 2.1: Prompts originating from mobile appear in the editor's chat panel - it('should inject prompt successfully using Kiro command', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt('Hello, Kiro!'); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('kiro.chat.sendMessage'); - expect(result.error).toBeUndefined(); - - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'kiro.chat.sendMessage', - { message: 'Hello, Kiro!' } - ); - }); - - it('should return error result when command execution fails', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - new Error('Command not found') - ); - - const result = await adapter.injectPrompt('Test prompt'); - - expect(result.success).toBe(false); - expect(result.error).toBeDefined(); - expect(result.error).toContain('Failed to inject prompt'); - expect(result.error).toContain('Command not found'); - expect(result.commandUsed).toBe('kiro.chat.sendMessage'); - }); - - it('should handle empty prompt string', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await adapter.injectPrompt(''); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'kiro.chat.sendMessage', - { message: '' } - ); - }); - - it('should handle multiline prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const multilinePrompt = 'Line 1\nLine 2\nLine 3'; - const result = await adapter.injectPrompt(multilinePrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'kiro.chat.sendMessage', - { message: multilinePrompt } - ); - }); - - it('should handle prompts with special characters', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const specialPrompt = 'Test !@#$%^&*() <>"\''; - const result = await adapter.injectPrompt(specialPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'kiro.chat.sendMessage', - { message: specialPrompt } - ); - }); - - it('should handle very long prompts', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const longPrompt = 'a'.repeat(10000); - const result = await adapter.injectPrompt(longPrompt); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'kiro.chat.sendMessage', - { message: longPrompt } - ); - }); - - it('should handle non-Error exceptions', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - 'String error' - ); - - const result = await adapter.injectPrompt('Test'); - - expect(result.success).toBe(false); - expect(result.error).toContain('Failed to inject prompt'); - expect(result.error).toContain('String error'); - }); - }); - - describe('readChatHistory()', () => { - it('should throw not implemented error', async () => { - await expect(adapter.readChatHistory()).rejects.toThrow( - 'readChatHistory not yet implemented for Kiro adapter' - ); - }); - }); - - describe('readDiffArtifacts()', () => { - it('should throw not implemented error', async () => { - await expect(adapter.readDiffArtifacts()).rejects.toThrow( - 'readDiffArtifacts not yet implemented for Kiro adapter' - ); - }); - }); - - describe('Interface Compliance', () => { - it('should implement IEditorAdapter interface', () => { - expect(adapter).toHaveProperty('editorId'); - expect(adapter).toHaveProperty('editorName'); - expect(adapter).toHaveProperty('capabilities'); - expect(adapter).toHaveProperty('detect'); - expect(adapter).toHaveProperty('injectPrompt'); - expect(adapter).toHaveProperty('readChatHistory'); - expect(adapter).toHaveProperty('readDiffArtifacts'); - }); - - it('should have detect method that returns Promise', () => { - expect(typeof adapter.detect).toBe('function'); - expect(adapter.detect()).toBeInstanceOf(Promise); - }); - - it('should have injectPrompt method that returns Promise', () => { - expect(typeof adapter.injectPrompt).toBe('function'); - expect(adapter.injectPrompt('test')).toBeInstanceOf(Promise); - }); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/KiroAdapter.ts b/packages/vscode-extension/src/editors/adapters/KiroAdapter.ts index 833fdeb..cbeb5a1 100644 --- a/packages/vscode-extension/src/editors/adapters/KiroAdapter.ts +++ b/packages/vscode-extension/src/editors/adapters/KiroAdapter.ts @@ -10,11 +10,11 @@ import { /** * Adapter for Kiro extension. - * + * * Since we ARE Kiro, we have internal access to our own state and capabilities. * However, this adapter uses public command patterns where possible to demonstrate * the adapter pattern for other editors. - * + * * Capabilities: * - Prompt injection: Yes (we control our own chat interface) * - Chat history: Yes (we control our own state) @@ -22,7 +22,7 @@ import { * - Diff artifacts: Yes (we control our own diffs) * - Prevent auto-apply: Yes (we control edit application) * - Sync level: Partial (we have full internal access but use partial for consistency) - * + * * Safety: Uses public VS Code commands where available. Since we are Kiro, * we can safely access internal state when needed, but we prefer command-based * interaction to maintain consistency with other adapters. @@ -41,11 +41,11 @@ export class KiroAdapter implements IEditorAdapter { /** * Detect if Kiro is available. - * + * * Since we ARE Kiro, this always returns installed. However, we still * query for Kiro commands to maintain consistency with other adapters * and to provide useful debugging information. - * + * * Safety: Always returns installed since we are running as Kiro. * Command discovery is used for informational purposes only. */ @@ -71,13 +71,13 @@ export class KiroAdapter implements IEditorAdapter { /** * Inject a prompt into Kiro's chat panel. - * + * * Uses Kiro's public command to send a message to the chat interface. * The command name follows the pattern used by other AI editors. - * + * * Safety: Uses public VS Code command API. Falls back gracefully if * the command doesn't exist or fails to execute. - * + * * @param prompt The prompt text to inject * @returns Result indicating success or failure with error details */ @@ -95,8 +95,7 @@ export class KiroAdapter implements IEditorAdapter { }; } catch (error) { // Safety: Never throw, always return error result with context - const errorMessage = - error instanceof Error ? error.message : String(error); + const errorMessage = error instanceof Error ? error.message : String(error); return { success: false, @@ -108,12 +107,12 @@ export class KiroAdapter implements IEditorAdapter { /** * Read chat history from Kiro. - * + * * Since we ARE Kiro, we can access our internal chat state directly. * This method would integrate with Kiro's chat history storage. - * + * * Safety: Only reads our own internal state. No external API access required. - * + * * @returns Array of chat messages * @throws Error indicating not yet implemented */ @@ -125,12 +124,12 @@ export class KiroAdapter implements IEditorAdapter { /** * Read diff artifacts from Kiro. - * + * * Since we ARE Kiro, we can access our internal diff state directly. * This method would integrate with Kiro's diff tracking system. - * + * * Safety: Only reads our own internal state. No external API access required. - * + * * @returns Array of diff artifacts * @throws Error indicating not yet implemented */ diff --git a/packages/vscode-extension/src/editors/adapters/errors.test.ts b/packages/vscode-extension/src/editors/adapters/errors.test.ts deleted file mode 100644 index ff42a37..0000000 --- a/packages/vscode-extension/src/editors/adapters/errors.test.ts +++ /dev/null @@ -1,416 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import * as vscode from 'vscode'; -import { - EditorAdapterErrorType, - safeExecuteCommand, - requireCapability, - requireMethod, - formatAdapterError, - createAdapterError, - executeWithCapabilityCheck, -} from './errors'; -import { IEditorAdapter, EditorCapabilities } from './types'; - -// Mock vscode module -vi.mock('vscode', () => ({ - commands: { - executeCommand: vi.fn(), - }, -})); - -describe('Error Utilities - Unit Tests', () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - describe('safeExecuteCommand()', () => { - // Requirement 6.4: Always fails safe when operations cannot be completed - it('should return success result when command executes successfully', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await safeExecuteCommand('test.command', { arg: 'value' }); - - expect(result.success).toBe(true); - expect(result.commandUsed).toBe('test.command'); - expect(result.error).toBeUndefined(); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'test.command', - { arg: 'value' } - ); - }); - - // Requirement 6.4: Always fails safe when operations cannot be completed - // Requirement 6.6: System provides clear error messages for unsupported operations - it('should catch exceptions and return error result', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - new Error('Command not found') - ); - - const result = await safeExecuteCommand('invalid.command'); - - expect(result.success).toBe(false); - expect(result.error).toBeDefined(); - expect(result.error).toContain('Command \'invalid.command\' failed'); - expect(result.error).toContain('Command not found'); - expect(result.commandUsed).toBe('invalid.command'); - }); - - it('should handle non-Error exceptions', async () => { - vi.mocked(vscode.commands.executeCommand).mockRejectedValue( - 'String error message' - ); - - const result = await safeExecuteCommand('test.command'); - - expect(result.success).toBe(false); - expect(result.error).toContain('String error message'); - }); - - it('should handle commands with no arguments', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await safeExecuteCommand('test.command'); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith('test.command'); - }); - - it('should handle commands with multiple arguments', async () => { - vi.mocked(vscode.commands.executeCommand).mockResolvedValue(undefined); - - const result = await safeExecuteCommand('test.command', 'arg1', 'arg2', 'arg3'); - - expect(result.success).toBe(true); - expect(vscode.commands.executeCommand).toHaveBeenCalledWith( - 'test.command', - 'arg1', - 'arg2', - 'arg3' - ); - }); - }); - - describe('requireCapability()', () => { - const createMockAdapter = (capabilities: Partial): IEditorAdapter => ({ - editorId: 'test', - editorName: 'Test Editor', - capabilities: { - canInjectPrompt: false, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - ...capabilities, - }, - detect: vi.fn(), - injectPrompt: vi.fn(), - }); - - // Requirement 6.4: Always fails safe when operations cannot be completed - it('should not throw when adapter has the required capability', () => { - const adapter = createMockAdapter({ canReadChatHistory: true }); - - expect(() => { - requireCapability(adapter, 'canReadChatHistory', 'reading chat history'); - }).not.toThrow(); - }); - - // Requirement 6.6: System provides clear error messages for unsupported operations - it('should throw clear error when adapter lacks the required capability', () => { - const adapter = createMockAdapter({ canReadChatHistory: false }); - - expect(() => { - requireCapability(adapter, 'canReadChatHistory', 'reading chat history'); - }).toThrow('Editor Test Editor does not support reading chat history'); - }); - - it('should include sync level in error message', () => { - const adapter = createMockAdapter({ - canReadChatHistory: false, - syncLevel: 'control-only', - }); - - expect(() => { - requireCapability(adapter, 'canReadChatHistory', 'reading chat history'); - }).toThrow('Sync level: control-only'); - }); - - it('should include capability name in error message', () => { - const adapter = createMockAdapter({ canStreamAssistantTokens: false }); - - expect(() => { - requireCapability(adapter, 'canStreamAssistantTokens', 'streaming tokens'); - }).toThrow('Capability \'canStreamAssistantTokens\' is not available'); - }); - - it('should work with different capability types', () => { - const adapter = createMockAdapter({ - canInjectPrompt: true, - canReadDiffArtifacts: true, - canPreventAutoApply: true, - }); - - expect(() => { - requireCapability(adapter, 'canInjectPrompt', 'injecting prompts'); - }).not.toThrow(); - - expect(() => { - requireCapability(adapter, 'canReadDiffArtifacts', 'reading diffs'); - }).not.toThrow(); - - expect(() => { - requireCapability(adapter, 'canPreventAutoApply', 'preventing auto-apply'); - }).not.toThrow(); - }); - }); - - describe('requireMethod()', () => { - it('should not throw when adapter has the required method', () => { - const adapter: IEditorAdapter = { - editorId: 'test', - editorName: 'Test Editor', - capabilities: { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'partial', - }, - detect: vi.fn(), - injectPrompt: vi.fn(), - readChatHistory: vi.fn(), - }; - - expect(() => { - requireMethod(adapter, 'readChatHistory', 'canReadChatHistory'); - }).not.toThrow(); - }); - - // Requirement 6.6: System provides clear error messages for unsupported operations - it('should throw clear error when method is missing', () => { - const adapter: IEditorAdapter = { - editorId: 'test', - editorName: 'Test Editor', - capabilities: { - canInjectPrompt: true, - canReadChatHistory: true, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'partial', - }, - detect: vi.fn(), - injectPrompt: vi.fn(), - // readChatHistory is missing - }; - - expect(() => { - requireMethod(adapter, 'readChatHistory', 'canReadChatHistory'); - }).toThrow( - 'Editor Test Editor claims to support \'canReadChatHistory\' but does not implement readChatHistory() method' - ); - }); - - it('should throw error when method is not a function', () => { - const adapter: any = { - editorId: 'test', - editorName: 'Test Editor', - capabilities: { - canReadChatHistory: true, - syncLevel: 'partial', - }, - detect: vi.fn(), - injectPrompt: vi.fn(), - readChatHistory: 'not a function', - }; - - expect(() => { - requireMethod(adapter, 'readChatHistory', 'canReadChatHistory'); - }).toThrow('does not implement readChatHistory() method'); - }); - }); - - describe('formatAdapterError()', () => { - const mockAdapter: IEditorAdapter = { - editorId: 'test', - editorName: 'Test Editor', - capabilities: { - canInjectPrompt: true, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - }, - detect: vi.fn(), - injectPrompt: vi.fn(), - }; - - // Requirement 6.6: System provides clear error messages for unsupported operations - it('should format error with adapter name and operation', () => { - const error = new Error('Something went wrong'); - const formatted = formatAdapterError(mockAdapter, 'inject prompt', error); - - expect(formatted).toContain('Failed to inject prompt'); - expect(formatted).toContain('Test Editor'); - expect(formatted).toContain('test'); - expect(formatted).toContain('Something went wrong'); - }); - - it('should handle Error objects', () => { - const error = new Error('Test error message'); - const formatted = formatAdapterError(mockAdapter, 'detect editor', error); - - expect(formatted).toContain('Test error message'); - }); - - it('should handle non-Error exceptions', () => { - const formatted = formatAdapterError(mockAdapter, 'test operation', 'String error'); - - expect(formatted).toContain('String error'); - }); - - it('should include editor ID in parentheses', () => { - const formatted = formatAdapterError(mockAdapter, 'test', new Error('error')); - - expect(formatted).toMatch(/Test Editor \(test\)/); - }); - }); - - describe('createAdapterError()', () => { - it('should create structured error with all fields', () => { - const error = createAdapterError( - EditorAdapterErrorType.COMMAND_EXECUTION_FAILED, - 'Command failed', - { command: 'test.command' } - ); - - expect(error.success).toBe(false); - expect(error.error).toBe('Command failed'); - expect(error.errorCode).toBe(EditorAdapterErrorType.COMMAND_EXECUTION_FAILED); - expect(error.details).toEqual({ command: 'test.command' }); - }); - - it('should create error without details', () => { - const error = createAdapterError( - EditorAdapterErrorType.EDITOR_NOT_FOUND, - 'Editor not found' - ); - - expect(error.success).toBe(false); - expect(error.error).toBe('Editor not found'); - expect(error.errorCode).toBe(EditorAdapterErrorType.EDITOR_NOT_FOUND); - expect(error.details).toBeUndefined(); - }); - - it('should support all error types', () => { - const errorTypes = [ - EditorAdapterErrorType.COMMAND_EXECUTION_FAILED, - EditorAdapterErrorType.EDITOR_NOT_FOUND, - EditorAdapterErrorType.UNSUPPORTED_OPERATION, - EditorAdapterErrorType.CAPABILITY_CHECK_FAILED, - EditorAdapterErrorType.UNKNOWN_ERROR, - ]; - - errorTypes.forEach((type) => { - const error = createAdapterError(type, 'Test message'); - expect(error.errorCode).toBe(type); - }); - }); - }); - - describe('executeWithCapabilityCheck()', () => { - const createMockAdapter = (capabilities: Partial): IEditorAdapter => ({ - editorId: 'test', - editorName: 'Test Editor', - capabilities: { - canInjectPrompt: false, - canReadChatHistory: false, - canStreamAssistantTokens: false, - canReadDiffArtifacts: false, - canPreventAutoApply: false, - syncLevel: 'control-only', - ...capabilities, - }, - detect: vi.fn(), - injectPrompt: vi.fn(), - }); - - // Requirement 6.4: Always fails safe when operations cannot be completed - it('should execute operation when capability is present', async () => { - const adapter = createMockAdapter({ canReadChatHistory: true }); - const operation = vi.fn().mockResolvedValue('success'); - - const result = await executeWithCapabilityCheck( - adapter, - 'canReadChatHistory', - 'reading chat history', - operation - ); - - expect(result).toBe('success'); - expect(operation).toHaveBeenCalled(); - }); - - // Requirement 6.6: System provides clear error messages for unsupported operations - it('should throw formatted error when capability is missing', async () => { - const adapter = createMockAdapter({ canReadChatHistory: false }); - const operation = vi.fn().mockResolvedValue('success'); - - await expect( - executeWithCapabilityCheck( - adapter, - 'canReadChatHistory', - 'reading chat history', - operation - ) - ).rejects.toThrow('Failed to reading chat history for editor Test Editor'); - - expect(operation).not.toHaveBeenCalled(); - }); - - it('should propagate operation errors with formatting', async () => { - const adapter = createMockAdapter({ canReadChatHistory: true }); - const operation = vi.fn().mockRejectedValue(new Error('Operation failed')); - - await expect( - executeWithCapabilityCheck( - adapter, - 'canReadChatHistory', - 'reading chat history', - operation - ) - ).rejects.toThrow('Failed to reading chat history for editor Test Editor'); - }); - - it('should return operation result on success', async () => { - const adapter = createMockAdapter({ canInjectPrompt: true }); - const operation = vi.fn().mockResolvedValue({ data: 'test' }); - - const result = await executeWithCapabilityCheck( - adapter, - 'canInjectPrompt', - 'injecting prompt', - operation - ); - - expect(result).toEqual({ data: 'test' }); - }); - }); - - describe('EditorAdapterErrorType enum', () => { - it('should have all required error types', () => { - expect(EditorAdapterErrorType.COMMAND_EXECUTION_FAILED).toBe('COMMAND_EXECUTION_FAILED'); - expect(EditorAdapterErrorType.EDITOR_NOT_FOUND).toBe('EDITOR_NOT_FOUND'); - expect(EditorAdapterErrorType.UNSUPPORTED_OPERATION).toBe('UNSUPPORTED_OPERATION'); - expect(EditorAdapterErrorType.CAPABILITY_CHECK_FAILED).toBe('CAPABILITY_CHECK_FAILED'); - expect(EditorAdapterErrorType.UNKNOWN_ERROR).toBe('UNKNOWN_ERROR'); - }); - }); -}); diff --git a/packages/vscode-extension/src/editors/adapters/errors.ts b/packages/vscode-extension/src/editors/adapters/errors.ts index 8a11bfb..96612f0 100644 --- a/packages/vscode-extension/src/editors/adapters/errors.ts +++ b/packages/vscode-extension/src/editors/adapters/errors.ts @@ -28,22 +28,22 @@ export interface EditorAdapterError { /** Machine-readable error code */ errorCode: EditorAdapterErrorType; /** Additional context for debugging */ - details?: any; + details?: unknown; } /** * Safe command execution wrapper that catches exceptions and returns error results. - * + * * Safety: Never throws exceptions. Always returns a PromptInjectionResult with * clear error messages if the command fails. - * + * * @param command - VS Code command to execute * @param args - Arguments to pass to the command * @returns PromptInjectionResult indicating success or failure */ export async function safeExecuteCommand( command: string, - ...args: any[] + ...args: unknown[] ): Promise { try { await vscode.commands.executeCommand(command, ...args); @@ -63,10 +63,10 @@ export async function safeExecuteCommand( /** * Check if an adapter has a specific capability before attempting an operation. - * + * * Safety: Prevents invalid operations by checking capabilities first. * Throws a clear error if the capability is not supported. - * + * * @param adapter - The editor adapter to check * @param capability - The capability key to check * @param operationName - Human-readable name of the operation (for error messages) @@ -78,22 +78,22 @@ export function requireCapability( operationName: string ): void { const hasCapability = adapter.capabilities[capability]; - + if (!hasCapability) { throw new Error( `Editor ${adapter.editorName} does not support ${operationName}. ` + - `Capability '${capability}' is not available. ` + - `Sync level: ${adapter.capabilities.syncLevel}` + `Capability '${capability}' is not available. ` + + `Sync level: ${adapter.capabilities.syncLevel}` ); } } /** * Check if an adapter has implemented an optional method. - * + * * Safety: Ensures that adapters claiming a capability actually implement * the corresponding method. - * + * * @param adapter - The editor adapter to check * @param methodName - The method name to check * @param capability - The capability that should enable this method @@ -105,18 +105,18 @@ export function requireMethod( capability: keyof IEditorAdapter['capabilities'] ): void { const method = adapter[methodName]; - + if (!method || typeof method !== 'function') { throw new Error( `Editor ${adapter.editorName} claims to support '${String(capability)}' ` + - `but does not implement ${String(methodName)}() method` + `but does not implement ${String(methodName)}() method` ); } } /** * Format an error message with context about the adapter and operation. - * + * * @param adapter - The editor adapter that encountered the error * @param operation - The operation that failed * @param error - The error that occurred @@ -128,7 +128,7 @@ export function formatAdapterError( error: unknown ): string { const errorMessage = error instanceof Error ? error.message : String(error); - + return ( `Failed to ${operation} for editor ${adapter.editorName} (${adapter.editorId}): ` + `${errorMessage}` @@ -137,7 +137,7 @@ export function formatAdapterError( /** * Create a structured error result for adapter operations. - * + * * @param errorType - The type of error that occurred * @param message - Human-readable error message * @param details - Optional additional context @@ -146,7 +146,7 @@ export function formatAdapterError( export function createAdapterError( errorType: EditorAdapterErrorType, message: string, - details?: any + details?: unknown ): EditorAdapterError { return { success: false, @@ -158,9 +158,9 @@ export function createAdapterError( /** * Safely execute an operation that requires a specific capability. - * + * * This combines capability checking with safe execution and error formatting. - * + * * @param adapter - The editor adapter to use * @param capability - The required capability * @param operationName - Human-readable operation name diff --git a/packages/vscode-extension/src/editors/adapters/types.ts b/packages/vscode-extension/src/editors/adapters/types.ts index e3ae200..3806ace 100644 --- a/packages/vscode-extension/src/editors/adapters/types.ts +++ b/packages/vscode-extension/src/editors/adapters/types.ts @@ -82,7 +82,7 @@ export interface DiffArtifact { /** * Common interface that all editor adapters must implement. - * + * * Safety: All methods use only public VS Code APIs and return result objects (never throw). */ export interface IEditorAdapter { diff --git a/packages/vscode-extension/src/extension.error-handling.test.ts b/packages/vscode-extension/src/extension.error-handling.test.ts deleted file mode 100644 index f093339..0000000 --- a/packages/vscode-extension/src/extension.error-handling.test.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { GitIntegrationModuleImpl } from './git/GitIntegrationModule'; -import { DiffGeneratorImpl } from './diff/DiffGenerator'; - -// Mock vscode module -vi.mock('vscode', () => ({ - window: { - createOutputChannel: vi.fn(() => ({ - appendLine: vi.fn(), - dispose: vi.fn(), - })), - showErrorMessage: vi.fn(), - showInformationMessage: vi.fn(), - }, - workspace: { - workspaceFolders: [], - asRelativePath: vi.fn((path: string) => { - const parts = path.split('/'); - return parts[parts.length - 1]; - }), - textDocuments: [], - }, - commands: { - registerCommand: vi.fn(() => ({ dispose: vi.fn() })), - }, -})); - -// Mock simple-git -vi.mock('simple-git', () => { - const mockGit = { - revparse: vi.fn(), - show: vi.fn(), - }; - - return { - default: vi.fn(() => mockGit), - __mockGit: mockGit, - }; -}); - -// Mock fs/promises -vi.mock('fs/promises', () => ({ - readFile: vi.fn(), - stat: vi.fn(), -})); - -describe('VS Code Extension Error Handling', () => { - let gitModule: GitIntegrationModuleImpl; - let diffGenerator: DiffGeneratorImpl; - let mockGit: any; - let mockFs: any; - - beforeEach(async () => { - gitModule = new GitIntegrationModuleImpl(); - diffGenerator = new DiffGeneratorImpl(); - - // Get mock instances - const simpleGit = await import('simple-git'); - mockGit = (simpleGit as any).__mockGit; - - const fs = await import('fs/promises'); - mockFs = fs; - - // Reset mocks - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - describe('Git Error Handling', () => { - it('should handle Git repository not found error', async () => { - mockGit.revparse.mockRejectedValue(new Error('Not a git repository')); - - const result = await gitModule.initialize('/not/a/repo'); - - expect(result).toBe(false); - // Should not throw, should handle gracefully - }); - - it('should handle Git permission denied error', async () => { - mockGit.revparse.mockRejectedValue(new Error('Permission denied')); - - const result = await gitModule.initialize('/no/permission'); - - expect(result).toBe(false); - }); - - it('should handle Git command timeout', async () => { - mockGit.revparse.mockRejectedValue(new Error('Command timeout')); - - const result = await gitModule.initialize('/timeout/repo'); - - expect(result).toBe(false); - }); - - it('should handle Git show command failure', async () => { - mockGit.revparse.mockResolvedValue('/repo\n'); - await gitModule.initialize('/repo'); - - mockGit.show.mockRejectedValue(new Error('Git show failed')); - - const content = await gitModule.getHeadVersion('/repo/file.ts'); - - expect(content).toBe(''); - // Should not throw, should return empty string - }); - - it('should handle corrupted Git repository', async () => { - mockGit.revparse.mockRejectedValue(new Error('fatal: not a git repository')); - - const result = await gitModule.initialize('/corrupted/repo'); - - expect(result).toBe(false); - }); - - it('should continue operation after Git error', async () => { - mockGit.revparse.mockResolvedValue('/repo\n'); - await gitModule.initialize('/repo'); - - // First call fails - mockGit.show.mockRejectedValueOnce(new Error('Network error')); - const content1 = await gitModule.getHeadVersion('/repo/file1.ts'); - expect(content1).toBe(''); - - // Second call succeeds - mockGit.show.mockResolvedValueOnce('file content'); - const content2 = await gitModule.getHeadVersion('/repo/file2.ts'); - expect(content2).toBe('file content'); - }); - }); - - describe('File Read Error Handling', () => { - it('should handle file not found error', async () => { - mockFs.readFile.mockRejectedValue(new Error('ENOENT: no such file or directory')); - - const payload = await diffGenerator.generateDiff('/nonexistent/file.ts', ''); - - expect(payload).toBeNull(); - // Should not throw, should return null - }); - - it('should handle file permission denied error', async () => { - mockFs.readFile.mockRejectedValue(new Error('EACCES: permission denied')); - - const payload = await diffGenerator.generateDiff('/no/permission/file.ts', ''); - - expect(payload).toBeNull(); - }); - - it('should handle file encoding error', async () => { - mockFs.readFile.mockRejectedValue(new Error('Invalid encoding')); - - const payload = await diffGenerator.generateDiff('/invalid/encoding.ts', ''); - - expect(payload).toBeNull(); - }); - - it('should handle file read timeout', async () => { - mockFs.readFile.mockRejectedValue(new Error('Read timeout')); - - const payload = await diffGenerator.generateDiff('/timeout/file.ts', ''); - - expect(payload).toBeNull(); - }); - - it('should handle file deleted during read', async () => { - mockFs.readFile.mockRejectedValue(new Error('File was deleted')); - - const payload = await diffGenerator.generateDiff('/deleted/file.ts', ''); - - expect(payload).toBeNull(); - }); - - it('should continue operation after file read error', async () => { - // First call fails - stat succeeds but read fails - mockFs.stat.mockResolvedValueOnce({ size: 1000 }); - mockFs.readFile.mockRejectedValueOnce(new Error('Read error')); - const payload1 = await diffGenerator.generateDiff('/error/file1.ts', ''); - expect(payload1).toBeNull(); - - // Second call succeeds - mockFs.stat.mockResolvedValueOnce({ size: 1000 }); - mockFs.readFile.mockResolvedValueOnce(Buffer.from('file content')); - const payload2 = await diffGenerator.generateDiff('/success/file2.ts', ''); - expect(payload2).not.toBeNull(); - expect(payload2?.modifiedFile).toBe('file content'); - }); - }); -}); diff --git a/packages/vscode-extension/src/extension.performance.test.ts b/packages/vscode-extension/src/extension.performance.test.ts deleted file mode 100644 index e0de141..0000000 --- a/packages/vscode-extension/src/extension.performance.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import * as fs from 'fs/promises'; -import * as path from 'path'; -import * as os from 'os'; -import simpleGit, { SimpleGit } from 'simple-git'; - -/** - * End-to-end performance tests - * Feature: git-integration-diffing - * - * Note: These tests simulate the full pipeline without VS Code dependencies - */ - -describe('End-to-End Performance Tests', () => { - let tempDir: string; - let git: SimpleGit; - - beforeEach(async () => { - // Create temporary directory for test repository - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'e2e-perf-test-')); - - // Initialize Git repository - git = simpleGit(tempDir); - await git.init(); - await git.addConfig('user.name', 'Test User'); - await git.addConfig('user.email', 'test@example.com'); - }); - - afterEach(async () => { - await fs.rm(tempDir, { recursive: true, force: true }); - }); - - /** - * Test end-to-end latency is under 2000ms - * Validates: Requirements 7.5 - */ - it('end-to-end pipeline completes within 2000ms', async () => { - // Create and commit a test file - const fileName = 'test.txt'; - const filePath = path.join(tempDir, fileName); - const originalContent = Array(1000).fill('original line').join('\n'); - - await fs.writeFile(filePath, originalContent); - - await git.add(fileName); - await git.commit('Initial commit'); - - // Modify the file - const modifiedContent = Array(1000).fill('modified line').join('\n'); - await fs.writeFile(filePath, modifiedContent); - - // Measure end-to-end pipeline - const startTime = Date.now(); - - // Step 1: Fetch HEAD version (Git operation) - const headContent = await git.show([`HEAD:${fileName}`]); - - // Step 2: Read current file (Diff generation) - const currentContent = await fs.readFile(filePath, 'utf-8'); - - // Step 3: Create payload - const payload = { - fileName: fileName, - originalFile: headContent, - modifiedFile: currentContent, - isDirty: false, - timestamp: Date.now(), - }; - - const elapsed = Date.now() - startTime; - - // Verify total time is under 2000ms - expect(elapsed).toBeLessThan(2000); - expect(payload.originalFile).toBe(originalContent); - expect(payload.modifiedFile).toBe(modifiedContent); - }); - - /** - * Test pipeline with various file sizes - * Validates: Requirements 7.1, 7.2, 7.3, 7.4, 7.5 - */ - it('handles various file sizes within performance requirements', async () => { - const fileSizes = [100, 500, 1000, 5000]; - - for (const numLines of fileSizes) { - const fileName = `test-${numLines}.txt`; - const filePath = path.join(tempDir, fileName); - const content = Array(numLines).fill('test line').join('\n'); - - await fs.writeFile(filePath, content); - - await git.add(fileName); - await git.commit(`Add ${fileName}`); - - // Modify file - const modifiedContent = Array(numLines).fill('modified line').join('\n'); - await fs.writeFile(filePath, modifiedContent); - - // Measure pipeline - const startTime = Date.now(); - const headContent = await git.show([`HEAD:${fileName}`]); - const currentContent = await fs.readFile(filePath, 'utf-8'); - const payload = { - fileName: fileName, - originalFile: headContent, - modifiedFile: currentContent, - isDirty: false, - timestamp: Date.now(), - }; - const elapsed = Date.now() - startTime; - - // Should be well under 2000ms - expect(elapsed).toBeLessThan(2000); - expect(payload.modifiedFile).toBe(modifiedContent); - } - }); -}); diff --git a/packages/vscode-extension/src/extension.properties.test.ts b/packages/vscode-extension/src/extension.properties.test.ts deleted file mode 100644 index a009501..0000000 --- a/packages/vscode-extension/src/extension.properties.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import * as fc from 'fast-check'; -import { SyncFullContextMessage, FileContextPayload } from '@codelink/protocol'; - -describe('Extension - Property-Based Tests', () => { - // Feature: git-integration-diffing, Property 12: Message structure completeness - it('Property 12: SYNC_FULL_CONTEXT message should include all required fields', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }), - fc.integer({ min: 0 }), - fc.string({ minLength: 1 }), - fc.string(), - fc.string(), - fc.boolean(), - fc.integer({ min: 0 }), - (id, timestamp, fileName, originalFile, modifiedFile, isDirty, payloadTimestamp) => { - // Create FileContextPayload - const payload: FileContextPayload = { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp: payloadTimestamp, - }; - - // Create SYNC_FULL_CONTEXT message - const message: SyncFullContextMessage = { - id, - timestamp, - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - // Verify all required fields are present - expect(message.id).toBeDefined(); - expect(message.timestamp).toBeDefined(); - expect(message.type).toBe('SYNC_FULL_CONTEXT'); - expect(message.payload).toBeDefined(); - - // Verify payload fields - expect(message.payload.fileName).toBeDefined(); - expect(message.payload.originalFile).toBeDefined(); - expect(message.payload.modifiedFile).toBeDefined(); - expect(message.payload.isDirty).toBeDefined(); - expect(message.payload.timestamp).toBeDefined(); - - // Verify field types - expect(typeof message.id).toBe('string'); - expect(typeof message.timestamp).toBe('number'); - expect(typeof message.type).toBe('string'); - expect(typeof message.payload.fileName).toBe('string'); - expect(typeof message.payload.originalFile).toBe('string'); - expect(typeof message.payload.modifiedFile).toBe('string'); - expect(typeof message.payload.isDirty).toBe('boolean'); - expect(typeof message.payload.timestamp).toBe('number'); - } - ), - { numRuns: 100 } - ); - }); - - it('Property: FileContextPayload should preserve all field values', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }), - fc.string(), - fc.string(), - fc.boolean(), - fc.integer({ min: 0 }), - (fileName, originalFile, modifiedFile, isDirty, timestamp) => { - const payload: FileContextPayload = { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp, - }; - - // Verify values are preserved exactly - expect(payload.fileName).toBe(fileName); - expect(payload.originalFile).toBe(originalFile); - expect(payload.modifiedFile).toBe(modifiedFile); - expect(payload.isDirty).toBe(isDirty); - expect(payload.timestamp).toBe(timestamp); - } - ), - { numRuns: 100 } - ); - }); - - it('Property: Message structure should be serializable to JSON', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }), - fc.integer({ min: 0 }), - fc.string({ minLength: 1 }), - fc.string(), - fc.string(), - fc.boolean(), - fc.integer({ min: 0 }), - (id, timestamp, fileName, originalFile, modifiedFile, isDirty, payloadTimestamp) => { - const payload: FileContextPayload = { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp: payloadTimestamp, - }; - - const message: SyncFullContextMessage = { - id, - timestamp, - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - // Serialize to JSON and back - const json = JSON.stringify(message); - const parsed = JSON.parse(json); - - // Verify structure is preserved - expect(parsed.id).toBe(message.id); - expect(parsed.timestamp).toBe(message.timestamp); - expect(parsed.type).toBe(message.type); - expect(parsed.payload.fileName).toBe(message.payload.fileName); - expect(parsed.payload.originalFile).toBe(message.payload.originalFile); - expect(parsed.payload.modifiedFile).toBe(message.payload.modifiedFile); - expect(parsed.payload.isDirty).toBe(message.payload.isDirty); - expect(parsed.payload.timestamp).toBe(message.payload.timestamp); - } - ), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/vscode-extension/src/extension.test.ts b/packages/vscode-extension/src/extension.test.ts deleted file mode 100644 index d731fe7..0000000 --- a/packages/vscode-extension/src/extension.test.ts +++ /dev/null @@ -1,577 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import * as vscode from 'vscode'; -import { FileWatcher } from './watcher/FileWatcher'; -import { GitIntegrationModuleImpl } from './git/GitIntegrationModule'; -import { DiffGeneratorImpl } from './diff/DiffGenerator'; -import { WebSocketClient } from './websocket/WebSocketClient'; -import { SyncFullContextMessage } from '@codelink/protocol'; -import { activate, deactivate, getEditorRegistry, resetEditorRegistry } from './extension'; -import { EditorRegistry } from './editors/adapters/EditorRegistry'; - -// Mock fs/promises module -vi.mock('fs/promises', () => ({ - readFile: vi.fn(), - stat: vi.fn(), -})); - -// Mock vscode module -vi.mock('vscode', () => ({ - window: { - onDidChangeActiveTextEditor: vi.fn(), - activeTextEditor: undefined, - createOutputChannel: vi.fn(() => ({ - appendLine: vi.fn(), - dispose: vi.fn(), - })), - showErrorMessage: vi.fn(), - showInformationMessage: vi.fn(), - }, - workspace: { - onDidChangeTextDocument: vi.fn(), - workspaceFolders: [], - textDocuments: [], - asRelativePath: vi.fn((path: string) => path.replace('/workspace/', '')), - }, - commands: { - registerCommand: vi.fn(() => ({ dispose: vi.fn() })), - executeCommand: vi.fn(), - getCommands: vi.fn(() => Promise.resolve([])), - }, -})); - -describe('VS Code Extension Integration', () => { - let fileWatcher: FileWatcher; - let gitModule: GitIntegrationModuleImpl; - let diffGenerator: DiffGeneratorImpl; - let wsClient: WebSocketClient; - let mockEditorChangeCallback: (editor: vscode.TextEditor | undefined) => void; - let mockDocumentChangeCallback: (event: vscode.TextDocumentChangeEvent) => void; - - beforeEach(() => { - // Set up workspace - (vscode.workspace.workspaceFolders as any) = [ - { uri: { fsPath: '/workspace' } }, - ]; - - // Capture VS Code event callbacks - vi.mocked(vscode.window.onDidChangeActiveTextEditor).mockImplementation((callback) => { - mockEditorChangeCallback = callback; - return { dispose: vi.fn() }; - }); - - vi.mocked(vscode.workspace.onDidChangeTextDocument).mockImplementation((callback) => { - mockDocumentChangeCallback = callback; - return { dispose: vi.fn() }; - }); - - // Initialize components - fileWatcher = new FileWatcher(); - gitModule = new GitIntegrationModuleImpl(); - diffGenerator = new DiffGeneratorImpl(); - wsClient = new WebSocketClient(); - }); - - afterEach(() => { - fileWatcher.dispose(); - wsClient.disconnect(); - vi.clearAllMocks(); - }); - - describe('end-to-end pipeline', () => { - beforeEach(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - vi.useRealTimers(); - }); - - it('should process file change through entire pipeline', async () => { - // Mock Git module - vi.spyOn(gitModule, 'getHeadVersion').mockResolvedValue('original content'); - - // Mock file system - const mockFs = await import('fs/promises'); - vi.mocked(mockFs.readFile).mockResolvedValue(Buffer.from('modified content')); - vi.mocked(mockFs.stat).mockResolvedValue({ size: 100 } as any); - - // Mock WebSocket - const sendSpy = vi.spyOn(wsClient, 'send'); - - // Initialize file watcher with pipeline callback - fileWatcher.initialize(); - fileWatcher.onFileChanged = async (filePath: string) => { - const headContent = await gitModule.getHeadVersion(filePath); - const payload = await diffGenerator.generateDiff(filePath, headContent); - - if (payload) { - const message: SyncFullContextMessage = { - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - wsClient.send(message); - } - }; - - // Simulate file change - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - - mockEditorChangeCallback(mockEditor); - - // Wait for async operations - await vi.runAllTimersAsync(); - - // Verify message was sent - expect(sendSpy).toHaveBeenCalled(); - const sentMessage = sendSpy.mock.calls[0][0] as SyncFullContextMessage; - expect(sentMessage.type).toBe('SYNC_FULL_CONTEXT'); - expect(sentMessage.payload.fileName).toContain('test.ts'); - expect(sentMessage.payload.originalFile).toBe('original content'); - expect(sentMessage.payload.modifiedFile).toBe('modified content'); - }); - - it('should handle untracked files correctly', async () => { - // Mock Git module to return empty string for untracked file - vi.spyOn(gitModule, 'getHeadVersion').mockResolvedValue(''); - - // Mock file system - const mockFs = await import('fs/promises'); - vi.mocked(mockFs.readFile).mockResolvedValue(Buffer.from('new file content')); - vi.mocked(mockFs.stat).mockResolvedValue({ size: 100 } as any); - - // Mock WebSocket - const sendSpy = vi.spyOn(wsClient, 'send'); - - // Initialize file watcher with pipeline callback - fileWatcher.initialize(); - fileWatcher.onFileChanged = async (filePath: string) => { - const headContent = await gitModule.getHeadVersion(filePath); - const payload = await diffGenerator.generateDiff(filePath, headContent); - - if (payload) { - const message: SyncFullContextMessage = { - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - wsClient.send(message); - } - }; - - // Simulate file change - const mockEditor = { - document: { - uri: { fsPath: '/workspace/newfile.ts' }, - }, - } as vscode.TextEditor; - - mockEditorChangeCallback(mockEditor); - - // Wait for async operations - await vi.runAllTimersAsync(); - - // Verify message was sent with empty originalFile - expect(sendSpy).toHaveBeenCalled(); - const sentMessage = sendSpy.mock.calls[0][0] as SyncFullContextMessage; - expect(sentMessage.payload.originalFile).toBe(''); - expect(sentMessage.payload.modifiedFile).toBe('new file content'); - }); - - it('should handle Git errors gracefully', async () => { - // Mock Git module to throw error - vi.spyOn(gitModule, 'getHeadVersion').mockRejectedValue(new Error('Git error')); - - // Mock file system - const mockFs = await import('fs/promises'); - vi.mocked(mockFs.readFile).mockResolvedValue(Buffer.from('content')); - - // Mock WebSocket - const sendSpy = vi.spyOn(wsClient, 'send'); - - // Initialize file watcher with error handling - fileWatcher.initialize(); - fileWatcher.onFileChanged = async (filePath: string) => { - try { - const headContent = await gitModule.getHeadVersion(filePath); - const payload = await diffGenerator.generateDiff(filePath, headContent); - - if (payload) { - const message: SyncFullContextMessage = { - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - wsClient.send(message); - } - } catch (error) { - // Error should be caught and logged - console.error('Pipeline error:', error); - } - }; - - // Simulate file change - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - - mockEditorChangeCallback(mockEditor); - - // Wait for async operations - await vi.runAllTimersAsync(); - - // Verify no message was sent due to error - expect(sendSpy).not.toHaveBeenCalled(); - }); - - it('should handle file read errors gracefully', async () => { - // Mock Git module - vi.spyOn(gitModule, 'getHeadVersion').mockResolvedValue('original'); - - // Mock file system to throw error - const mockFs = await import('fs/promises'); - vi.mocked(mockFs.readFile).mockRejectedValue(new Error('File read error')); - vi.mocked(mockFs.stat).mockResolvedValue({ size: 100 } as any); - - // Mock WebSocket - const sendSpy = vi.spyOn(wsClient, 'send'); - - // Initialize file watcher with error handling - fileWatcher.initialize(); - fileWatcher.onFileChanged = async (filePath: string) => { - try { - const headContent = await gitModule.getHeadVersion(filePath); - const payload = await diffGenerator.generateDiff(filePath, headContent); - - if (payload) { - const message: SyncFullContextMessage = { - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - wsClient.send(message); - } - } catch (error) { - // Error should be caught - console.error('Pipeline error:', error); - } - }; - - // Simulate file change - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - - mockEditorChangeCallback(mockEditor); - - // Wait for async operations - await vi.runAllTimersAsync(); - - // Verify no message was sent due to error - expect(sendSpy).not.toHaveBeenCalled(); - }); - - it('should respect debounce timing', async () => { - // Mock Git and file system - vi.spyOn(gitModule, 'getHeadVersion').mockResolvedValue('original'); - const mockFs = await import('fs/promises'); - vi.mocked(mockFs.readFile).mockResolvedValue(Buffer.from('modified')); - vi.mocked(mockFs.stat).mockResolvedValue({ size: 100 } as any); - - // Mock WebSocket - const sendSpy = vi.spyOn(wsClient, 'send'); - - // Initialize file watcher - fileWatcher.initialize(); - fileWatcher.onFileChanged = async (filePath: string) => { - const headContent = await gitModule.getHeadVersion(filePath); - const payload = await diffGenerator.generateDiff(filePath, headContent); - - if (payload) { - const message: SyncFullContextMessage = { - id: 'test-id', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - wsClient.send(message); - } - }; - - // Simulate editor change first - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - // Wait for first message - await vi.runAllTimersAsync(); - sendSpy.mockClear(); - - // Simulate multiple rapid document changes - const mockEvent = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(500); - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(500); - - mockDocumentChangeCallback(mockEvent); - - // Should not have sent yet - expect(sendSpy).not.toHaveBeenCalled(); - - // Advance past debounce period - await vi.advanceTimersByTimeAsync(1000); - - // Should have sent exactly once - expect(sendSpy).toHaveBeenCalledTimes(1); - }); - }); -}); - -describe('Extension Activation with Editor Registry', () => { - let mockContext: vscode.ExtensionContext; - - beforeEach(() => { - // Set up workspace - (vscode.workspace.workspaceFolders as any) = [ - { uri: { fsPath: '/workspace' } }, - ]; - - // Create mock extension context - mockContext = { - subscriptions: [], - globalState: { - get: vi.fn() as any, - update: vi.fn(), - keys: vi.fn(() => []), - setKeysForSync: vi.fn(), - }, - workspaceState: { - get: vi.fn() as any, - update: vi.fn(), - keys: vi.fn(() => []), - }, - extensionPath: '/extension', - extensionUri: {} as any, - environmentVariableCollection: {} as any, - extensionMode: 3, - storageUri: undefined, - storagePath: undefined, - globalStorageUri: {} as any, - globalStoragePath: '/global', - logUri: {} as any, - logPath: '/logs', - asAbsolutePath: vi.fn((path: string) => `/extension/${path}`), - secrets: {} as any, - extension: {} as any, - languageModelAccessInformation: {} as any, - }; - - // Mock VS Code commands to return some test commands - vi.mocked(vscode.commands.getCommands).mockResolvedValue([ - 'kiro.chat.sendMessage', - 'kiro.openSettings', - 'continue.continueGUIView.focusContinueInput', - 'continue.openSettings', - ]); - }); - - afterEach(() => { - deactivate(); - resetEditorRegistry(); - vi.clearAllMocks(); - }); - - it('should initialize editor registry with all adapters', async () => { - await activate(mockContext); - - const registry = getEditorRegistry(); - expect(registry).toBeDefined(); - expect(registry).toBeInstanceOf(EditorRegistry); - - // Verify all 4 adapters are registered - const allAdapters = registry!.getAllAdapters(); - expect(allAdapters).toHaveLength(4); - - const adapterIds = allAdapters.map((adapter) => adapter.editorId); - expect(adapterIds).toContain('continue'); - expect(adapterIds).toContain('kiro'); - expect(adapterIds).toContain('cursor'); - expect(adapterIds).toContain('antigravity'); - }); - - it('should run detection on activation', async () => { - await activate(mockContext); - - const registry = getEditorRegistry(); - expect(registry).toBeDefined(); - - // Verify detection was run by checking that getCommands was called - expect(vscode.commands.getCommands).toHaveBeenCalled(); - - // Verify we can get detection results - const continueAdapter = registry!.getAdapter('continue'); - expect(continueAdapter).toBeDefined(); - expect(continueAdapter!.editorId).toBe('continue'); - }); - - it('should make registry accessible from context', async () => { - await activate(mockContext); - - // Verify registry was stored in global state - expect(mockContext.globalState.update).toHaveBeenCalledWith( - 'editorRegistry', - expect.any(EditorRegistry) - ); - }); - - it('should detect installed editors correctly', async () => { - // Mock commands to show Continue and Kiro are installed - vi.mocked(vscode.commands.getCommands).mockResolvedValue([ - 'continue.continueGUIView.focusContinueInput', - 'continue.openSettings', - 'kiro.chat.sendMessage', - 'kiro.openSettings', - ]); - - await activate(mockContext); - - const registry = getEditorRegistry(); - expect(registry).toBeDefined(); - - // Check detection results - const detectionResults = await registry!.detectAll(); - - // Continue should be detected as installed - const continueResult = detectionResults.get('continue'); - expect(continueResult?.isInstalled).toBe(true); - expect(continueResult?.availableCommands?.length).toBeGreaterThan(0); - - // Kiro should be detected as installed - const kiroResult = detectionResults.get('kiro'); - expect(kiroResult?.isInstalled).toBe(true); - - // Cursor should not be detected (no cursor commands) - const cursorResult = detectionResults.get('cursor'); - expect(cursorResult?.isInstalled).toBe(false); - - // Antigravity should not be detected (no antigravity commands) - const antigravityResult = detectionResults.get('antigravity'); - expect(antigravityResult?.isInstalled).toBe(false); - }); - - it('should select best available adapter based on sync level', async () => { - // Mock commands to show Continue (full sync) is installed - vi.mocked(vscode.commands.getCommands).mockResolvedValue([ - 'continue.continueGUIView.focusContinueInput', - 'kiro.chat.sendMessage', - ]); - - await activate(mockContext); - - const registry = getEditorRegistry(); - expect(registry).toBeDefined(); - - // Get best adapter - should prefer Continue (full sync) over Kiro (partial sync) - const bestAdapter = await registry!.getBestAdapter(); - expect(bestAdapter).toBeDefined(); - expect(bestAdapter!.editorId).toBe('continue'); - expect(bestAdapter!.capabilities.syncLevel).toBe('full'); - }); - - it('should handle no editors installed gracefully', async () => { - // Mock commands to show no AI editors are installed - vi.mocked(vscode.commands.getCommands).mockResolvedValue([ - 'workbench.action.openSettings', - 'editor.action.formatDocument', - ]); - - await activate(mockContext); - - const registry = getEditorRegistry(); - expect(registry).toBeDefined(); - - // Get best adapter - Kiro is always installed since we ARE Kiro - // So we should get Kiro adapter even when no other editors are installed - const bestAdapter = await registry!.getBestAdapter(); - expect(bestAdapter).toBeDefined(); - expect(bestAdapter!.editorId).toBe('kiro'); - }); - - it('should register cleanup in context subscriptions', async () => { - await activate(mockContext); - - // Verify that disposal logic was registered - expect(mockContext.subscriptions.length).toBeGreaterThan(0); - - // Find the disposal object that includes registry cleanup - const disposables = mockContext.subscriptions; - expect(disposables.some((d) => typeof d.dispose === 'function')).toBe(true); - }); - - it('should clear registry cache on deactivation', async () => { - await activate(mockContext); - - const registry = getEditorRegistry(); - expect(registry).toBeDefined(); - - // Run detection to populate cache - await registry!.detectAll(); - - // Deactivate extension - deactivate(); - - // Note: We can't directly verify cache was cleared since it's private, - // but we verify deactivate doesn't throw and completes successfully - expect(true).toBe(true); - }); - - it('should handle activation errors gracefully', async () => { - // Mock getCommands to throw an error - vi.mocked(vscode.commands.getCommands).mockRejectedValue( - new Error('Command query failed') - ); - - // Activation should not throw - await expect(activate(mockContext)).resolves.not.toThrow(); - - // Registry should still be initialized even if detection fails - const registry = getEditorRegistry(); - expect(registry).toBeDefined(); - }); - - it('should work without workspace folder', async () => { - // Remove workspace folders - (vscode.workspace.workspaceFolders as any) = undefined; - - // Activation should not throw - await expect(activate(mockContext)).resolves.not.toThrow(); - - // Registry should not be initialized without workspace - const registry = getEditorRegistry(); - expect(registry).toBeUndefined(); - }); -}); diff --git a/packages/vscode-extension/src/extension.ts b/packages/vscode-extension/src/extension.ts index a40da94..a06dd3d 100644 --- a/packages/vscode-extension/src/extension.ts +++ b/packages/vscode-extension/src/extension.ts @@ -2,7 +2,13 @@ import * as vscode from 'vscode'; import * as zlib from 'zlib'; import * as crypto from 'crypto'; import { promisify } from 'util'; -import { SyncFullContextMessage, FileContextPayload, InjectPromptMessage, InjectPromptResponseMessage, ProtocolMessage } from '@codelink/protocol'; +import { + SyncFullContextMessage, + FileContextPayload, + InjectPromptMessage, + InjectPromptResponse, + ProtocolMessage, +} from '@codelink/protocol'; import { FileWatcher } from './watcher/FileWatcher'; import { GitIntegrationModuleImpl } from './git/GitIntegrationModule'; import { DiffGeneratorImpl } from './diff/DiffGenerator'; @@ -63,46 +69,50 @@ async function initializeModules(context: vscode.ExtensionContext): Promise('relayServerUrl') || 'http://localhost:8080'; wsClient = new WebSocketClient(); wsClient.connect(relayServerUrl); outputChannel.appendLine(`WebSocket client connecting to ${relayServerUrl}`); @@ -134,10 +146,7 @@ async function initializeModules(context: vscode.ExtensionContext): Promise { fileWatcher.dispose(); wsClient.disconnect(); - // Clear editor registry cache on disposal - if (editorRegistry) { - editorRegistry.clearCache(); - } + editorRegistry.clearCache(); }, }); } @@ -164,85 +173,93 @@ async function handleIncomingMessage(message: ProtocolMessage): Promise { */ async function handlePromptInjection(message: InjectPromptMessage): Promise { const startTime = Date.now(); - outputChannel.appendLine(`[INFO] Handling prompt injection: "${message.prompt.substring(0, 50)}..."`); + outputChannel.appendLine( + `[INFO] Handling prompt injection: "${message.payload.prompt.substring(0, 50)}..."` + ); try { // Get the best available editor adapter const adapter = await editorRegistry.getBestAdapter(); if (!adapter) { - // No editor available - send error response - const errorResponse: InjectPromptResponseMessage = { + const errorResponse: InjectPromptResponse = { id: crypto.randomUUID(), timestamp: Date.now(), type: 'INJECT_PROMPT_RESPONSE', - success: false, - error: 'No AI editor is installed. Please install Continue, Kiro, Cursor, or Antigravity.', - originalRequestId: message.id, + originalId: message.id, + payload: { + success: false, + error: + 'No AI editor is installed. Please install Continue, Kiro, Cursor, or Antigravity.', + }, }; - wsClient.send(errorResponse); outputChannel.appendLine(`[ERROR] No AI editor available for prompt injection`); return; } - outputChannel.appendLine(`[INFO] Using editor: ${adapter.editorName} (${adapter.capabilities.syncLevel} sync)`); + outputChannel.appendLine( + `[INFO] Using editor: ${adapter.editorName} (${adapter.capabilities.syncLevel} sync)` + ); - // Check if the adapter supports prompt injection if (!adapter.capabilities.canInjectPrompt) { - const errorResponse: InjectPromptResponseMessage = { + const errorResponse: InjectPromptResponse = { id: crypto.randomUUID(), timestamp: Date.now(), type: 'INJECT_PROMPT_RESPONSE', - success: false, - error: `Editor ${adapter.editorName} does not support prompt injection`, - editorUsed: adapter.editorName, - originalRequestId: message.id, + originalId: message.id, + payload: { + success: false, + error: `Editor ${adapter.editorName} does not support prompt injection`, + editorUsed: adapter.editorName, + }, }; - wsClient.send(errorResponse); - outputChannel.appendLine(`[ERROR] Editor ${adapter.editorName} does not support prompt injection`); + outputChannel.appendLine( + `[ERROR] Editor ${adapter.editorName} does not support prompt injection` + ); return; } - // Inject the prompt - const result = await adapter.injectPrompt(message.prompt); + const result = await adapter.injectPrompt(message.payload.prompt); const elapsed = Date.now() - startTime; - // Send response back to mobile client - const response: InjectPromptResponseMessage = { + const response: InjectPromptResponse = { id: crypto.randomUUID(), timestamp: Date.now(), type: 'INJECT_PROMPT_RESPONSE', - success: result.success, - error: result.error, - editorUsed: adapter.editorName, - commandUsed: result.commandUsed, - originalRequestId: message.id, + originalId: message.id, + payload: { + success: result.success, + error: result.error, + editorUsed: adapter.editorName, + }, }; - wsClient.send(response); if (result.success) { - outputChannel.appendLine(`[INFO] Prompt injection successful (${elapsed}ms) using ${result.commandUsed}`); + outputChannel.appendLine( + `[INFO] Prompt injection successful (${elapsed}ms) using ${result.commandUsed}` + ); } else { outputChannel.appendLine(`[ERROR] Prompt injection failed (${elapsed}ms): ${result.error}`); } } catch (error) { const elapsed = Date.now() - startTime; - - // Send error response - const errorResponse: InjectPromptResponseMessage = { + const errorResponse: InjectPromptResponse = { id: crypto.randomUUID(), timestamp: Date.now(), type: 'INJECT_PROMPT_RESPONSE', - success: false, - error: `Unexpected error during prompt injection: ${error}`, - originalRequestId: message.id, + originalId: message.id, + payload: { + success: false, + error: `Unexpected error during prompt injection: ${error}`, + }, }; - wsClient.send(errorResponse); - outputChannel.appendLine(`[ERROR] Unexpected error during prompt injection (${elapsed}ms): ${error}`); + outputChannel.appendLine( + `[ERROR] Unexpected error during prompt injection (${elapsed}ms): ${error}` + ); } } @@ -252,7 +269,7 @@ async function handlePromptInjection(message: InjectPromptMessage): Promise { const pipelineStartTime = Date.now(); - + try { outputChannel.appendLine(`[INFO] File changed: ${filePath}`); @@ -262,7 +279,9 @@ async function handleFileChanged(filePath: string): Promise { try { headContent = await gitModule.getHeadVersion(filePath); const gitElapsed = Date.now() - gitStartTime; - outputChannel.appendLine(`[PERF] Git operation: ${gitElapsed}ms (HEAD content: ${headContent.length} bytes)`); + outputChannel.appendLine( + `[PERF] Git operation: ${gitElapsed}ms (HEAD content: ${headContent.length} bytes)` + ); } catch (error) { const gitElapsed = Date.now() - gitStartTime; outputChannel.appendLine(`[ERROR] Failed to fetch HEAD version (${gitElapsed}ms): ${error}`); @@ -273,7 +292,7 @@ async function handleFileChanged(filePath: string): Promise { const diffStartTime = Date.now(); const payload = await diffGenerator.generateDiff(filePath, headContent); const diffElapsed = Date.now() - diffStartTime; - + if (!payload) { outputChannel.appendLine(`[WARN] Failed to generate diff (${diffElapsed}ms), skipping`); return; @@ -287,7 +306,7 @@ async function handleFileChanged(filePath: string): Promise { const compressionStartTime = Date.now(); const compressedPayload = await compressPayloadIfNeeded(payload); const compressionElapsed = Date.now() - compressionStartTime; - + if (compressedPayload.compressed) { outputChannel.appendLine( `[PERF] Compression: ${compressionElapsed}ms (${compressedPayload.originalSize} → ${compressedPayload.compressedSize} bytes, ${compressedPayload.compressionRatio}% reduction)` @@ -317,14 +336,13 @@ async function handleFileChanged(filePath: string): Promise { // Log total pipeline time const totalElapsed = Date.now() - pipelineStartTime; outputChannel.appendLine(`[PERF] Total pipeline: ${totalElapsed}ms`); - + // Performance warning if total time exceeds 2000ms if (totalElapsed > 2000) { outputChannel.appendLine( `[WARN] Pipeline exceeded 2000ms threshold: ${totalElapsed}ms for ${payload.fileName}` ); } - } catch (error) { const totalElapsed = Date.now() - pipelineStartTime; outputChannel.appendLine(`[ERROR] Pipeline error (${totalElapsed}ms): ${error}`); @@ -350,11 +368,11 @@ export function deactivate() { /** * Get the editor registry instance. - * + * * This function provides access to the editor registry for other modules * that need to interact with AI editors (e.g., WebSocket handlers for * mobile prompt injection). - * + * * @returns The editor registry instance, or undefined if not initialized */ export function getEditorRegistry(): EditorRegistry | undefined { @@ -363,11 +381,11 @@ export function getEditorRegistry(): EditorRegistry | undefined { /** * Reset the editor registry (for testing purposes only). - * + * * @internal */ export function resetEditorRegistry(): void { - editorRegistry = undefined as any; + editorRegistry = undefined as unknown as EditorRegistry; } /** diff --git a/packages/vscode-extension/src/git/GitIntegrationModule.performance.test.ts b/packages/vscode-extension/src/git/GitIntegrationModule.performance.test.ts deleted file mode 100644 index c31c195..0000000 --- a/packages/vscode-extension/src/git/GitIntegrationModule.performance.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import * as fc from 'fast-check'; -import * as fs from 'fs/promises'; -import * as path from 'path'; -import * as os from 'os'; -import simpleGit, { SimpleGit } from 'simple-git'; - -/** - * Performance tests for Git Integration Module - * Feature: git-integration-diffing - * - * Note: These tests use simple-git directly to avoid VS Code API dependencies - */ - -describe('GitIntegrationModule Performance Tests', () => { - let tempDir: string; - let git: SimpleGit; - - beforeEach(async () => { - // Create temporary directory for test repository - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'git-perf-test-')); - - // Initialize Git repository - git = simpleGit(tempDir); - await git.init(); - await git.addConfig('user.name', 'Test User'); - await git.addConfig('user.email', 'test@example.com'); - }); - - afterEach(async () => { - // Clean up temp directory - await fs.rm(tempDir, { recursive: true, force: true }); - }); - - /** - * Property 23: Git operation performance - * For any typical file (under 10,000 lines), Git operations should complete within 500ms. - * Validates: Requirements 7.2 - */ - it('Property 23: Git operations complete within 500ms for typical files', async () => { - await fc.assert( - fc.asyncProperty( - fc.integer({ min: 10, max: 1000 }), // Number of lines - async (numLines) => { - // Create a test file with specified number of lines - const fileName = `test-${numLines}.txt`; - const filePath = path.join(tempDir, fileName); - const content = Array(numLines).fill('test line content').join('\n'); - - await fs.writeFile(filePath, content); - - // Add and commit the file - await git.add(fileName); - await git.commit('Add test file'); - - // Measure getHeadVersion performance (git show HEAD:file) - const startTime = Date.now(); - const headContent = await git.show([`HEAD:${fileName}`]); - const elapsed = Date.now() - startTime; - - // Verify operation completed within 500ms - expect(elapsed).toBeLessThan(500); - expect(headContent).toBe(content); - } - ), - { numRuns: 20 } // Reduced runs for performance tests - ); - }); - - /** - * Test Git operations with large files - * Validates: Requirements 7.2 - */ - it('handles large files efficiently', async () => { - // Create a file with 5000 lines - const fileName = 'large-file.txt'; - const filePath = path.join(tempDir, fileName); - const content = Array(5000).fill('test line content with some data').join('\n'); - - await fs.writeFile(filePath, content); - - await git.add(fileName); - await git.commit('Add large file'); - - // Measure performance - const startTime = Date.now(); - const headContent = await git.show([`HEAD:${fileName}`]); - const elapsed = Date.now() - startTime; - - expect(elapsed).toBeLessThan(500); - expect(headContent.length).toBe(content.length); - }); -}); diff --git a/packages/vscode-extension/src/git/GitIntegrationModule.properties.test.ts b/packages/vscode-extension/src/git/GitIntegrationModule.properties.test.ts deleted file mode 100644 index 43de32d..0000000 --- a/packages/vscode-extension/src/git/GitIntegrationModule.properties.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import * as fc from 'fast-check'; -import { GitIntegrationModuleImpl } from './GitIntegrationModule'; - -// Mock vscode module -vi.mock('vscode', () => ({ - workspace: { - asRelativePath: vi.fn((path: string) => { - // Extract relative path from absolute path - const parts = path.split('/'); - const projectIndex = parts.indexOf('project'); - if (projectIndex >= 0 && projectIndex < parts.length - 1) { - return parts.slice(projectIndex + 1).join('/'); - } - return parts[parts.length - 1]; - }), - }, -})); - -// Mock simple-git -vi.mock('simple-git', () => { - const mockGit = { - revparse: vi.fn(), - show: vi.fn(), - }; - - return { - default: vi.fn(() => mockGit), - __mockGit: mockGit, - }; -}); - -describe('GitIntegrationModule - Property Tests', () => { - let mockGit: any; - - beforeEach(async () => { - // Get the mock git instance - const simpleGit = await import('simple-git'); - mockGit = (simpleGit as any).__mockGit; - - // Reset mocks - vi.clearAllMocks(); - }); - - // Feature: git-integration-diffing, Property 4: HEAD content retrieval - it('Property 4: For any tracked file, getHeadVersion returns valid content', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 100 }), // file content - fc.string({ minLength: 1, maxLength: 50 }), // file name - async (content, fileName) => { - const gitModule = new GitIntegrationModuleImpl(); - - // Setup: Initialize with a valid repository - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - - // Setup: Mock git show to return the content (simulating tracked file) - mockGit.show.mockResolvedValue(content); - - // Act: Get HEAD version - const result = await gitModule.getHeadVersion(`/home/user/project/${fileName}`); - - // Assert: Result should match the mocked content - expect(result).toBe(content); - expect(mockGit.show).toHaveBeenCalled(); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 5: Untracked file handling - it('Property 5: For any untracked file, getHeadVersion returns empty string', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }), // file name - async (fileName) => { - const gitModule = new GitIntegrationModuleImpl(); - - // Setup: Initialize with a valid repository - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - - // Setup: Mock git show to throw error (simulating untracked file) - mockGit.show.mockRejectedValue(new Error('Path not in HEAD')); - - // Act: Get HEAD version - const result = await gitModule.getHeadVersion(`/home/user/project/${fileName}`); - - // Assert: Result should be empty string - expect(result).toBe(''); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 6: Git error resilience - it('Property 6: For any Git operation that fails, module returns empty string without throwing', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }), // file name - fc.oneof( - fc.constant('Git command failed'), - fc.constant('Permission denied'), - fc.constant('Network error'), - fc.constant('Timeout') - ), // error message - async (fileName, errorMessage) => { - const gitModule = new GitIntegrationModuleImpl(); - - // Setup: Initialize with a valid repository - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - - // Setup: Mock git show to throw various errors - mockGit.show.mockRejectedValue(new Error(errorMessage)); - - // Act & Assert: Should not throw, should return empty string - await expect( - gitModule.getHeadVersion(`/home/user/project/${fileName}`) - ).resolves.toBe(''); - } - ), - { numRuns: 100 } - ); - }); - - // Additional property: Path normalization - it('Property: Path separators are normalized for Git compatibility', async () => { - await fc.assert( - fc.asyncProperty( - fc.array( - fc.string({ minLength: 1, maxLength: 20 }).filter(s => !s.includes('/') && !s.includes('\\')), - { minLength: 1, maxLength: 5 } - ), // path segments without slashes - fc.string({ minLength: 1, maxLength: 100 }), // content - async (pathSegments, content) => { - const gitModule = new GitIntegrationModuleImpl(); - - // Setup: Initialize with a valid repository - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - - // Setup: Mock git show to return content - mockGit.show.mockResolvedValue(content); - - // Create path with backslashes (Windows-style) - const windowsPath = pathSegments.join('\\'); - - // Mock asRelativePath to return Windows-style path for this specific call - const vscode = await import('vscode'); - (vscode.workspace.asRelativePath as any).mockReturnValueOnce(windowsPath); - - // Act: Get HEAD version - await gitModule.getHeadVersion(`/home/user/project/${windowsPath}`); - - // Assert: Git show should be called with forward slashes - const expectedPath = pathSegments.join('/'); - expect(mockGit.show).toHaveBeenLastCalledWith([`HEAD:${expectedPath}`]); - } - ), - { numRuns: 100 } - ); - }); - - // Property: isTracked consistency - it('Property: isTracked returns true if and only if getHeadVersion returns non-empty content', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }), // file name - fc.boolean(), // whether file is tracked - async (fileName, isTracked) => { - const gitModule = new GitIntegrationModuleImpl(); - - // Setup: Initialize with a valid repository - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - - const filePath = `/home/user/project/${fileName}`; - - if (isTracked) { - // Setup: File is tracked - mockGit.show.mockResolvedValue('some content'); - - // Act - const trackedResult = await gitModule.isTracked(filePath); - const content = await gitModule.getHeadVersion(filePath); - - // Assert: Both should indicate tracked file - expect(trackedResult).toBe(true); - expect(content).not.toBe(''); - } else { - // Setup: File is not tracked - mockGit.show.mockRejectedValue(new Error('Path not in HEAD')); - - // Act - const trackedResult = await gitModule.isTracked(filePath); - const content = await gitModule.getHeadVersion(filePath); - - // Assert: Both should indicate untracked file - expect(trackedResult).toBe(false); - expect(content).toBe(''); - } - } - ), - { numRuns: 100 } - ); - }); - - // Property: Initialization state consistency - it('Property: Operations return empty/false when not initialized', async () => { - await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1, maxLength: 50 }), // file name - async (fileName) => { - const gitModule = new GitIntegrationModuleImpl(); - - // Do NOT initialize the module - const filePath = `/home/user/project/${fileName}`; - - // Act - const content = await gitModule.getHeadVersion(filePath); - const tracked = await gitModule.isTracked(filePath); - - // Assert: Should return safe defaults - expect(content).toBe(''); - expect(tracked).toBe(false); - } - ), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/vscode-extension/src/git/GitIntegrationModule.test.ts b/packages/vscode-extension/src/git/GitIntegrationModule.test.ts deleted file mode 100644 index 74ac7ff..0000000 --- a/packages/vscode-extension/src/git/GitIntegrationModule.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { GitIntegrationModuleImpl } from './GitIntegrationModule'; -import * as vscode from 'vscode'; - -// Mock vscode module -vi.mock('vscode', () => ({ - workspace: { - asRelativePath: vi.fn((path: string) => { - // Simple mock: extract filename from path - const parts = path.split('/'); - return parts[parts.length - 1]; - }), - }, -})); - -// Mock simple-git -vi.mock('simple-git', () => { - const mockGit = { - revparse: vi.fn(), - show: vi.fn(), - }; - - return { - default: vi.fn(() => mockGit), - __mockGit: mockGit, - }; -}); - -describe('GitIntegrationModule', () => { - let gitModule: GitIntegrationModuleImpl; - let mockGit: any; - - beforeEach(async () => { - gitModule = new GitIntegrationModuleImpl(); - - // Get the mock git instance - const simpleGit = await import('simple-git'); - mockGit = (simpleGit as any).__mockGit; - - // Reset mocks - vi.clearAllMocks(); - }); - - describe('initialize', () => { - it('should find repository root correctly', async () => { - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - - const result = await gitModule.initialize('/home/user/project'); - - expect(result).toBe(true); - expect(mockGit.revparse).toHaveBeenCalledWith(['--show-toplevel']); - }); - - it('should return false when Git repository not found', async () => { - mockGit.revparse.mockRejectedValue(new Error('Not a git repository')); - - const result = await gitModule.initialize('/home/user/not-a-repo'); - - expect(result).toBe(false); - }); - - it('should handle initialization errors gracefully', async () => { - mockGit.revparse.mockRejectedValue(new Error('Permission denied')); - - const result = await gitModule.initialize('/home/user/no-permission'); - - expect(result).toBe(false); - }); - }); - - describe('getHeadVersion', () => { - beforeEach(async () => { - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - }); - - it('should return HEAD content for tracked files', async () => { - const expectedContent = 'const x = 1;\nconsole.log(x);'; - mockGit.show.mockResolvedValue(expectedContent); - - const content = await gitModule.getHeadVersion('/home/user/project/src/index.ts'); - - expect(content).toBe(expectedContent); - expect(mockGit.show).toHaveBeenCalledWith(['HEAD:index.ts']); - }); - - it('should return empty string for untracked files', async () => { - mockGit.show.mockRejectedValue(new Error('Path not in HEAD')); - - const content = await gitModule.getHeadVersion('/home/user/project/src/newfile.ts'); - - expect(content).toBe(''); - }); - - it('should return empty string for newly added files', async () => { - mockGit.show.mockRejectedValue(new Error('fatal: path not in HEAD')); - - const content = await gitModule.getHeadVersion('/home/user/project/src/added.ts'); - - expect(content).toBe(''); - }); - - it('should handle Git operation failures', async () => { - mockGit.show.mockRejectedValue(new Error('Git command failed')); - - const content = await gitModule.getHeadVersion('/home/user/project/src/file.ts'); - - expect(content).toBe(''); - }); - - it('should return empty string when not initialized', async () => { - const uninitializedModule = new GitIntegrationModuleImpl(); - - const content = await uninitializedModule.getHeadVersion('/some/path/file.ts'); - - expect(content).toBe(''); - }); - }); - - describe('isTracked', () => { - beforeEach(async () => { - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - }); - - it('should return true for tracked files', async () => { - mockGit.show.mockResolvedValue('file content'); - - const isTracked = await gitModule.isTracked('/home/user/project/src/tracked.ts'); - - expect(isTracked).toBe(true); - }); - - it('should return false for untracked files', async () => { - mockGit.show.mockRejectedValue(new Error('Path not in HEAD')); - - const isTracked = await gitModule.isTracked('/home/user/project/src/untracked.ts'); - - expect(isTracked).toBe(false); - }); - - it('should return false when not initialized', async () => { - const uninitializedModule = new GitIntegrationModuleImpl(); - - const isTracked = await uninitializedModule.isTracked('/some/path/file.ts'); - - expect(isTracked).toBe(false); - }); - }); - - describe('path conversion', () => { - beforeEach(async () => { - mockGit.revparse.mockResolvedValue('/home/user/project\n'); - await gitModule.initialize('/home/user/project'); - }); - - it('should convert absolute path to relative path', async () => { - // Mock asRelativePath to return a proper relative path - (vscode.workspace.asRelativePath as any).mockReturnValue('src/components/Button.tsx'); - mockGit.show.mockResolvedValue('content'); - - await gitModule.getHeadVersion('/home/user/project/src/components/Button.tsx'); - - expect(mockGit.show).toHaveBeenCalledWith(['HEAD:src/components/Button.tsx']); - }); - - it('should normalize Windows path separators', async () => { - // Mock asRelativePath to return Windows-style path - (vscode.workspace.asRelativePath as any).mockReturnValue('src\\utils\\helper.ts'); - mockGit.show.mockResolvedValue('content'); - - await gitModule.getHeadVersion('C:\\project\\src\\utils\\helper.ts'); - - // Should convert backslashes to forward slashes for Git - expect(mockGit.show).toHaveBeenCalledWith(['HEAD:src/utils/helper.ts']); - }); - }); -}); diff --git a/packages/vscode-extension/src/git/GitIntegrationModule.ts b/packages/vscode-extension/src/git/GitIntegrationModule.ts index afaa1e7..5d47177 100644 --- a/packages/vscode-extension/src/git/GitIntegrationModule.ts +++ b/packages/vscode-extension/src/git/GitIntegrationModule.ts @@ -61,26 +61,26 @@ export class GitIntegrationModuleImpl implements GitIntegrationModule { } const startTime = Date.now(); - + try { // Convert absolute path to repository-relative path const relativePath = this.getRelativePath(filePath); - + // Fetch HEAD version using git show const content = await this.git.show([`HEAD:${relativePath}`]); - + const elapsed = Date.now() - startTime; console.log( `[GitIntegration] Fetched HEAD version for ${relativePath} (${content.length} bytes, took ${elapsed}ms)` ); - + // Performance warning if Git operation took too long if (elapsed > 500) { console.warn( `[GitIntegration] Git operation exceeded 500ms threshold: ${elapsed}ms for ${relativePath}` ); } - + return content; } catch (error) { const elapsed = Date.now() - startTime; @@ -98,7 +98,7 @@ export class GitIntegrationModuleImpl implements GitIntegrationModule { try { const relativePath = this.getRelativePath(filePath); - + // Check if file exists in HEAD await this.git.show([`HEAD:${relativePath}`]); return true; @@ -115,7 +115,7 @@ export class GitIntegrationModuleImpl implements GitIntegrationModule { private getRelativePath(filePath: string): string { // Use VS Code's workspace API to get relative path const relativePath = vscode.workspace.asRelativePath(filePath, false); - + // Normalize path separators for Git (always use forward slashes) return relativePath.replace(/\\/g, '/'); } diff --git a/packages/vscode-extension/src/watcher/FileWatcher.performance.test.ts b/packages/vscode-extension/src/watcher/FileWatcher.performance.test.ts deleted file mode 100644 index 46be603..0000000 --- a/packages/vscode-extension/src/watcher/FileWatcher.performance.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import * as fc from 'fast-check'; - -/** - * Performance tests for FileWatcher - * Feature: git-integration-diffing - */ - -describe('FileWatcher Performance Tests', () => { - beforeEach(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - vi.restoreAllMocks(); - vi.useRealTimers(); - }); - - /** - * Property 22: Debounce delay - * For any file change event, the File_Watcher should trigger the callback - * within 1000ms ± 50ms after the last change. - * Validates: Requirements 7.1 - */ - it('Property 22: Debounce delay is within 1000ms ± 50ms', () => { - fc.assert( - fc.property( - fc.integer({ min: 1, max: 10 }), // Number of rapid changes - fc.integer({ min: 0, max: 100 }), // Delay between changes (ms) - (numChanges, delayBetweenChanges) => { - // Simulate rapid changes - for (let i = 0; i < numChanges; i++) { - vi.advanceTimersByTime(delayBetweenChanges); - } - - // Advance to when callback should fire - const startTime = Date.now(); - vi.advanceTimersByTime(1000); - const callbackTime = Date.now(); - - const actualDelay = callbackTime - startTime; - - // Verify delay is within tolerance (1000ms ± 50ms) - expect(actualDelay).toBeGreaterThanOrEqual(950); - expect(actualDelay).toBeLessThanOrEqual(1050); - } - ), - { numRuns: 100 } - ); - }); - - /** - * Test end-to-end latency measurement - * Validates: Requirements 7.5 - */ - it('measures debounce timing accurately', async () => { - const startTime = Date.now(); - - // Simulate file change - vi.advanceTimersByTime(1000); - - const endTime = Date.now(); - const elapsed = endTime - startTime; - - // Should be exactly 1000ms with fake timers - expect(elapsed).toBe(1000); - }); -}); diff --git a/packages/vscode-extension/src/watcher/FileWatcher.properties.test.ts b/packages/vscode-extension/src/watcher/FileWatcher.properties.test.ts deleted file mode 100644 index d5fcb09..0000000 --- a/packages/vscode-extension/src/watcher/FileWatcher.properties.test.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import * as fc from 'fast-check'; -import * as vscode from 'vscode'; -import { FileWatcher } from './FileWatcher'; - -// Mock vscode module -vi.mock('vscode', () => ({ - window: { - onDidChangeActiveTextEditor: vi.fn(), - activeTextEditor: undefined, - }, - workspace: { - onDidChangeTextDocument: vi.fn(), - workspaceFolders: [], - }, -})); - -describe('FileWatcher - Property-Based Tests', () => { - let fileWatcher: FileWatcher; - let mockEditorChangeCallback: (editor: vscode.TextEditor | undefined) => void; - let mockDocumentChangeCallback: (event: vscode.TextDocumentChangeEvent) => void; - - beforeEach(() => { - fileWatcher = new FileWatcher(); - - vi.mocked(vscode.window.onDidChangeActiveTextEditor).mockImplementation((callback) => { - mockEditorChangeCallback = callback; - return { dispose: vi.fn() }; - }); - - vi.mocked(vscode.workspace.onDidChangeTextDocument).mockImplementation((callback) => { - mockDocumentChangeCallback = callback; - return { dispose: vi.fn() }; - }); - - (vscode.workspace.workspaceFolders as any) = [ - { uri: { fsPath: '/workspace' } }, - ]; - - fileWatcher.initialize(); - }); - - afterEach(() => { - fileWatcher.dispose(); - vi.clearAllMocks(); - }); - - // Feature: git-integration-diffing, Property 1: Active file tracking - it('Property 1: should track any file that becomes the active editor', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }).map(s => `/workspace/${s}.ts`), - (filePath) => { - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: filePath }, - }, - } as vscode.TextEditor; - - mockEditorChangeCallback(mockEditor); - - expect(onFileChangedSpy).toHaveBeenCalledWith(filePath); - onFileChangedSpy.mockClear(); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 2: Debounce timing - it('Property 2: should not trigger callback until 1000ms after last change', () => { - vi.useFakeTimers(); - - fc.assert( - fc.property( - fc.string({ minLength: 1 }).map(s => `/workspace/${s}.ts`), - fc.integer({ min: 2, max: 10 }), - (filePath, numChanges) => { - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: filePath }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - onFileChangedSpy.mockClear(); - - const mockEvent = { - document: { - uri: { fsPath: filePath }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - for (let i = 0; i < numChanges; i++) { - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(500); - expect(onFileChangedSpy).not.toHaveBeenCalled(); - } - - vi.advanceTimersByTime(500); - expect(onFileChangedSpy).toHaveBeenCalledTimes(1); - expect(onFileChangedSpy).toHaveBeenCalledWith(filePath); - - onFileChangedSpy.mockClear(); - } - ), - { numRuns: 100 } - ); - - vi.useRealTimers(); - }); - - // Feature: git-integration-diffing, Property 3: Editor cleanup - it('Property 3: should stop tracking file when editor is closed', () => { - vi.useFakeTimers(); - - fc.assert( - fc.property( - fc.string({ minLength: 1 }).map(s => `/workspace/${s}.ts`), - (filePath) => { - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: filePath }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - onFileChangedSpy.mockClear(); - - mockEditorChangeCallback(undefined); - - const mockEvent = { - document: { - uri: { fsPath: filePath }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(1000); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - - onFileChangedSpy.mockClear(); - } - ), - { numRuns: 100 } - ); - - vi.useRealTimers(); - }); -}); diff --git a/packages/vscode-extension/src/watcher/FileWatcher.test.ts b/packages/vscode-extension/src/watcher/FileWatcher.test.ts deleted file mode 100644 index 486af4b..0000000 --- a/packages/vscode-extension/src/watcher/FileWatcher.test.ts +++ /dev/null @@ -1,351 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import * as vscode from 'vscode'; -import { FileWatcher } from './FileWatcher'; - -// Mock vscode module -vi.mock('vscode', () => ({ - window: { - onDidChangeActiveTextEditor: vi.fn(), - activeTextEditor: undefined, - }, - workspace: { - onDidChangeTextDocument: vi.fn(), - workspaceFolders: [], - }, -})); - -describe('FileWatcher', () => { - let fileWatcher: FileWatcher; - let mockEditorChangeCallback: (editor: vscode.TextEditor | undefined) => void; - let mockDocumentChangeCallback: (event: vscode.TextDocumentChangeEvent) => void; - - beforeEach(() => { - fileWatcher = new FileWatcher(); - - vi.mocked(vscode.window.onDidChangeActiveTextEditor).mockImplementation((callback) => { - mockEditorChangeCallback = callback; - return { dispose: vi.fn() }; - }); - - vi.mocked(vscode.workspace.onDidChangeTextDocument).mockImplementation((callback) => { - mockDocumentChangeCallback = callback; - return { dispose: vi.fn() }; - }); - - (vscode.workspace.workspaceFolders as any) = [ - { uri: { fsPath: '/workspace' } }, - ]; - }); - - afterEach(() => { - fileWatcher.dispose(); - vi.clearAllMocks(); - }); - - describe('initialize', () => { - it('should register event listeners', () => { - fileWatcher.initialize(); - - expect(vscode.window.onDidChangeActiveTextEditor).toHaveBeenCalled(); - expect(vscode.workspace.onDidChangeTextDocument).toHaveBeenCalled(); - }); - }); - - describe('active editor change detection', () => { - it('should register new active file when editor changes', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/newfile.ts' }, - }, - } as vscode.TextEditor; - - mockEditorChangeCallback(mockEditor); - - expect(onFileChangedSpy).toHaveBeenCalledWith('/workspace/newfile.ts'); - }); - - it('should unregister file when editor is closed', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - onFileChangedSpy.mockClear(); - mockEditorChangeCallback(undefined); - - const mockEvent = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - }); - - it('should not track files outside workspace', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/outside/file.ts' }, - }, - } as vscode.TextEditor; - - mockEditorChangeCallback(mockEditor); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - }); - }); - - describe('text document change detection', () => { - beforeEach(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - vi.useRealTimers(); - }); - - it('should trigger callback after debounce period', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - onFileChangedSpy.mockClear(); - - const mockEvent = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - - vi.advanceTimersByTime(1000); - expect(onFileChangedSpy).toHaveBeenCalledWith('/workspace/test.ts'); - }); - - it('should reset debounce timer on multiple rapid changes', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - onFileChangedSpy.mockClear(); - - const mockEvent = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(500); - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(500); - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(500); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - - vi.advanceTimersByTime(500); - expect(onFileChangedSpy).toHaveBeenCalledTimes(1); - }); - - it('should only trigger for active file changes', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/active.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - onFileChangedSpy.mockClear(); - - const mockEvent = { - document: { - uri: { fsPath: '/workspace/other.ts' }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(1000); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - }); - }); - - describe('workspace file filtering', () => { - it('should only trigger events for files within workspace', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - expect(onFileChangedSpy).toHaveBeenCalledWith('/workspace/test.ts'); - - onFileChangedSpy.mockClear(); - - const outsideEditor = { - document: { - uri: { fsPath: '/outside/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(outsideEditor); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - }); - - it('should not trigger when no workspace is open', () => { - (vscode.workspace.workspaceFolders as any) = undefined; - - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - }); - }); - - describe('dispose', () => { - beforeEach(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - vi.useRealTimers(); - }); - - it('should clean up listeners', () => { - const disposeSpy1 = vi.fn(); - const disposeSpy2 = vi.fn(); - - vi.mocked(vscode.window.onDidChangeActiveTextEditor).mockReturnValue({ - dispose: disposeSpy1, - }); - vi.mocked(vscode.workspace.onDidChangeTextDocument).mockReturnValue({ - dispose: disposeSpy2, - }); - - fileWatcher.initialize(); - fileWatcher.dispose(); - - expect(disposeSpy1).toHaveBeenCalled(); - expect(disposeSpy2).toHaveBeenCalled(); - }); - - it('should clear pending debounce timer', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEditor = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - } as vscode.TextEditor; - mockEditorChangeCallback(mockEditor); - - onFileChangedSpy.mockClear(); - - const mockEvent = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - fileWatcher.dispose(); - - vi.advanceTimersByTime(1000); - expect(onFileChangedSpy).not.toHaveBeenCalled(); - }); - }); - - describe('no events when no file is active', () => { - beforeEach(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - vi.useRealTimers(); - }); - - it('should not trigger events when no file is active', () => { - fileWatcher.initialize(); - const onFileChangedSpy = vi.fn(); - fileWatcher.onFileChanged = onFileChangedSpy; - - const mockEvent = { - document: { - uri: { fsPath: '/workspace/test.ts' }, - }, - contentChanges: [], - reason: undefined, - } as unknown as vscode.TextDocumentChangeEvent; - - mockDocumentChangeCallback(mockEvent); - vi.advanceTimersByTime(1000); - - expect(onFileChangedSpy).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/vscode-extension/src/watcher/FileWatcher.ts b/packages/vscode-extension/src/watcher/FileWatcher.ts index 1a3259d..ad2f1fa 100644 --- a/packages/vscode-extension/src/watcher/FileWatcher.ts +++ b/packages/vscode-extension/src/watcher/FileWatcher.ts @@ -58,7 +58,7 @@ export class FileWatcher { } this.activeFilePath = filePath; - + // Trigger diff generation immediately when switching files this.triggerFileChanged(filePath); } @@ -89,7 +89,7 @@ export class FileWatcher { private debounceFileChange(filePath: string): void { // Track when the change occurred this.lastChangeTime = Date.now(); - + // Clear existing timer this.clearDebounceTimer(); @@ -98,13 +98,13 @@ export class FileWatcher { // Verify debounce timing (1000ms ± 50ms tolerance) const actualDelay = Date.now() - this.lastChangeTime; const tolerance = 50; - + if (Math.abs(actualDelay - this.debounceDelay) > tolerance) { console.warn( `[FileWatcher] Debounce timing outside tolerance: ${actualDelay}ms (expected ${this.debounceDelay}ms ± ${tolerance}ms)` ); } - + this.triggerFileChanged(filePath); }, this.debounceDelay); } @@ -132,12 +132,12 @@ export class FileWatcher { */ private isWithinWorkspace(filePath: string): boolean { const workspaceFolders = vscode.workspace.workspaceFolders; - + if (!workspaceFolders || workspaceFolders.length === 0) { return false; } - return workspaceFolders.some(folder => { + return workspaceFolders.some((folder) => { const workspacePath = folder.uri.fsPath; return filePath.startsWith(workspacePath); }); @@ -148,7 +148,7 @@ export class FileWatcher { */ public dispose(): void { this.clearDebounceTimer(); - this.disposables.forEach(disposable => disposable.dispose()); + this.disposables.forEach((disposable) => disposable.dispose()); this.disposables = []; this.activeFilePath = null; } diff --git a/packages/vscode-extension/src/websocket/WebSocketClient.properties.test.ts b/packages/vscode-extension/src/websocket/WebSocketClient.properties.test.ts deleted file mode 100644 index 7cee000..0000000 --- a/packages/vscode-extension/src/websocket/WebSocketClient.properties.test.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import * as fc from 'fast-check'; -import { ProtocolMessage } from '@codelink/protocol'; - -// Mock socket.io-client - must be defined before vi.mock -const mockSocket = { - connected: false, - on: vi.fn(), - emit: vi.fn(), - disconnect: vi.fn(), -}; - -vi.mock('socket.io-client', () => ({ - io: vi.fn(() => mockSocket), -})); - -import { WebSocketClient } from './WebSocketClient'; - -describe('WebSocketClient - Property-Based Tests', () => { - let client: WebSocketClient; - let connectHandler: () => void; - - beforeEach(async () => { - const { io } = await import('socket.io-client'); - - client = new WebSocketClient(); - mockSocket.connected = false; - mockSocket.on.mockClear(); - mockSocket.emit.mockClear(); - mockSocket.disconnect.mockClear(); - vi.mocked(io).mockClear(); - - mockSocket.on.mockImplementation((event: string, handler: any) => { - if (event === 'connect') connectHandler = handler; - }); - }); - - afterEach(() => { - client.disconnect(); - }); - - // Feature: git-integration-diffing, Property 13: Message transmission - it('Property 13: should transmit any message when connected', () => { - fc.assert( - fc.property( - fc.string({ minLength: 1 }), - fc.integer({ min: 0 }), - fc.string({ minLength: 1 }), - fc.string(), - fc.string(), - fc.boolean(), - (id, timestamp, fileName, originalFile, modifiedFile, isDirty) => { - client.connect('http://localhost:3000'); - mockSocket.connected = true; - mockSocket.emit.mockClear(); - - const message: ProtocolMessage = { - id, - timestamp, - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName, - originalFile, - modifiedFile, - isDirty, - timestamp, - }, - }; - - client.send(message); - - expect(mockSocket.emit).toHaveBeenCalledWith('message', JSON.stringify(message)); - expect(mockSocket.emit).toHaveBeenCalledTimes(1); - } - ), - { numRuns: 100 } - ); - }); - - // Feature: git-integration-diffing, Property 15: Message queueing on disconnect - it('Property 15: should queue any message when disconnected', () => { - vi.useFakeTimers(); - - fc.assert( - fc.property( - fc.array( - fc.record({ - id: fc.string({ minLength: 1 }), - timestamp: fc.integer({ min: 0 }), - fileName: fc.string({ minLength: 1 }), - originalFile: fc.string(), - modifiedFile: fc.string(), - isDirty: fc.boolean(), - }), - { minLength: 1, maxLength: 50 } - ), - (messageData) => { - client.connect('http://localhost:3000'); - mockSocket.connected = false; - mockSocket.emit.mockClear(); - - const messages: ProtocolMessage[] = messageData.map(data => ({ - id: data.id, - timestamp: data.timestamp, - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: data.fileName, - originalFile: data.originalFile, - modifiedFile: data.modifiedFile, - isDirty: data.isDirty, - timestamp: data.timestamp, - }, - })); - - messages.forEach(msg => client.send(msg)); - - expect(client.getQueueSize()).toBe(messages.length); - expect(mockSocket.emit).not.toHaveBeenCalled(); - - mockSocket.connected = true; - connectHandler(); - vi.runAllTimers(); - - expect(client.getQueueSize()).toBe(0); - expect(mockSocket.emit).toHaveBeenCalledTimes(messages.length); - - messages.forEach(msg => { - expect(mockSocket.emit).toHaveBeenCalledWith('message', JSON.stringify(msg)); - }); - } - ), - { numRuns: 100 } - ); - - vi.useRealTimers(); - }); - - // Additional property: Connection state consistency - it('Property: isConnected should reflect actual socket state', () => { - fc.assert( - fc.property( - fc.boolean(), - (connected) => { - client.connect('http://localhost:3000'); - mockSocket.connected = connected; - - expect(client.isConnected()).toBe(connected); - } - ), - { numRuns: 100 } - ); - }); -}); diff --git a/packages/vscode-extension/src/websocket/WebSocketClient.test.ts b/packages/vscode-extension/src/websocket/WebSocketClient.test.ts deleted file mode 100644 index 42e688a..0000000 --- a/packages/vscode-extension/src/websocket/WebSocketClient.test.ts +++ /dev/null @@ -1,333 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { ProtocolMessage } from '@codelink/protocol'; - -// Mock socket.io-client - must be defined before vi.mock -const mockSocket = { - connected: false, - on: vi.fn(), - emit: vi.fn(), - disconnect: vi.fn(), -}; - -vi.mock('socket.io-client', () => ({ - io: vi.fn(() => mockSocket), -})); - -import { WebSocketClient } from './WebSocketClient'; - -describe('WebSocketClient', () => { - let client: WebSocketClient; - let connectHandler: () => void; - let disconnectHandler: (reason: string) => void; - let errorHandler: (error: Error) => void; - let connectErrorHandler: (error: Error) => void; - - beforeEach(async () => { - const { io } = await import('socket.io-client'); - - client = new WebSocketClient(); - mockSocket.connected = false; - mockSocket.on.mockClear(); - mockSocket.emit.mockClear(); - mockSocket.disconnect.mockClear(); - vi.mocked(io).mockClear(); - - // Capture event handlers - mockSocket.on.mockImplementation((event: string, handler: any) => { - if (event === 'connect') connectHandler = handler; - if (event === 'disconnect') disconnectHandler = handler; - if (event === 'error') errorHandler = handler; - if (event === 'connect_error') connectErrorHandler = handler; - }); - }); - - afterEach(() => { - client.disconnect(); - }); - - describe('connect', () => { - it('should initialize socket connection', async () => { - const { io } = await import('socket.io-client'); - - client.connect('http://localhost:3000'); - - expect(io).toHaveBeenCalledWith('http://localhost:3000', { - reconnection: true, - reconnectionDelay: 1000, - reconnectionDelayMax: 5000, - reconnectionAttempts: 10, - }); - }); - - it('should set up event handlers', () => { - client.connect('http://localhost:3000'); - - expect(mockSocket.on).toHaveBeenCalledWith('connect', expect.any(Function)); - expect(mockSocket.on).toHaveBeenCalledWith('disconnect', expect.any(Function)); - expect(mockSocket.on).toHaveBeenCalledWith('connect_error', expect.any(Function)); - expect(mockSocket.on).toHaveBeenCalledWith('error', expect.any(Function)); - }); - - it('should not connect if already connected', async () => { - const { io } = await import('socket.io-client'); - - client.connect('http://localhost:3000'); - vi.mocked(io).mockClear(); - - client.connect('http://localhost:3000'); - - expect(io).not.toHaveBeenCalled(); - }); - }); - - describe('send', () => { - it('should transmit message when connected', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = true; - - const message: ProtocolMessage = { - id: '123', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: 'test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: true, - timestamp: Date.now(), - }, - }; - - client.send(message); - - expect(mockSocket.emit).toHaveBeenCalledWith('message', JSON.stringify(message)); - }); - - it('should queue message when disconnected', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = false; - - const message: ProtocolMessage = { - id: '123', - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: 'test.ts', - originalFile: 'old', - modifiedFile: 'new', - isDirty: true, - timestamp: Date.now(), - }, - }; - - client.send(message); - - expect(mockSocket.emit).not.toHaveBeenCalled(); - expect(client.getQueueSize()).toBe(1); - }); - }); - - describe('isConnected', () => { - it('should return true when socket is connected', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = true; - - expect(client.isConnected()).toBe(true); - }); - - it('should return false when socket is disconnected', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = false; - - expect(client.isConnected()).toBe(false); - }); - - it('should return false when socket is not initialized', () => { - expect(client.isConnected()).toBe(false); - }); - }); - - describe('message queueing', () => { - beforeEach(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - vi.useRealTimers(); - }); - - it('should queue messages when disconnected', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = false; - - const message1: ProtocolMessage = { - id: '1', - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - - const message2: ProtocolMessage = { - id: '2', - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - - client.send(message1); - client.send(message2); - - expect(client.getQueueSize()).toBe(2); - }); - - it('should flush queue on reconnection', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = false; - - const messages: ProtocolMessage[] = []; - for (let i = 0; i < 5; i++) { - const msg: ProtocolMessage = { - id: `${i}`, - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - messages.push(msg); - client.send(msg); - } - - expect(client.getQueueSize()).toBe(5); - - mockSocket.connected = true; - connectHandler(); - - vi.runAllTimers(); - - expect(mockSocket.emit).toHaveBeenCalledTimes(5); - expect(client.getQueueSize()).toBe(0); - }); - - it('should drop oldest message when queue is full', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = false; - - for (let i = 0; i < 101; i++) { - const msg: ProtocolMessage = { - id: `${i}`, - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - client.send(msg); - } - - expect(client.getQueueSize()).toBe(100); - }); - }); - - describe('retry logic', () => { - beforeEach(() => { - vi.useFakeTimers(); - vi.spyOn(console, 'log').mockImplementation(() => {}); - vi.spyOn(console, 'error').mockImplementation(() => {}); - }); - - afterEach(() => { - vi.useRealTimers(); - vi.restoreAllMocks(); - }); - - it('should handle connection errors with exponential backoff', () => { - client.connect('http://localhost:3000'); - - const error = new Error('Connection failed'); - - // First error: reconnectAttempts becomes 1, delay = 2^1 * 1000 = 2000ms - connectErrorHandler(error); - expect(console.log).toHaveBeenCalledWith( - expect.stringContaining('retrying in 2000ms'), - 'Connection failed' - ); - - // Second error: reconnectAttempts becomes 2, delay = 2^2 * 1000 = 4000ms - connectErrorHandler(error); - expect(console.log).toHaveBeenCalledWith( - expect.stringContaining('retrying in 4000ms'), - 'Connection failed' - ); - - // Third error: reconnectAttempts becomes 3, delay = 2^3 * 1000 = 5000ms (capped at 5000) - connectErrorHandler(error); - expect(console.log).toHaveBeenCalledWith( - expect.stringContaining('retrying in 5000ms'), - 'Connection failed' - ); - }); - - it('should stop retrying after max attempts', () => { - client.connect('http://localhost:3000'); - - const error = new Error('Connection failed'); - - for (let i = 0; i < 10; i++) { - connectErrorHandler(error); - } - - expect(console.error).toHaveBeenCalledWith('Max reconnection attempts reached'); - }); - }); - - describe('connection event handlers', () => { - beforeEach(() => { - vi.spyOn(console, 'log').mockImplementation(() => {}); - vi.spyOn(console, 'error').mockImplementation(() => {}); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - it('should handle disconnect event', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = true; - connectHandler(); - - mockSocket.connected = false; - disconnectHandler('transport close'); - - expect(console.log).toHaveBeenCalledWith('WebSocket disconnected: transport close'); - }); - - it('should handle error event', () => { - client.connect('http://localhost:3000'); - - const error = new Error('Socket error'); - errorHandler(error); - - expect(console.error).toHaveBeenCalledWith('WebSocket error:', error); - }); - }); - - describe('disconnect', () => { - it('should disconnect socket and clear queue', () => { - client.connect('http://localhost:3000'); - mockSocket.connected = false; - - const message: ProtocolMessage = { - id: '1', - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - client.send(message); - - expect(client.getQueueSize()).toBe(1); - - client.disconnect(); - - expect(mockSocket.disconnect).toHaveBeenCalled(); - expect(client.getQueueSize()).toBe(0); - expect(client.isConnected()).toBe(false); - }); - }); -}); diff --git a/packages/vscode-extension/src/websocket/WebSocketClient.ts b/packages/vscode-extension/src/websocket/WebSocketClient.ts index ea0d3f7..9e7122f 100644 --- a/packages/vscode-extension/src/websocket/WebSocketClient.ts +++ b/packages/vscode-extension/src/websocket/WebSocketClient.ts @@ -1,5 +1,5 @@ import { io, Socket } from 'socket.io-client'; -import { ProtocolMessage, InjectPromptMessage } from '@codelink/protocol'; +import { ProtocolMessage } from '@codelink/protocol'; /** * Message handler callback type for incoming messages @@ -52,6 +52,18 @@ export class WebSocketClient { this.isConnecting = false; this.reconnectAttempts = 0; this.flushMessageQueue(); + + // Re-bind message handlers + this.messageHandlers.forEach((handler) => { + this.socket!.on('message', (data: string) => { + try { + const parsed = JSON.parse(data); + handler(parsed); + } catch (error) { + console.error('Error parsing message:', error); + } + }); + }); }); this.socket.on('disconnect', (reason) => { @@ -61,7 +73,7 @@ export class WebSocketClient { this.socket.on('connect_error', (error) => { this.isConnecting = false; this.reconnectAttempts++; - + if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.error('Max reconnection attempts reached'); return; @@ -90,7 +102,7 @@ export class WebSocketClient { * Handle incoming messages by notifying all registered handlers */ private handleIncomingMessage(message: ProtocolMessage): void { - this.messageHandlers.forEach(handler => { + this.messageHandlers.forEach((handler) => { try { handler(message); } catch (error) { @@ -120,10 +132,7 @@ export class WebSocketClient { * Calculate exponential backoff delay */ private calculateBackoffDelay(): number { - return Math.min( - this.baseRetryDelay * Math.pow(2, this.reconnectAttempts), - 5000 - ); + return Math.min(this.baseRetryDelay * Math.pow(2, this.reconnectAttempts), 5000); } /** @@ -169,7 +178,7 @@ export class WebSocketClient { const sendBatch = () => { const batch = this.messageQueue.splice(0, messagesPerBatch); - batch.forEach(msg => { + batch.forEach((msg) => { if (this.isConnected()) { this.socket!.emit('message', JSON.stringify(msg)); } diff --git a/packages/vscode-extension/tsconfig.tsbuildinfo b/packages/vscode-extension/tsconfig.tsbuildinfo index f7424d5..664432e 100644 --- a/packages/vscode-extension/tsconfig.tsbuildinfo +++ b/packages/vscode-extension/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@vitest/utils/dist/types.d.ts","../../node_modules/@vitest/utils/dist/helpers.d.ts","../../node_modules/@sinclair/typebox/typebox.d.ts","../../node_modules/@jest/schemas/build/index.d.ts","../../node_modules/pretty-format/build/index.d.ts","../../node_modules/@vitest/utils/dist/index.d.ts","../../node_modules/@vitest/runner/dist/tasks-K5XERDtv.d.ts","../../node_modules/@vitest/utils/dist/types-9l4niLY8.d.ts","../../node_modules/@vitest/utils/dist/diff.d.ts","../../node_modules/@vitest/utils/diff.d.ts","../../node_modules/@vitest/runner/dist/types.d.ts","../../node_modules/@vitest/utils/dist/error.d.ts","../../node_modules/@vitest/utils/error.d.ts","../../node_modules/@vitest/runner/dist/index.d.ts","../../node_modules/@vitest/runner/dist/utils.d.ts","../../node_modules/@vitest/runner/utils.d.ts","../../node_modules/@types/node/compatibility/disposable.d.ts","../../node_modules/@types/node/compatibility/indexable.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/compatibility/index.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../node_modules/@types/node/web-globals/domexception.d.ts","../../node_modules/@types/node/web-globals/events.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/file.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/filereader.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/web-globals/fetch.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.generated.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/@types/estree/index.d.ts","../../node_modules/rollup/dist/rollup.d.ts","../../node_modules/vite/types/hmrPayload.d.ts","../../node_modules/vite/types/customEvent.d.ts","../../node_modules/vite/types/hot.d.ts","../../node_modules/vite/dist/node/types.d-aGj9QkWt.d.ts","../../node_modules/esbuild/lib/main.d.ts","../../node_modules/source-map-js/source-map.d.ts","../../node_modules/postcss/lib/previous-map.d.ts","../../node_modules/postcss/lib/input.d.ts","../../node_modules/postcss/lib/css-syntax-error.d.ts","../../node_modules/postcss/lib/declaration.d.ts","../../node_modules/postcss/lib/root.d.ts","../../node_modules/postcss/lib/warning.d.ts","../../node_modules/postcss/lib/lazy-result.d.ts","../../node_modules/postcss/lib/no-work-result.d.ts","../../node_modules/postcss/lib/processor.d.ts","../../node_modules/postcss/lib/result.d.ts","../../node_modules/postcss/lib/document.d.ts","../../node_modules/postcss/lib/rule.d.ts","../../node_modules/postcss/lib/node.d.ts","../../node_modules/postcss/lib/comment.d.ts","../../node_modules/postcss/lib/container.d.ts","../../node_modules/postcss/lib/at-rule.d.ts","../../node_modules/postcss/lib/list.d.ts","../../node_modules/postcss/lib/postcss.d.ts","../../node_modules/vite/dist/node/runtime.d.ts","../../node_modules/vite/types/importGlob.d.ts","../../node_modules/vite/types/metadata.d.ts","../../node_modules/vite/dist/node/index.d.ts","../../node_modules/vite-node/dist/trace-mapping.d-xyIfZtPm.d.ts","../../node_modules/vite-node/dist/index-O2IrwHKf.d.ts","../../node_modules/vite-node/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment-cMiGIVXz.d.ts","../../node_modules/@vitest/snapshot/dist/index-S94ASl6q.d.ts","../../node_modules/@vitest/snapshot/dist/index.d.ts","../../node_modules/@vitest/expect/dist/chai.d.cts","../../node_modules/@vitest/expect/dist/index.d.ts","../../node_modules/@vitest/expect/index.d.ts","../../node_modules/tinybench/dist/index.d.cts","../../node_modules/vite-node/dist/client.d.ts","../../node_modules/@vitest/snapshot/dist/manager.d.ts","../../node_modules/@vitest/snapshot/manager.d.ts","../../node_modules/vite-node/dist/server.d.ts","../../node_modules/vitest/dist/reporters-w_64AS5f.d.ts","../../node_modules/vitest/dist/suite-dWqIFb_-.d.ts","../../node_modules/@vitest/spy/dist/index.d.ts","../../node_modules/@vitest/snapshot/dist/environment.d.ts","../../node_modules/@vitest/snapshot/environment.d.ts","../../node_modules/vitest/dist/index.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/diff-name-status.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/task.d.ts","../../node_modules/simple-git/dist/src/lib/types/tasks.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-error.d.ts","../../node_modules/simple-git/dist/src/lib/types/handlers.d.ts","../../node_modules/simple-git/dist/src/lib/types/index.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/log.d.ts","../../node_modules/simple-git/dist/typings/response.d.ts","../../node_modules/simple-git/dist/src/lib/responses/GetRemoteSummary.d.ts","../../node_modules/simple-git/dist/src/lib/args/pathspec.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/apply-patch.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/check-is-repo.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/clean.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/clone.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/config.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/count-objects.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/grep.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/reset.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/version.d.ts","../../node_modules/simple-git/dist/typings/types.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-construct-error.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-plugin-error.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-response-error.d.ts","../../node_modules/simple-git/dist/src/lib/errors/task-configuration-error.d.ts","../../node_modules/simple-git/dist/typings/errors.d.ts","../../node_modules/simple-git/dist/typings/simple-git.d.ts","../../node_modules/simple-git/dist/typings/index.d.ts","../../node_modules/@types/vscode/index.d.ts","./src/git/GitIntegrationModule.ts","../protocol/dist/index.d.ts","./src/diff/DiffGenerator.ts","./src/extension.error-handling.test.ts","./src/extension.performance.test.ts","../../node_modules/fast-check/lib/types/check/precondition/Pre.d.ts","../../node_modules/pure-rand/lib/types/generator/RandomGenerator.d.ts","../../node_modules/pure-rand/lib/types/generator/LinearCongruential.d.ts","../../node_modules/pure-rand/lib/types/generator/MersenneTwister.d.ts","../../node_modules/pure-rand/lib/types/generator/XorShift.d.ts","../../node_modules/pure-rand/lib/types/generator/XoroShiro.d.ts","../../node_modules/pure-rand/lib/types/distribution/Distribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/internals/ArrayInt.d.ts","../../node_modules/pure-rand/lib/types/distribution/UniformArrayIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UniformBigIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UniformIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UnsafeUniformArrayIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UnsafeUniformBigIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/distribution/UnsafeUniformIntDistribution.d.ts","../../node_modules/pure-rand/lib/types/pure-rand-default.d.ts","../../node_modules/pure-rand/lib/types/pure-rand.d.ts","../../node_modules/fast-check/lib/types/random/generator/Random.d.ts","../../node_modules/fast-check/lib/types/stream/Stream.d.ts","../../node_modules/fast-check/lib/types/check/arbitrary/definition/Value.d.ts","../../node_modules/fast-check/lib/types/check/arbitrary/definition/Arbitrary.d.ts","../../node_modules/fast-check/lib/types/check/precondition/PreconditionFailure.d.ts","../../node_modules/fast-check/lib/types/check/property/IRawProperty.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/MaxLengthFromMinLength.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/RandomType.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/VerbosityLevel.d.ts","../../node_modules/fast-check/lib/types/check/runner/reporter/ExecutionStatus.d.ts","../../node_modules/fast-check/lib/types/check/runner/reporter/ExecutionTree.d.ts","../../node_modules/fast-check/lib/types/check/runner/reporter/RunDetails.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/Parameters.d.ts","../../node_modules/fast-check/lib/types/check/runner/configuration/GlobalParameters.d.ts","../../node_modules/fast-check/lib/types/check/property/AsyncProperty.generic.d.ts","../../node_modules/fast-check/lib/types/check/property/AsyncProperty.d.ts","../../node_modules/fast-check/lib/types/check/property/Property.generic.d.ts","../../node_modules/fast-check/lib/types/check/property/Property.d.ts","../../node_modules/fast-check/lib/types/check/runner/Runner.d.ts","../../node_modules/fast-check/lib/types/check/runner/Sampler.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/builders/GeneratorValueBuilder.d.ts","../../node_modules/fast-check/lib/types/arbitrary/gen.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/DepthContext.d.ts","../../node_modules/fast-check/lib/types/arbitrary/array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigInt.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigIntN.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigUint.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigUintN.d.ts","../../node_modules/fast-check/lib/types/arbitrary/boolean.d.ts","../../node_modules/fast-check/lib/types/arbitrary/falsy.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ascii.d.ts","../../node_modules/fast-check/lib/types/arbitrary/base64.d.ts","../../node_modules/fast-check/lib/types/arbitrary/char.d.ts","../../node_modules/fast-check/lib/types/arbitrary/char16bits.d.ts","../../node_modules/fast-check/lib/types/arbitrary/fullUnicode.d.ts","../../node_modules/fast-check/lib/types/arbitrary/hexa.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicode.d.ts","../../node_modules/fast-check/lib/types/arbitrary/constant.d.ts","../../node_modules/fast-check/lib/types/arbitrary/constantFrom.d.ts","../../node_modules/fast-check/lib/types/arbitrary/context.d.ts","../../node_modules/fast-check/lib/types/arbitrary/date.d.ts","../../node_modules/fast-check/lib/types/arbitrary/clone.d.ts","../../node_modules/fast-check/lib/types/arbitrary/dictionary.d.ts","../../node_modules/fast-check/lib/types/arbitrary/emailAddress.d.ts","../../node_modules/fast-check/lib/types/arbitrary/double.d.ts","../../node_modules/fast-check/lib/types/arbitrary/float.d.ts","../../node_modules/fast-check/lib/types/arbitrary/compareBooleanFunc.d.ts","../../node_modules/fast-check/lib/types/arbitrary/compareFunc.d.ts","../../node_modules/fast-check/lib/types/arbitrary/func.d.ts","../../node_modules/fast-check/lib/types/arbitrary/domain.d.ts","../../node_modules/fast-check/lib/types/arbitrary/integer.d.ts","../../node_modules/fast-check/lib/types/arbitrary/maxSafeInteger.d.ts","../../node_modules/fast-check/lib/types/arbitrary/maxSafeNat.d.ts","../../node_modules/fast-check/lib/types/arbitrary/nat.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ipV4.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ipV4Extended.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ipV6.d.ts","../../node_modules/fast-check/lib/types/arbitrary/letrec.d.ts","../../node_modules/fast-check/lib/types/arbitrary/lorem.d.ts","../../node_modules/fast-check/lib/types/arbitrary/mapToConstant.d.ts","../../node_modules/fast-check/lib/types/arbitrary/memo.d.ts","../../node_modules/fast-check/lib/types/arbitrary/mixedCase.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_shared/StringSharedConstraints.d.ts","../../node_modules/fast-check/lib/types/arbitrary/string.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/QualifiedObjectConstraints.d.ts","../../node_modules/fast-check/lib/types/arbitrary/object.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/helpers/JsonConstraintsBuilder.d.ts","../../node_modules/fast-check/lib/types/arbitrary/json.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicodeJson.d.ts","../../node_modules/fast-check/lib/types/arbitrary/anything.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicodeJsonValue.d.ts","../../node_modules/fast-check/lib/types/arbitrary/jsonValue.d.ts","../../node_modules/fast-check/lib/types/arbitrary/oneof.d.ts","../../node_modules/fast-check/lib/types/arbitrary/option.d.ts","../../node_modules/fast-check/lib/types/arbitrary/record.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uniqueArray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/infiniteStream.d.ts","../../node_modules/fast-check/lib/types/arbitrary/asciiString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/base64String.d.ts","../../node_modules/fast-check/lib/types/arbitrary/fullUnicodeString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/hexaString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/string16bits.d.ts","../../node_modules/fast-check/lib/types/arbitrary/stringOf.d.ts","../../node_modules/fast-check/lib/types/arbitrary/unicodeString.d.ts","../../node_modules/fast-check/lib/types/arbitrary/subarray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/shuffledSubarray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/tuple.d.ts","../../node_modules/fast-check/lib/types/arbitrary/ulid.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uuid.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uuidV.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webAuthority.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webFragments.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webPath.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webQueryParameters.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webSegment.d.ts","../../node_modules/fast-check/lib/types/arbitrary/webUrl.d.ts","../../node_modules/fast-check/lib/types/check/model/command/ICommand.d.ts","../../node_modules/fast-check/lib/types/check/model/command/AsyncCommand.d.ts","../../node_modules/fast-check/lib/types/check/model/command/Command.d.ts","../../node_modules/fast-check/lib/types/check/model/commands/CommandsContraints.d.ts","../../node_modules/fast-check/lib/types/arbitrary/commands.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/interfaces/Scheduler.d.ts","../../node_modules/fast-check/lib/types/arbitrary/scheduler.d.ts","../../node_modules/fast-check/lib/types/check/model/ModelRunner.d.ts","../../node_modules/fast-check/lib/types/check/symbols.d.ts","../../node_modules/fast-check/lib/types/utils/hash.d.ts","../../node_modules/fast-check/lib/types/utils/stringify.d.ts","../../node_modules/fast-check/lib/types/check/runner/utils/RunDetailsFormatter.d.ts","../../node_modules/fast-check/lib/types/arbitrary/_internals/builders/TypedIntArrayArbitraryBuilder.d.ts","../../node_modules/fast-check/lib/types/arbitrary/int8Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/int16Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/int32Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint8Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint8ClampedArray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint16Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/uint32Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/float32Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/float64Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/sparseArray.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigInt64Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/bigUint64Array.d.ts","../../node_modules/fast-check/lib/types/arbitrary/stringMatching.d.ts","../../node_modules/fast-check/lib/types/arbitrary/noShrink.d.ts","../../node_modules/fast-check/lib/types/arbitrary/noBias.d.ts","../../node_modules/fast-check/lib/types/arbitrary/limitShrink.d.ts","../../node_modules/fast-check/lib/types/fast-check-default.d.ts","../../node_modules/fast-check/lib/types/fast-check.d.ts","./src/extension.properties.test.ts","./src/watcher/FileWatcher.ts","../../node_modules/@socket.io/component-emitter/lib/cjs/index.d.ts","../../node_modules/engine.io-parser/build/esm/commons.d.ts","../../node_modules/engine.io-parser/build/esm/encodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/decodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/index.d.ts","../../node_modules/engine.io-client/build/esm/transport.d.ts","../../node_modules/engine.io-client/build/esm/globals.node.d.ts","../../node_modules/engine.io-client/build/esm/socket.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling-xhr.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling-xhr.node.d.ts","../../node_modules/engine.io-client/build/esm/transports/websocket.d.ts","../../node_modules/engine.io-client/build/esm/transports/websocket.node.d.ts","../../node_modules/engine.io-client/build/esm/transports/webtransport.d.ts","../../node_modules/engine.io-client/build/esm/transports/index.d.ts","../../node_modules/engine.io-client/build/esm/util.d.ts","../../node_modules/engine.io-client/build/esm/contrib/parseuri.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling-fetch.d.ts","../../node_modules/engine.io-client/build/esm/index.d.ts","../../node_modules/socket.io-parser/build/esm/index.d.ts","../../node_modules/socket.io-client/build/esm/socket.d.ts","../../node_modules/socket.io-client/build/esm/manager.d.ts","../../node_modules/socket.io-client/build/esm/index.d.ts","./src/websocket/WebSocketClient.ts","./src/editors/adapters/types.ts","./src/editors/adapters/EditorRegistry.ts","./src/editors/adapters/ContinueAdapter.ts","./src/editors/adapters/KiroAdapter.ts","./src/editors/adapters/CursorAdapter.ts","./src/editors/adapters/AntigravityAdapter.ts","./src/extension.ts","./src/extension.test.ts","./src/diff/DiffGenerator.performance.test.ts","./src/diff/DiffGenerator.properties.test.ts","./src/diff/DiffGenerator.test.ts","./src/editors/adapters/AntigravityAdapter.test.ts","./src/editors/adapters/ContinueAdapter.properties.test.ts","./src/editors/adapters/ContinueAdapter.test.ts","./src/editors/adapters/CursorAdapter.properties.test.ts","./src/editors/adapters/CursorAdapter.test.ts","./src/editors/adapters/EditorRegistry.properties.test.ts","./src/editors/adapters/EditorRegistry.test.ts","./src/editors/adapters/KiroAdapter.test.ts","./src/git/GitIntegrationModule.performance.test.ts","./src/git/GitIntegrationModule.properties.test.ts","./src/git/GitIntegrationModule.test.ts","./src/watcher/FileWatcher.performance.test.ts","./src/watcher/FileWatcher.properties.test.ts","./src/watcher/FileWatcher.test.ts","./src/websocket/WebSocketClient.properties.test.ts","./src/websocket/WebSocketClient.test.ts","../../node_modules/vitest/globals.d.ts"],"fileIdsList":[[48,67,113],[67,113],[67,110,113],[67,112,113],[113],[67,113,118,146],[67,113,114,119,124,132,143,154],[67,113,114,115,124,132],[62,63,64,67,113],[67,113,116,155],[67,113,117,118,125,133],[67,113,118,143,151],[67,113,119,121,124,132],[67,112,113,120],[67,113,121,122],[67,113,123,124],[67,112,113,124],[67,113,124,125,126,143,154],[67,113,124,125,126,139,143,146],[67,113,121,124,127,132,143,154],[67,113,124,125,127,128,132,143,151,154],[67,113,127,129,143,151,154],[65,66,67,68,69,70,71,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160],[67,113,124,130],[67,113,131,154,159],[67,113,121,124,132,143],[67,113,133],[67,113,134],[67,112,113,135],[67,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160],[67,113,137],[67,113,138],[67,113,124,139,140],[67,113,139,141,155,157],[67,113,124,143,144,146],[67,113,145,146],[67,113,143,144],[67,113,146],[67,113,147],[67,110,113,143,148],[67,113,124,149,150],[67,113,149,150],[67,113,118,132,143,151],[67,113,152],[67,113,132,153],[67,113,127,138,154],[67,113,118,155],[67,113,143,156],[67,113,131,157],[67,113,158],[67,108,113],[67,108,113,124,126,135,143,146,154,157,159],[67,113,143,160],[51,55,67,113],[67,113,199],[51,52,55,56,58,67,113],[51,67,113],[51,52,55,67,113],[51,52,67,113],[60,67,113],[67,113,195],[50,67,113,195],[50,67,113,195,196],[67,113,209],[67,113,203],[54,67,113],[50,53,67,113],[46,67,113],[46,47,50,67,113],[50,67,113],[57,67,113],[67,113,395,396,397,399,400,401,402,403,404,405,406,407],[67,113,390,394,395,396],[67,113,390,394,397],[67,113,400,402,403],[67,113,398],[67,113,390,394,396,397,398],[67,113,399],[67,113,395],[67,113,394,395],[67,113,394,401],[67,113,391],[67,113,391,392,393],[67,113,264],[67,113,267],[67,113,267,324],[67,113,264,267,324],[67,113,264,325],[67,113,264,267,283],[67,113,264,323],[67,113,264,369],[67,113,264,358,359,360],[67,113,264,267],[67,113,264,267,306],[67,113,264,267,305],[67,113,264,281],[67,113,262,264],[67,113,264,327],[67,113,264,362],[67,113,264,267,351],[67,113,261,262,263],[67,113,358,359,363],[67,113,357],[67,113,264,275],[67,113,266,274],[67,113,261,262,263,265],[67,113,264,277],[67,113,266,272,273,276,278],[67,113,264,266,273],[67,113,267,273],[67,113,260,268,269,272],[67,113,270],[67,113,269,271,273],[67,113,272],[67,113,245,261,262,263,264,265,266,267,268,269,270,271,272,273,274,276,278,279,280,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,324,326,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385],[67,113,386],[67,113,260],[67,113,184],[67,113,182,184],[67,113,173,181,182,183,185,187],[67,113,171],[67,113,174,179,184,187],[67,113,170,187],[67,113,174,175,178,179,180,187],[67,113,174,175,176,178,179,187],[67,113,171,172,173,174,175,179,180,181,183,184,185,187],[67,113,169,171,172,173,174,175,176,178,179,180,181,182,183,184,185,186],[67,113,169,187],[67,113,174,176,177,179,180,187],[67,113,178,187],[67,113,179,180,184,187],[67,113,172,182],[49,67,113],[67,113,246],[67,113,246,251,252],[67,113,246,251],[67,113,246,252],[67,113,246,247,248,249,250,251,253,254,255,256,257,258],[67,113,259],[67,113,162,163],[67,113,215,217],[67,113,217],[67,113,215],[67,113,213,217,238],[67,113,213,217],[67,113,238],[67,113,217,238],[67,113,114,214,216],[67,113,215,232,233,234,235],[67,113,219,231,236,237],[67,113,212,218],[67,113,219,231,236],[67,113,212,217,218,220,221,222,223,224,225,226,227,228,229,230],[67,113,408,409,410,411],[67,113,390,408,409,410],[67,113,390,409,411],[67,113,390],[67,80,84,113,154],[67,80,113,143,154],[67,75,113],[67,77,80,113,151,154],[67,113,132,151],[67,113,161],[67,75,113,161],[67,77,80,113,132,154],[67,72,73,76,79,113,124,143,154],[67,80,87,113],[67,72,78,113],[67,80,101,102,113],[67,76,80,113,146,154,161],[67,101,113,161],[67,74,75,113,161],[67,80,113],[67,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,102,103,104,105,106,107,113],[67,80,95,113],[67,80,87,88,113],[67,78,80,88,89,113],[67,79,113],[67,72,75,80,113],[67,80,84,88,89,113],[67,84,113],[67,78,80,83,113,154],[67,72,77,80,87,113],[67,113,143],[67,75,80,101,113,159,161],[67,113,192,193],[67,113,192],[67,113,191,192,193,206],[67,113,124,125,127,128,129,132,143,151,154,160,161,163,164,165,166,167,168,187,188,189,190],[67,113,164,165,166,167],[67,113,164,165,166],[67,113,164],[67,113,165],[67,113,163],[51,55,59,61,67,113,125,143,159,191,194,197,198,200,201,202,204,205,206,207,208,210],[51,59,61,67,113,125,143,159,191,194,197,198,200,201,202,204,205,206],[59,61,67,113,201,206],[67,113,211],[67,113,126,133,134,211,387],[67,113,126,211,239,242,387],[67,113,126,211,239,242],[67,113,126,239,241],[67,113,211,239,419],[67,113,239,414],[67,113,211,239,387,416],[67,113,211,239,416],[67,113,211,239,387,416,417,418],[67,113,211,239,418],[67,113,211,387,414,415],[67,113,211,414,415],[67,113,414],[67,113,211,239,417],[67,113,126,211,238,240,242],[67,113,126,133,134,211,238],[67,113,211,241,387],[67,113,126,211,239,240,241,242,389,413,415,420],[67,113,118,155,160,239,240,241,242,389,413,415,416,417,418,419],[67,113,126,133,134,211,238,387],[67,113,211,238,239,240,387],[67,113,211,238,239,240],[67,113,238,239],[67,113,211,387],[67,113,211,239,387,389],[67,113,211,239,389],[67,113,239],[67,113,211,241,387,412,413],[67,113,211,241,412,413],[67,113,241,412]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"3deed5e2a5f1e7590d44e65a5b61900158a3c38bac9048462d38b1bc8098bb2e","impliedFormat":99},{"version":"d435a43f89ed8794744c59d72ce71e43c1953338303f6be9ef99086faa8591d7","impliedFormat":99},{"version":"c085e9aa62d1ae1375794c1fb927a445fa105fed891a7e24edbb1c3300f7384a","impliedFormat":1},{"version":"f315e1e65a1f80992f0509e84e4ae2df15ecd9ef73df975f7c98813b71e4c8da","impliedFormat":1},{"version":"5b9586e9b0b6322e5bfbd2c29bd3b8e21ab9d871f82346cb71020e3d84bae73e","impliedFormat":1},{"version":"a4f64e674903a21e1594a24c3fc8583f3a587336d17d41ade46aa177a8ab889b","impliedFormat":99},{"version":"b6f69984ffcd00a7cbcef9c931b815e8872c792ed85d9213cb2e2c14c50ca63a","impliedFormat":99},{"version":"2bbc5abe5030aa07a97aabd6d3932ed2e8b7a241cf3923f9f9bf91a0addbe41f","impliedFormat":99},{"version":"1e5e5592594e16bcf9544c065656293374120eb8e78780fb6c582cc710f6db11","impliedFormat":99},{"version":"05c7aef6a4e496b93c2e682cced8903c0dfe6340d04f3fe616176e2782193435","impliedFormat":99},{"version":"4abf1e884eecb0bf742510d69d064e33d53ac507991d6c573958356f920c3de4","impliedFormat":99},{"version":"44f1d2dd522c849ca98c4f95b8b2bc84b64408d654f75eb17ec78b8ceb84da11","impliedFormat":99},{"version":"500a67e158e4025f27570ab6a99831680852bb45a44d4c3647ab7567feb1fb4c","impliedFormat":99},{"version":"89edc5e1739692904fdf69edcff9e1023d2213e90372ec425b2f17e3aecbaa4a","impliedFormat":99},{"version":"e7d5bcffc98eded65d620bc0b6707c307b79c21d97a5fb8601e8bdf2296026b6","impliedFormat":99},{"version":"e666e31d323fef5642f87db0da48a83e58f0aaf9e3823e87eabd8ec7e0441a36","impliedFormat":99},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"2fd4c143eff88dabb57701e6a40e02a4dbc36d5eb1362e7964d32028056a782b","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e456fd5b101271183d99a9087875a282323e3a3ff0d7bcf1881537eaa8b8e63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"0225ecb9ed86bdb7a2c7fd01f1556906902929377b44483dc4b83e03b3ef227d","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"ddc734b4fae82a01d247e9e342d020976640b5e93b4e9b3a1e30e5518883a060","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"05db535df8bdc30d9116fe754a3473d1b6479afbc14ae8eb18b605c62677d518","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"4e741b9c88e80c9e4cedf07b5a698e8e3a3bd73cf649f664d6dd3f868c05c2f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","impliedFormat":1},{"version":"6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","impliedFormat":1},{"version":"cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","impliedFormat":1},{"version":"8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87","impliedFormat":99},{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true,"impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","impliedFormat":1},{"version":"333caa2bfff7f06017f114de738050dd99a765c7eb16571c6d25a38c0d5365dc","impliedFormat":1},{"version":"e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","impliedFormat":1},{"version":"459920181700cec8cbdf2a5faca127f3f17fd8dd9d9e577ed3f5f3af5d12a2e4","impliedFormat":1},{"version":"4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","impliedFormat":1},{"version":"7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","impliedFormat":1},{"version":"70790a7f0040993ca66ab8a07a059a0f8256e7bb57d968ae945f696cbff4ac7a","impliedFormat":1},{"version":"d1b9a81e99a0050ca7f2d98d7eedc6cda768f0eb9fa90b602e7107433e64c04c","impliedFormat":1},{"version":"a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","impliedFormat":1},{"version":"b215c4f0096f108020f666ffcc1f072c81e9f2f95464e894a5d5f34c5ea2a8b1","impliedFormat":1},{"version":"644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","impliedFormat":1},{"version":"dfe54dab1fa4961a6bcfba68c4ca955f8b5bbeb5f2ab3c915aa7adaa2eabc03a","impliedFormat":1},{"version":"1251d53755b03cde02466064260bb88fd83c30006a46395b7d9167340bc59b73","impliedFormat":1},{"version":"47865c5e695a382a916b1eedda1b6523145426e48a2eae4647e96b3b5e52024f","impliedFormat":1},{"version":"4cdf27e29feae6c7826cdd5c91751cc35559125e8304f9e7aed8faef97dcf572","impliedFormat":1},{"version":"331b8f71bfae1df25d564f5ea9ee65a0d847c4a94baa45925b6f38c55c7039bf","impliedFormat":1},{"version":"2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","impliedFormat":1},{"version":"0146fd6262c3fd3da51cb0254bb6b9a4e42931eb2f56329edd4c199cb9aaf804","impliedFormat":1},{"version":"82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","impliedFormat":99},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","impliedFormat":1},{"version":"257b83faa134d971c738a6b9e4c47e59bb7b23274719d92197580dd662bfafc3","impliedFormat":99},{"version":"4a27c79c57a6692abb196711f82b8b07a27908c94652148d5469887836390116","impliedFormat":99},{"version":"f42400484f181c2c2d7557c0ed3b8baaace644a9e943511f3d35ac6be6eb5257","impliedFormat":99},{"version":"54b381d36b35df872159a8d3b52e8d852659ee805695a867a388c8ccbf57521b","impliedFormat":99},{"version":"c67b4c864ec9dcde25f7ad51b90ae9fe1f6af214dbd063d15db81194fe652223","impliedFormat":99},{"version":"7a4aa00aaf2160278aeae3cf0d2fc6820cf22b86374efa7a00780fbb965923ff","impliedFormat":99},{"version":"66e3ee0a655ff3698be0aef05f7b76ac34c349873e073cde46d43db795b79f04","impliedFormat":99},{"version":"48c411efce1848d1ed55de41d7deb93cbf7c04080912fd87aa517ed25ef42639","affectsGlobalScope":true,"impliedFormat":1},{"version":"28e065b6fb60a04a538b5fbf8c003d7dac3ae9a49eddc357c2a14f2ffe9b3185","affectsGlobalScope":true,"impliedFormat":99},{"version":"fe2d63fcfdde197391b6b70daf7be8c02a60afa90754a5f4a04bdc367f62793d","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":1},{"version":"0d87708dafcde5468a130dfe64fac05ecad8328c298a4f0f2bd86603e5fd002e","impliedFormat":99},{"version":"a3f2554ba6726d0da0ffdc15b675b8b3de4aea543deebbbead845680b740a7fd","impliedFormat":99},{"version":"b7e28e06011460436d5c2ec2996846ac0c451e135357fc5a7269e5665a32fbd7","impliedFormat":99},{"version":"93dda0982b139b27b85dd2924d23e07ee8b4ca36a10be7bdf361163e4ffcc033","impliedFormat":99},{"version":"d7b652822e2a387fd2bcf0b78bcf2b7a9a9e73c4a71c12c5d0bbbb367aea6a87","affectsGlobalScope":true,"impliedFormat":99},{"version":"cb80558784fc93165b64809b3ba66266d10585d838709ebf5e4576f63f9f2929","impliedFormat":99},{"version":"dfa6bb848807bc5e01e84214d4ec13ee8ffe5e1142546dcbb32065783a5db468","impliedFormat":99},{"version":"2f1ffc29f9ba7b005c0c48e6389536a245837264c99041669e0b768cfab6711d","impliedFormat":99},{"version":"f2d1a59a658165341b0e2b7879aa2e19ea6a709146b2d3f70ee8a07159d3d08e","impliedFormat":99},{"version":"b4270f889835e50044bf80e479fef2482edd69daf4b168f9e3ee34cf817ae41a","impliedFormat":99},{"version":"16b81141d0c59af6f07e5fc24824c54dd6003da0ab0a2d2cedc95f8eb03ea8d3","impliedFormat":1},{"version":"6578758b0b94087beffd0ce554701365cd1e6a7428f14464ac8b88095fca4e50","impliedFormat":1},{"version":"b6c4796630a47f8b0f420519cd241e8e7701247b48ed4b205e8d057cbf7107d7","impliedFormat":1},{"version":"6256cf36c8ae7e82bff606595af8fe08a06f8478140fcf304ee2f10c7716ddc8","impliedFormat":1},{"version":"b2dbe6b053e04ec135c7ce722e0a4e9744281ea40429af96e2662cc926465519","impliedFormat":1},{"version":"95cc177eacf4ddd138f1577e69ee235fd8f1ea7c7f160627deb013b39774b94e","impliedFormat":1},{"version":"5619706bbd7a964d7c82cd4a307457ed0327ecc86772ceb7ea0870566c6578b2","impliedFormat":1},{"version":"b48c4e15766170c5003a6273b1d8f17f854ec565ccaaebd9f700fef159b84078","impliedFormat":1},{"version":"7c774169686976056434799723bd7a48348df9d2204b928a0b77920505585214","impliedFormat":1},{"version":"5e95379e81e2d373e5235cedc4579938e39db274a32cfa32f8906e7ff6698763","impliedFormat":1},{"version":"3e697e2186544103572756d80b61fcce3842ab07abdc5a1b7b8d4b9a4136005a","impliedFormat":1},{"version":"8758b438b12ea50fb8b678d29ab0ef42d77abfb801cec481596ce6002b537a6f","impliedFormat":1},{"version":"688a28e7953ef4465f68da2718dc6438aaa16325133a8cb903bf850c63cb4a7e","impliedFormat":1},{"version":"015682a15ef92844685cca5e816b1d21dc2a2cfb5905b556a8e9ca50b236af05","impliedFormat":1},{"version":"f73cf81342d2a25b65179c262ca7c38df023969129094607d0eb52510a56f10f","impliedFormat":1},{"version":"f433d28f86313073f13b16c0a18ccdd21759390f52c8d7bf9d916645b12d16ed","impliedFormat":1},{"version":"e7d7e67bd66b30f2216e4678b97bb09629a2b31766a79119acaa30e3005ef5fb","impliedFormat":1},{"version":"e05a20aa85c7324c65643542c2d7314774c2adf510f9dcbad5d3afac74ca3dac","impliedFormat":1},{"version":"e137f087bda0256410b28743ef9a1bf57a4cafd43ffa6b62d5c17a8f5a08b3b5","impliedFormat":1},{"version":"b1e92e9b96cacb98a39acc958670ac895c3b2bb05d8810497310b6b678c46acc","impliedFormat":1},{"version":"af504042a6db047c40cc0aeb14550bbc954f194f2b8c5ad8944f2da502f45bf5","impliedFormat":1},{"version":"5b25b6ab5ad6c17f90b592162b2e9978ad8d81edf24cd3957306eb6e5edb89a9","impliedFormat":1},{"version":"24693bd77ac3be0b16e564d0ab498a397feb758ce7f4ed9f13478d566e3aafde","impliedFormat":1},{"version":"208dad548b895c7d02465de6ba79064b7c67bc4d94e5227b09f21d58790e634c","impliedFormat":1},{"version":"048c0ced65fa41fbf4bcc3d5e8e5b6f6c7f27335ceb54d401be654e821adbc08","impliedFormat":1},{"version":"919565c378b8a4919ac9e2d1b5dbbd230c9d3dbb951e4d77c8137bce27bcc280","impliedFormat":1},{"version":"9a57d654b0a0e4bf56a8eb0aa3ede1c7d349cec6220e36b5288c26626c8688ed","impliedFormat":1},{"version":"dd31f9423525b3eaaba877d290a0a648f2ea774c2ff946611905e949d6078ee6","affectsGlobalScope":true,"impliedFormat":1},{"version":"82045568843ec70b4d71b04456ee731c55d927fe7798b4f9c0e5deb27efa6fea","signature":"ca0fb8bb51cb98487feade895431b8e6fe32db6e54934e2a4e317b67d238ac59"},"5903e5db3aa79385274da245d1970fe1b124eb2f686c13335fffedbc843af701",{"version":"7a51079d45f381f44bab0e2a87a687281def4a5ebcd87e3b8e4a29edd344a512","signature":"b40f0bcde2c563510b5ed092d5759d75c446aca764e270f0b24c5b353ab2391c"},{"version":"40d71cb21176fd9a0ba4b1944b5f1f2f99a1b3ac4c9b9c818358c46286bfebb8","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"08800dd43cd2db7d278f2b0f7a4a2427568c8ba41ba1e474b5b3b7221d78d518","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"b98cbe170e5774f6d9c364eef2a71dff38705390eada04670643271d436e44cd","impliedFormat":1},{"version":"2c1c7ebb6588ca14ec62bc2a19497b6378de25ab5d6a6241f4b8973f5f314faf","impliedFormat":1},{"version":"cefbdbc7607e7d32560385e018b991e18075f9b3b5b952f3b5f20478e4d15c43","impliedFormat":1},{"version":"72339629fd17518e8de4e495b0d91908a938fc4774457f09896789d40eb238b5","impliedFormat":1},{"version":"d0e5421dc798ee8146f82eddd6b96135f662e9a905c3afe400a029eea5b405a8","impliedFormat":1},{"version":"7a0a70d6f7ba13c11bb570a45000e6e428210ec2e1bdb8cbac46c90dfef698e8","impliedFormat":1},{"version":"b375d410108bcc3dab93dbc1de2b64777efac618025dbe675f1b2bfb63a91462","impliedFormat":1},{"version":"e352c35e7a226a5ff81bc9139e6e41bd5990f291a123de224987f5da34e2f725","impliedFormat":1},{"version":"3b416138214e8f4213e911723cf7f383ebdaa97e369687819452b53576980caf","impliedFormat":1},{"version":"faaed6dc3c93ac12afa83fc1a8ac384820437272622308b07f250650e16de120","impliedFormat":1},{"version":"16c28b35bb61fd8937b9ac446744601840e4d135ee863459259973e43d9ac458","impliedFormat":1},{"version":"4dd9018777b9b3feb8a7705841e3322000b3fa9dbb52aeaa7f189a4a408312f5","impliedFormat":1},{"version":"b91e472a9547e0d6e75b114c6d08d2e916174528f71c7473922d74018b9f9b93","impliedFormat":1},{"version":"c04a9cc39d447fa332a52e687b3ecd55165626c4305c1037d02afffd7020867c","impliedFormat":1},{"version":"e41e2bc86051b0f41d5ec99e728127e461b48152b6fb4735822b7fa4b4b0bc77","impliedFormat":1},{"version":"b49e721e29f8bb94b61bf8121a13965cced1b57cd088fb511c25a93c4ddfc1ac","impliedFormat":1},{"version":"24ff411ed19b006ec0efbdc5d56abd5f8a2a605eff97eb3db0941719c19e0844","impliedFormat":1},{"version":"190123e7b32a1a44dcc6b5b397cfd61c452606ea287576679d18f046b9296bf0","impliedFormat":1},{"version":"aeb54b9213fe90552e5e032abd0485d7ed21d505e59782b5e15c344a4ee54db6","impliedFormat":1},{"version":"51a201487cc0049e538a406c884d28b6d2ab141dd9c0650190b791c63803cae8","impliedFormat":1},{"version":"cb37d06c94592039ce1fa54d73ed241115494d886ee84800f3639cce48d0f832","impliedFormat":1},{"version":"82120a297fdf2f0bd9fa877f0c82b26bd9a94635536aa0ab59fe3ec78086f219","impliedFormat":1},{"version":"63aa0a9aa26aced773af0a69efe0cb58e12c7fc1257d1dcf951e9c301da67aee","impliedFormat":1},{"version":"fe9157ed26e6ab75adeead0164445d4ef49978baf2f9d2a5e635faf684d070d4","impliedFormat":1},{"version":"d0a02c12e4fb6b7c666773485e1ea53cdaa02b5b7c9483f370dccf1c815ff385","impliedFormat":1},{"version":"554edc2633760ba1c6ced5ce1e65586fe45f37c1f9f76052f68eadc4a06007b4","impliedFormat":1},{"version":"7c3335010a48156bb5eaa5866aeda1f0bf9a2402500e3cd3d047ca7b34f42dda","impliedFormat":1},{"version":"5d62771188e40ff7468d7f28ea5ed207ec0bce364e59e0fbf3e0c3ec794ddbf8","impliedFormat":1},{"version":"e6affb59098efce161ef8874843ecb1ebfed74f7374af0ce36ec4c9d1a370790","impliedFormat":1},{"version":"16cb0961a5f64defa068e4ce8482ed2e081bf1db2593205cca16f89f7d607b17","impliedFormat":1},{"version":"03bf2b2eee330dd7583c915349d75249ea3e4e2e90c9cc707957c22a37072f38","impliedFormat":1},{"version":"30ba32b82c39057e1f67f0ba14784836148a16d0c6feb5346d17b89559aadacc","impliedFormat":1},{"version":"f68437efcfd89bb312891b1e85e2ff4aa8fafcf0b648fc8d4726158aa4071252","impliedFormat":1},{"version":"dafb6d7587402ec60c4dd7129c8f84eb4af66c9f6b20c286b9dde8f316b9c7f2","impliedFormat":1},{"version":"598c2c581e6bd9171a59ef6ec9ce60d0eddcab49bd9db53a90d169c2387ec908","impliedFormat":1},{"version":"95ba818edf3770e357e9bbe6f55c9227a0041cb2460fff50e9d9e35ce7d23718","impliedFormat":1},{"version":"29a04903692cd5533c3c48c669361876522bde9f594f56d27589886157ad4894","impliedFormat":1},{"version":"d0e6175eb404f3de20b6e7168742eb3c9af55306209b3874ac0f946ac62158d3","impliedFormat":1},{"version":"3e8cfafb493180ef840f481750b49452001e5d80942a2a5d5151deae67b21465","impliedFormat":1},{"version":"d75c6765136563e3155b55220801379cbf1488eb42d7950afe1f94e1c8fde3e8","impliedFormat":1},{"version":"0126291175f486dcb5d8fceb57718c71c9ace7403987724127f373fd6696d067","impliedFormat":1},{"version":"01196174fb4b03fc4cba712a6e5150336b14d232d850dca2c9576d005f434715","impliedFormat":1},{"version":"16a8a7425362ec7531791fc18d2350f9801c483180cc93266c04b66e9676c464","impliedFormat":1},{"version":"63461bf37e9ef045b528e4f2182000922166e1c9729621f56984171cf49f2a8a","impliedFormat":1},{"version":"905fcafee4ebea900d9beec4fbff2b4c2551442da865733e1583085a4dc906d6","impliedFormat":1},{"version":"fe8165682f31b1f82cb93d62a759f1a26eaea745c361fbe2884134b73094d738","impliedFormat":1},{"version":"9b5d632d6f656382a85d3e77330cbf1eb27ed7290e9b3db0cd2663cf9251c6b8","impliedFormat":1},{"version":"2fc74eb5983a1a5986374eac99302432698a97186e577e91aa59b3ff91e657ec","impliedFormat":1},{"version":"ec767f9a0beefc9fc710bb0e5fc77f67468bb3b3fa34b9ebb8f72cd4f9fe2209","impliedFormat":1},{"version":"5fda99f644f00fb41efe3dfe936dc66d6f1d8d4abec93bf9735c4af3f70233dd","impliedFormat":1},{"version":"ceda7e9320a5a86ea760bb70c3c3b2278e01977b2cf30050ac9dfa80528e3442","impliedFormat":1},{"version":"d492ee06385287cce63b4173f7e553b7877464789598b03cec6b35ca2a64f9dd","impliedFormat":1},{"version":"2a0d3ddee69590b52ddec7eecfe8385fc2c54b3e2fd402439abe6b1c962434a6","impliedFormat":1},{"version":"55e6253bf987f95c86280b7bbb40500b5f5a21bfe890f166e647b864d3a7b8c5","impliedFormat":1},{"version":"efc4c4273bdda552afb3425998d95d87cb57a9e119734109c2282b3a378b305a","impliedFormat":1},{"version":"afb6cc0af49d24e5d787de77d5b46f05ecaea444f73829d60fcf6ceb76e608eb","impliedFormat":1},{"version":"882e89116341394e371cd8f24bc2e38239400276da03d3c38c9c9fe6b244fb1f","impliedFormat":1},{"version":"7d17be79ca035a9b8e02ba11f6351cea1bafd38c27a8004a401474ac2aa6695e","impliedFormat":1},{"version":"8e89f4377964cc23d5fe3bed390e5a415926f124a7cc7963d5e7bbce823e9887","impliedFormat":1},{"version":"7f6cdf4d7129c667eabf8c87b1798d5578623e39c42a3ff1aad742561e863858","impliedFormat":1},{"version":"ea5885ba5e792e0b88dc39f51b6b6c6c789d8fe2116bce3905f01d790f59c10d","impliedFormat":1},{"version":"0e09f1810ab7821d9d3c967323ec9cfa042cd9a1d8c3e8af4ed9b6dae4e63f86","impliedFormat":1},{"version":"f089bbeb3f2f0c528d3382fdea9cbb282ce252c918497e7abb974804f4faae1e","impliedFormat":1},{"version":"e57ad5997f573113f39391e780098560a341556b8d55d07b02675afbd72d82cf","impliedFormat":1},{"version":"896ed9bc9650a9ad6ead21583c007463217edeb58a4f45d1d019c1926b684643","impliedFormat":1},{"version":"7976b4472cfda91c462250daf51eae6e1121c2d725e4812d5c89019bb00e9551","impliedFormat":1},{"version":"901807bd11ececb52f0a2586689dacabf0e14f15e5e0604a673c9e1ff8186412","impliedFormat":1},{"version":"c9ebb2be9fc78b6df354c69b646c37945da54464389ce4342a0fd9cebc731f19","impliedFormat":1},{"version":"3f9a0317283412268b02f47fb3c83920a3b6a6c506898cef7e6ed42d5aff8d45","impliedFormat":1},{"version":"9de11c7d313d848291ec1a850637cc23dc7978f7350541af3314f7b343287d11","impliedFormat":1},{"version":"23f76b69848fe41a4801c7df41cf22bb380ad3fefc5adf2f7026d60f9f0451ba","impliedFormat":1},{"version":"ec17da14f94c8fddb8adeb4277b2cdd75f592095c4236db613853fe569ddb7b9","impliedFormat":1},{"version":"48ade6580bd1b0730427316352920606ff854f6a4548d2dee073fab4eecc6e62","impliedFormat":1},{"version":"5975ac1e6043d47f6771a0219b66530c23f05d1a27743091203ee7f6ea0f3a7b","impliedFormat":1},{"version":"e84b43d807d525da4dcd996ecf63e17245649672c2f620e84faed87e518ad639","impliedFormat":1},{"version":"2dbf4764d09250ec5850b5cd5ab47f72c9a16add6c73bd1f1ebfb55aefbb35d7","impliedFormat":1},{"version":"d147d653b19c446e14cc941c2a96eb111512702f765e086a450c5b720d2128b6","impliedFormat":1},{"version":"e9f2adc30882f676aa8109beeb32f2229da408f3ff25cd66b18e0d65fc162e51","impliedFormat":1},{"version":"1cc2419f7786055521ea0985b44dd961563a645dad471de3d6a45b83e686121f","impliedFormat":1},{"version":"9feba5111ddcd564d317f8a5fddd361f451b90fef6a17278134db450febc03a2","impliedFormat":1},{"version":"0b0ab6bb2cce3b6398ea9e01980e3a0d8dd341c6c83fffbcf4b33d3065fdeb76","impliedFormat":1},{"version":"31c5e0d467794830f02766351f8d5e9c2b08e6cc4e739478f798fb243e3eb8ce","impliedFormat":1},{"version":"7855b568645d7fa99b22eb48070c5174cf45c198b9f81abb5cbed6f4e6051a7b","impliedFormat":1},{"version":"fe01241cd36b45f1673814120a682aaa41ee12b62509c46535925ce991cca196","impliedFormat":1},{"version":"e2a3d01be6c9004bb660546b244d0bc3aba49ea6e42af5490afa6bb9eacaf03b","impliedFormat":1},{"version":"d46410a523d938fae1c998fd4317867ea4fd09c90f548070317570682e5fb144","impliedFormat":1},{"version":"3eb7886b8771bb649de71937d1d06a56277f9aa4705d4748ab10e2549cb90051","impliedFormat":1},{"version":"e1b882923b064f7ec2cec07f9ba2c2027d43502eb7fca3ce5444f5b4de8d812b","impliedFormat":1},{"version":"e05f866a0711a3a6059be95921a6c25b4a5a4190c295341ed4958950e491f9c4","impliedFormat":1},{"version":"a2fec5fe18ee1eea9782074951c366b9952f7dfd8282104cf8002821daddd07b","impliedFormat":1},{"version":"a4cf0ab697cbab80d76105244792d400e37a789cc3e783e94afc62290f4524e1","impliedFormat":1},{"version":"cd279bc48f9d44eb6cc4e98155ffbc29489d2ecc0ad8f83fee2956b62b0fbe47","impliedFormat":1},{"version":"b5f586144570a0e7cfb3efa1ae88c5f8b49d3429a0c63b7eecf7e521bffb6ab2","impliedFormat":1},{"version":"d78bef98f2833243f79ec5a6a2b09dc7ff5fc8d02916404c6599eb8596e5c17c","impliedFormat":1},{"version":"fdd66ca2430dd3eb6463f385c3898291d97b64f2e575ab53c101ee92ba073a5b","impliedFormat":1},{"version":"7b8326615d6ba6f85d6eec78447b5734839572075e053f01972e386569eb7cf9","impliedFormat":1},{"version":"5e1fca4ecd38a7a5194bffefb713460610521d1db4835f715d8b7e5132a451ae","impliedFormat":1},{"version":"e008e16c64ee65759e1336db16e538f2360bda6eee86303b7f9875f93566926a","impliedFormat":1},{"version":"4bf01b353ef24f6daf68d4ed15a40d079dbc8402824e41f9b11444c366c87e46","impliedFormat":1},{"version":"47d370c23aae9d4a46d108fbd241c2f4c4293934348fe67c09275863c663ba28","impliedFormat":1},{"version":"4e37aea128d8ee55192de216ec9b5c19b6f5469f2f3888965e878387b87d82ce","impliedFormat":1},{"version":"e0a26715db09e01d895767dad26409fe282b457fb937087066a83cdf7ed1510d","impliedFormat":1},{"version":"5bbc28e15ffe9c3b553b351da50907f3dace4b8f2698e8c633957ccca79f1587","impliedFormat":1},{"version":"d8605eab739e6eff9e5a810953bc8f110c18d4767915070122d8de270d93a539","impliedFormat":1},{"version":"159559d509aee31c698353bf9d021defadfc017acbcaaa979b03e8b9ea4fcdbe","impliedFormat":1},{"version":"ef830fa9b8ac8e1c7d328e632e1f37251c5f178157e0172b7f91bf82a249ae48","impliedFormat":1},{"version":"029c0ae6486c8247533c321d7769087178efe4f339344ed33ccc919d4645a65c","impliedFormat":1},{"version":"c85cc7e94c2b24b4fef57afb0ab6ecfe6d8fd54f8743f8e761ec1b5b2682d147","impliedFormat":1},{"version":"ba833bb474b4778dd0e708e12e5078a0044fdf872b130c23eee4d4d80cf59c1a","impliedFormat":1},{"version":"b22d90f2d362bb4b0ab09d42b5504a9ef1c3f768336c7676d75208cb9bf44fe1","impliedFormat":1},{"version":"ea725cf858cce0fa4c30b1957eebeb3b84c42c87721dc3a9212738adbdad3e47","impliedFormat":1},{"version":"556dc97b6164b18b1ace4ca474da27bc7ec07ed62d2e1f1e5feec7db34ea85e7","impliedFormat":1},{"version":"34f4a5e5abcb889bd4a1c070db50d102facc8d438bc12fbcd28cf10106e5dec8","impliedFormat":1},{"version":"b278e3030409d79aa0587a1327e4a9bc5333e1c6297f13e61e60117d49bac5a7","impliedFormat":1},{"version":"dcb93b7edd87a93bbda3480a506c636243c43849e28c209294f326080acfb4fd","impliedFormat":1},{"version":"f3179b329e1e7c7b8e9879597daa8d08d1a7c0e3409195b3db5adf0c8a972662","impliedFormat":1},{"version":"19d91a46dc5dff804b67c502c0d08348efa8e841b6eaefb938e4e4258b626882","impliedFormat":1},{"version":"550b1bcee751b496b5c54a4de7a747a186487e74971da1a2fb6488df24234dc5","impliedFormat":1},{"version":"6d54746945b9c2b2c88cd64dc22e5c642971dd39c221ba2ad9a602f46c260c31","impliedFormat":1},{"version":"00677cf86a3e8b5b64ac5a3963be34dd4f6e7b4e52fed9332e190b4a41877fba","impliedFormat":1},{"version":"7cae95b5b65941db32f44820159fa81605097327070ce7abc0508084e88d9366","impliedFormat":1},{"version":"82ea80af29aab4e0c39b6198d3b373ab6431b3f30ee02fdb8513fb1d80da2f98","impliedFormat":1},{"version":"6252c4e1c67faebb31907262e329975c9c9574e662b8e1f29a9e1c65f4933fc1","impliedFormat":1},{"version":"7dd32c136b356b80e648966b457bd5dba81e86a7a5e10118e5dc62a91e5d8dff","impliedFormat":1},{"version":"ff2807d90505df16875eb8beb04e6379d751ea5a6412a612aacc1779dc834f6f","impliedFormat":1},{"version":"707d69e35a457a02df69e407bf45c7c2bd770230e61fba69897c706373efda3d","impliedFormat":1},{"version":"ee3f3159fb0eb04322dc08ca0344cada9b1afdbff4bf021ed229ea33418c02bf","impliedFormat":1},{"version":"60a10874f1445d12af58ec3d7d26711b11b95d2432d7a67d591eed8ac42aeecb","impliedFormat":1},{"version":"6b54b93dee5a1c4f2432571fcb8b6846c224e5fa8a3e1d02a08760d202ba24bf","impliedFormat":1},{"version":"5b5af36f2494858b01f8bc22f08a90e7687fb20fe5b89aec9f05fea56ce2f4a7","impliedFormat":1},{"version":"01dc1755f60d10971b43d71562a7ee05deffc7317a88476becef9b30686fcf5d","impliedFormat":1},{"version":"d0e653d9a5f4970098dfd3bf7ff515fcde909d3599cabadd168b49dd3786c1d3","impliedFormat":1},{"version":"2170cbd9e9feba37765aac36f6bced8349b51b70149b96c359ef6e4e581d29cb","impliedFormat":1},{"version":"e5a7066c96dd80d71293afb5c694142d66abc6a649be4bd6bcdf8629f80bd647","impliedFormat":1},{"version":"d144a03dc18068dc788da021f34b96cd0011aa767f0c811fd16e17e0fabafac4","impliedFormat":1},{"version":"41d4348127cac62f18177bfbd6673d7227d08df3c834808b7bbf623220854dcb","impliedFormat":1},{"version":"82f83d1c59621504a282813d2079d319d14134acb9a4e753bc661286b760d93f","impliedFormat":1},{"version":"320f2403a8976b11068464b8c031e9a7418d01e2b226f4a75dbddba2ea071e02","impliedFormat":1},{"version":"2df0f708ce3ca701d9ecb1ad865337b6ece0a464c1db0a4d7beaef0e6c1431c7","impliedFormat":1},{"version":"d0c23c27ab25f8298fbdb57f90d7c9555dd9dedf6c65910491f0502149296bc3","impliedFormat":1},{"version":"a9dc1a642ec16c8b9c319d886b8e4a5bf3737879794b17a6e3c3a8a20b9a8084","impliedFormat":1},{"version":"8d7416be7127d2bcea8591a0a8aeac9ef14e400cb67cba14f93ad2efd78abed8","impliedFormat":1},{"version":"4f76cabb92d767cc8f854a5c26a1ecfa068b6095bb7abf45803f91e16ee817b4","impliedFormat":1},{"version":"17ae0e579dbfb2b01a5709d3d98e4be2b187f3dff9018972c5e74fa31beca63e","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"2564d83bdccf660ca2fe0c9a2eda7938e77b45d4f4cbd1717071bd98a3d6d2af","signature":"aba9c3cc4f9d43a45729e97dc7f724874c995e9928eee24e1195461b715539dd"},{"version":"14ecfc29e0c44ad4c5e50f9b597492cd8f45a2a635db8b5fe911a5da83e26cf8","impliedFormat":1},{"version":"569e762cf47aafdad508360a443c6c757e56c61db3b652b65458a7d168d139c4","impliedFormat":99},{"version":"02ed2766d79a00719ac3cc77851d54bd7197c1b12085ea12126bc2a65068223e","impliedFormat":99},{"version":"4b84373e192b7e0f8569b65eb16857098a6ee279b75d49223db2a751fdd7efde","impliedFormat":99},{"version":"5aeea312cd1d3cc5d72fc8a9c964439d771bdf41d9cce46667471b896b997473","impliedFormat":99},{"version":"1d963927f62a0d266874e19fcecf43a7c4f68487864a2c52f51fbdd7c5cc40d8","impliedFormat":99},{"version":"d7341559b385e668ca553f65003ccc5808d33a475c141798ba841992fef7c056","impliedFormat":99},{"version":"fcf502cbb816413ab8c79176938357992e95c7e0af3aa2ef835136f88f5ad995","impliedFormat":99},{"version":"5c59fd485fff665a639e97e9691a7169f069e24b42ffc1f70442c55720ad3969","impliedFormat":99},{"version":"89c6bcc4f7b19580009a50674b4da0951165c8a2202fa908735ccbe35a5090dd","impliedFormat":99},{"version":"df283af30056ef4ab9cf31350d4b40c0ed15b1032833e32dc974ade50c13f621","impliedFormat":99},{"version":"9de40cf702d52a49d6f3d36d054fc12638348ea3e1fb5f8d53ef8910e7eaa56f","impliedFormat":99},{"version":"2f844dc2e5d3e8d15a951ff3dc39c7900736d8b2be67cc21831b50e5faaa760a","impliedFormat":99},{"version":"ecbbfd67f08f18500f2faaaa5d257d5a81421e5c0d41fa497061d2870b2e39db","impliedFormat":99},{"version":"79570f4dfd82e9ae41401b22922965da128512d31790050f0eaf8bbdb7be9465","impliedFormat":99},{"version":"4b7716182d0d0349a953d1ff31ab535274c63cbb556e88d888caeb5c5602bc65","impliedFormat":99},{"version":"d51809d133c78da34a13a1b4267e29afb0d979f50acbeb4321e10d74380beeea","impliedFormat":99},{"version":"e1dafdb1db7e8b597fc0dbc9e4ea002c39b3c471be1c4439eda14cf0550afe92","impliedFormat":99},{"version":"6ea4f73a90f9914608bd1ab342ecfc67df235ad66089b21f0632264bb786a98e","impliedFormat":99},{"version":"06e9dc3f7549e194e0ed6e46e4ac52dee84bb5973f1e96edc2adff83ff6e6e5f","impliedFormat":99},{"version":"dd018ed60101a59a8e89374e62ed5ab3cb5df76640fc0ab215c9adf8fbc3c4b0","impliedFormat":99},{"version":"8d401f73380bdd30293e1923338e2544d57a9cdbd3dd34b6d24df93be866906e","impliedFormat":99},{"version":"6a33d9e50fc28d0a7431e29fd7a07d7a74ac0218c6c17f9fecbed52a1985ecb5","impliedFormat":99},{"version":"c91aee972b81be2d0df7ea764e4c58472d0bfb1e4ea68c30c003b13a96871a52","signature":"3a02d67e8e78f48a03a675acf0e23f75327f7357bf36f7a31b75325806d15227"},{"version":"0fdb9cbbe2ef5f22151b9b270d1d37bfb4aad0db086f31c2aa529c7e44031bb1","signature":"1558b49afdec2051f6742faff973845ad3eee7b2cf6042cb1b806ce946e7eb96"},{"version":"a13b6da7bc3963aa95828f505c5611bd4818cd2f26667f04387c7bd4bd1da073","signature":"6f979a314192657d1e43b006ba2dea68c5e5f5466d143eb8187484ded2f36ddc"},{"version":"ece6c142923607e451ceeb7470c0c60fb956e8444bae78ef9ccfe589bf006760","signature":"b1c92890355636a3f01df85cd52e61c82fa4306914ddb553a99b41c231d4cfce"},{"version":"11610a39c23fe381816f89226ef694a11a0e40a7091a91acfb18fb1fc460b7e7","signature":"12d76b9de3e454a26d03346dddd1f2691edbf1740856f6c37f3821d7aad401e1"},{"version":"c425e0c8945a5b26bd7edf3cc4f97211c395e620da3d10e90a216e4bbe672026","signature":"46a300915669771a6e74336efbe905fa1cda99e8aa3bb7e6977f85e0abdac7dc"},{"version":"5768c5db9625db9491a0a629168e73a7d86e229289bfc604be684cc61693d45f","signature":"6d152a11ee0377a8290eb14df5855874d9ce7065687c368aad890916f9b4152e"},{"version":"46aad5907f0a0b9e6bdc0c5a372d0eed60f0c25d9602f1d18d206f14f9c3a7fd","signature":"e888f57c70a5655dedf190409bbc1dd992ff56f48b2f4cea147e43ca9258dcf2"},{"version":"d70bab6dbcced5bc51de4fa7ed3a869d2ddcacd9aed4e13410a628d7ba255a70","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"11036871673d85b37945346fbd466c5b2df9fc5dc907f2e9bc5a9bc76342abc3","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"a1e8ef6e41d89c2627b9c1701f5161967e4293314a9b082a442063135b9235f2","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"868367d19acb9a1c4a39e7d459b69ac80b7852ba45ff852a16e189e3b7ccd333","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"8815bd9c5cb0236a0aa463c33bc81b82ddc9e108ed7997d4a1d332b982ebb416","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"d2a74296e8234ba6e73e2b5c84eb8c2b81be6f12a9774a8fd5139b13786b84d9","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"de57f075ce5cb17e7c9068e149eb6a05932b0526c336da51a5255ccee4eb42dc","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"a3206ceb57d78135aa72cd4169c0d836346e94d83f89200ce64a68a16d470e25","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"249c190f63df3d1334f9e4ad13e1c37a2bde9d30eef8ffb038de8cdea4fa1789","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"6e2564fc191638225acbb6a2a4e88f931c9dac1e42cf010549dd5acdf0e12bef","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"01701362aab447c4d9bbee201a3a7fa7ddb5c357b0cee6234e3e04256b54eed8","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"bf73b8e904cd57f024faf84c2c18672173c57ee582465223af0c445f4f1ebcdc","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"2329c5fa50b44d256f4e79d0b6c00fd802e522ca5f5e15858cd1a6042df0ba71","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"598478927e63d732529206bd9aa1aecc7fde77d9445d86630703b0299ce1519a","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"4874ff4e969065ca8151f965791dd76caa2be98ca98c14e84adcb731d5161fce","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"f0ebfb595c44b8ac13c699dc88570bdc9ef826a6a892868dd05e1e19e06c67c9","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"97183dded3b518f1c594dcd0f3ec125452c4a0c532aaca8238b0374786dfaa27","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"47031bb39674fe652f8fe783bf05056439866bf36b48a06e95e2219337dee221","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"185a9bc974412d73a8d31b306a27582a22f99878651da25e68266cb310ffdac3","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"1dab04f92fbab1273a3cdceb0587bee73195456dec6c93ef2a16673ee0e7affd","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"381d27c35f5a5bf6c09dd238ec26fef30a03d12ea84589c621ebc208d7dc8378","affectsGlobalScope":true,"impliedFormat":99}],"root":[240,[242,244],388,389,[413,440]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":1,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":7},"referencedMap":[[49,1],[48,2],[390,2],[162,2],[110,3],[111,3],[112,4],[67,5],[113,6],[114,7],[115,8],[62,2],[65,9],[63,2],[64,2],[116,10],[117,11],[118,12],[119,13],[120,14],[121,15],[122,15],[123,16],[124,17],[125,18],[126,19],[68,2],[66,2],[127,20],[128,21],[129,22],[161,23],[130,24],[131,25],[132,26],[133,27],[134,28],[135,29],[136,30],[137,31],[138,32],[139,33],[140,33],[141,34],[142,2],[143,35],[145,36],[144,37],[146,38],[147,39],[148,40],[149,41],[150,42],[151,43],[152,44],[153,45],[154,46],[155,47],[156,48],[157,49],[158,50],[69,2],[70,2],[71,2],[109,51],[159,52],[160,53],[239,2],[198,2],[199,54],[200,55],[59,56],[52,57],[56,58],[60,59],[61,60],[195,2],[209,61],[196,62],[197,63],[203,63],[210,64],[204,65],[208,2],[55,66],[54,67],[57,67],[47,68],[51,69],[53,70],[46,2],[58,71],[406,2],[396,2],[408,72],[397,73],[395,74],[404,75],[407,76],[399,77],[400,78],[398,79],[401,80],[402,81],[403,80],[405,2],[391,2],[393,82],[392,82],[394,83],[168,2],[281,84],[369,85],[283,2],[327,86],[267,2],[325,87],[362,2],[323,85],[330,88],[284,89],[291,84],[338,90],[292,84],[339,90],[285,84],[380,91],[286,84],[287,84],[381,91],[288,84],[289,84],[293,84],[294,84],[302,84],[361,92],[307,84],[308,84],[298,84],[299,84],[300,84],[301,84],[303,89],[310,93],[305,84],[304,93],[290,84],[306,84],[377,94],[378,95],[295,84],[340,90],[309,84],[282,96],[296,84],[341,90],[337,97],[371,91],[372,91],[370,91],[311,84],[315,84],[316,84],[317,84],[328,98],[332,98],[318,84],[385,84],[319,93],[320,84],[312,84],[313,84],[321,84],[322,84],[314,84],[384,84],[383,84],[326,88],[333,89],[334,89],[335,84],[363,99],[346,84],[379,89],[324,90],[342,90],[382,93],[343,90],[345,84],[347,84],[375,91],[376,91],[373,91],[374,91],[348,84],[297,84],[329,98],[331,98],[344,90],[336,89],[349,84],[350,84],[351,93],[352,93],[353,93],[354,93],[355,93],[356,100],[264,101],[263,2],[364,102],[358,103],[359,103],[357,2],[360,85],[245,2],[265,2],[276,104],[275,105],[266,106],[278,107],[277,105],[279,108],[280,109],[274,110],[273,111],[268,2],[269,2],[270,2],[271,112],[272,113],[368,114],[365,2],[386,115],[387,116],[261,117],[262,2],[366,2],[367,2],[185,118],[183,119],[184,120],[172,121],[173,119],[180,122],[171,123],[176,124],[186,2],[177,125],[182,126],[187,127],[170,128],[178,129],[179,130],[174,131],[181,118],[175,132],[50,133],[251,134],[253,135],[254,136],[255,136],[256,137],[257,134],[258,134],[252,2],[247,134],[248,134],[246,2],[249,134],[250,134],[259,138],[260,139],[163,140],[221,2],[232,141],[215,142],[233,141],[234,143],[235,143],[220,2],[222,142],[223,142],[224,144],[225,145],[226,146],[227,146],[212,2],[228,146],[218,147],[229,142],[213,142],[230,146],[216,143],[217,148],[214,145],[236,149],[238,150],[219,151],[237,152],[231,153],[412,154],[411,155],[410,156],[409,157],[169,2],[201,2],[44,2],[45,2],[9,2],[8,2],[2,2],[10,2],[11,2],[12,2],[13,2],[14,2],[15,2],[16,2],[17,2],[3,2],[18,2],[19,2],[4,2],[20,2],[24,2],[21,2],[22,2],[23,2],[25,2],[26,2],[27,2],[5,2],[28,2],[29,2],[30,2],[31,2],[6,2],[35,2],[32,2],[33,2],[34,2],[36,2],[7,2],[37,2],[42,2],[43,2],[38,2],[39,2],[40,2],[41,2],[1,2],[87,158],[97,159],[86,158],[107,160],[78,161],[77,162],[106,163],[100,164],[105,165],[80,166],[94,167],[79,168],[103,169],[75,170],[74,163],[104,171],[76,172],[81,173],[82,2],[85,173],[72,2],[108,174],[98,175],[89,176],[90,177],[92,178],[88,179],[91,180],[101,163],[83,181],[84,182],[93,183],[73,184],[96,175],[95,173],[99,2],[102,185],[202,186],[193,187],[194,186],[205,188],[192,2],[191,189],[188,190],[167,191],[165,192],[164,2],[166,193],[189,2],[190,194],[211,195],[206,196],[207,197],[441,198],[241,2],[422,199],[423,200],[424,201],[242,202],[425,203],[419,204],[426,205],[427,206],[416,204],[428,207],[429,208],[418,204],[430,209],[431,210],[415,211],[432,212],[417,204],[414,2],[243,213],[244,214],[388,215],[421,216],[420,217],[433,218],[434,219],[435,220],[240,221],[436,222],[437,223],[438,224],[389,225],[439,226],[440,227],[413,228]],"latestChangedDtsFile":"./dist/editors/adapters/EditorRegistry.d.ts","version":"5.9.3"} \ No newline at end of file +{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/typescript/lib/lib.esnext.float16.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@types/vscode/index.d.ts","../protocol/dist/index.d.ts","./src/watcher/FileWatcher.ts","../../node_modules/simple-git/dist/src/lib/tasks/diff-name-status.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/task.d.ts","../../node_modules/simple-git/dist/src/lib/types/tasks.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-error.d.ts","../../node_modules/simple-git/dist/src/lib/types/handlers.d.ts","../../node_modules/simple-git/dist/src/lib/types/index.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/log.d.ts","../../node_modules/simple-git/dist/typings/response.d.ts","../../node_modules/simple-git/dist/src/lib/responses/GetRemoteSummary.d.ts","../../node_modules/simple-git/dist/src/lib/args/pathspec.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/apply-patch.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/check-is-repo.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/clean.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/clone.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/config.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/count-objects.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/grep.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/reset.d.ts","../../node_modules/simple-git/dist/src/lib/tasks/version.d.ts","../../node_modules/simple-git/dist/typings/types.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-construct-error.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-plugin-error.d.ts","../../node_modules/simple-git/dist/src/lib/errors/git-response-error.d.ts","../../node_modules/simple-git/dist/src/lib/errors/task-configuration-error.d.ts","../../node_modules/simple-git/dist/typings/errors.d.ts","../../node_modules/simple-git/dist/typings/simple-git.d.ts","../../node_modules/simple-git/dist/typings/index.d.ts","./src/git/GitIntegrationModule.ts","./src/diff/DiffGenerator.ts","../../node_modules/@socket.io/component-emitter/lib/cjs/index.d.ts","../../node_modules/engine.io-parser/build/esm/commons.d.ts","../../node_modules/engine.io-parser/build/esm/encodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/decodePacket.d.ts","../../node_modules/engine.io-parser/build/esm/index.d.ts","../../node_modules/engine.io-client/build/esm/transport.d.ts","../../node_modules/engine.io-client/build/esm/globals.node.d.ts","../../node_modules/engine.io-client/build/esm/socket.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling-xhr.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling-xhr.node.d.ts","../../node_modules/engine.io-client/build/esm/transports/websocket.d.ts","../../node_modules/engine.io-client/build/esm/transports/websocket.node.d.ts","../../node_modules/engine.io-client/build/esm/transports/webtransport.d.ts","../../node_modules/engine.io-client/build/esm/transports/index.d.ts","../../node_modules/engine.io-client/build/esm/util.d.ts","../../node_modules/engine.io-client/build/esm/contrib/parseuri.d.ts","../../node_modules/engine.io-client/build/esm/transports/polling-fetch.d.ts","../../node_modules/engine.io-client/build/esm/index.d.ts","../../node_modules/socket.io-parser/build/esm/index.d.ts","../../node_modules/socket.io-client/build/esm/socket.d.ts","../../node_modules/socket.io-client/build/esm/manager.d.ts","../../node_modules/socket.io-client/build/esm/index.d.ts","./src/websocket/WebSocketClient.ts","./src/editors/adapters/types.ts","./src/editors/adapters/EditorRegistry.ts","./src/editors/adapters/ContinueAdapter.ts","./src/editors/adapters/KiroAdapter.ts","./src/editors/adapters/CursorAdapter.ts","./src/editors/adapters/AntigravityAdapter.ts","./src/extension.ts","./src/editor-adapters/EditorAdapter.ts","./src/editor-adapters/ContinueAdapter.ts","./src/editor-adapters/OtherAdapters.ts","./src/editor-adapters/VSCodeAdapter.ts","./src/editor-adapters/EditorRegistry.ts","./src/editors/adapters/errors.ts","../../node_modules/@vitest/pretty-format/dist/index.d.ts","./node_modules/@vitest/utils/dist/display.d.ts","./node_modules/@vitest/utils/dist/types.d.ts","./node_modules/@vitest/utils/dist/helpers.d.ts","./node_modules/@vitest/utils/dist/timers.d.ts","./node_modules/@vitest/utils/dist/index.d.ts","./node_modules/@vitest/runner/dist/tasks.d-C7UxawJ9.d.ts","./node_modules/@vitest/utils/dist/types.d-BCElaP-c.d.ts","./node_modules/@vitest/utils/dist/diff.d.ts","./node_modules/@vitest/utils/diff.d.ts","./node_modules/@vitest/runner/dist/types.d.ts","./node_modules/@vitest/runner/dist/index.d.ts","./node_modules/vitest/dist/chunks/traces.d.402V_yFI.d.ts","./node_modules/vite/dist/node/chunks/moduleRunnerTransport.d.ts","./node_modules/vite/dist/node/module-runner.d.ts","./node_modules/@vitest/snapshot/dist/environment.d-DHdQ1Csl.d.ts","./node_modules/@vitest/snapshot/dist/rawSnapshot.d-lFsMJFUd.d.ts","./node_modules/@vitest/snapshot/dist/index.d.ts","./node_modules/vitest/dist/chunks/config.d.Cy95HiCx.d.ts","./node_modules/vitest/dist/chunks/environment.d.CrsxCzP1.d.ts","./node_modules/vitest/dist/chunks/rpc.d.RH3apGEf.d.ts","./node_modules/vitest/dist/chunks/worker.d.Dyxm8DEL.d.ts","./node_modules/vitest/dist/chunks/browser.d.ChKACdzH.d.ts","./node_modules/@vitest/spy/dist/index.d.ts","../../node_modules/tinyrainbow/dist/index.d.ts","../../node_modules/@standard-schema/spec/dist/index.d.ts","../../node_modules/@types/deep-eql/index.d.ts","../../node_modules/@types/chai/node_modules/assertion-error/index.d.ts","../../node_modules/@types/chai/index.d.ts","./node_modules/@vitest/expect/dist/index.d.ts","./node_modules/@vitest/runner/dist/utils.d.ts","./node_modules/@vitest/runner/utils.d.ts","../../node_modules/tinybench/dist/index.d.cts","./node_modules/vitest/dist/chunks/benchmark.d.DAaHLpsq.d.ts","./node_modules/vitest/dist/chunks/global.d.B15mdLcR.d.ts","./node_modules/vitest/dist/chunks/suite.d.BJWk38HB.d.ts","./node_modules/vitest/dist/chunks/evaluatedModules.d.BxJ5omdx.d.ts","../../node_modules/expect-type/dist/utils.d.ts","../../node_modules/expect-type/dist/overloads.d.ts","../../node_modules/expect-type/dist/branding.d.ts","../../node_modules/expect-type/dist/messages.d.ts","../../node_modules/expect-type/dist/index.d.ts","./node_modules/vitest/dist/index.d.ts","./node_modules/vitest/globals.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/blob.d.ts","./node_modules/@types/node/web-globals/console.d.ts","./node_modules/@types/node/web-globals/crypto.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/encoding.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/utility.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client-stats.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/round-robin-pool.d.ts","./node_modules/undici-types/h2c-client.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-call-history.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/snapshot-agent.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/cache-interceptor.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/web-globals/importmeta.d.ts","./node_modules/@types/node/web-globals/messaging.d.ts","./node_modules/@types/node/web-globals/navigator.d.ts","./node_modules/@types/node/web-globals/performance.d.ts","./node_modules/@types/node/web-globals/storage.d.ts","./node_modules/@types/node/web-globals/streams.d.ts","./node_modules/@types/node/web-globals/timers.d.ts","./node_modules/@types/node/web-globals/url.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/inspector/promises.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","../../node_modules/buffer/index.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/path/posix.d.ts","./node_modules/@types/node/path/win32.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/quic.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/sqlite.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/test/reporters.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/util/types.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts"],"fileIdsList":[[163,226,234,238,241,243,244,245,258],[143,144,163,226,234,238,241,243,244,245,258],[85,86,87,89,90,91,92,93,94,95,96,97,163,226,234,238,241,243,244,245,258],[80,84,85,86,163,226,234,238,241,243,244,245,258],[80,84,87,163,226,234,238,241,243,244,245,258],[90,92,93,163,226,234,238,241,243,244,245,258],[88,163,226,234,238,241,243,244,245,258],[80,84,86,87,88,163,226,234,238,241,243,244,245,258],[89,163,226,234,238,241,243,244,245,258],[85,163,226,234,238,241,243,244,245,258],[84,85,163,226,234,238,241,243,244,245,258],[84,91,163,226,234,238,241,243,244,245,258],[81,163,226,234,238,241,243,244,245,258],[81,82,83,163,226,234,238,241,243,244,245,258],[154,155,163,226,234,238,241,243,244,245,258],[154,155,156,157,163,226,234,238,241,243,244,245,258],[154,156,163,226,234,238,241,243,244,245,258],[154,163,226,234,238,241,243,244,245,258],[54,56,163,226,234,238,241,243,244,245,258],[56,163,226,234,238,241,243,244,245,258],[54,163,226,234,238,241,243,244,245,258],[52,56,77,163,226,234,238,241,243,244,245,258],[77,163,226,234,238,241,243,244,245,258],[56,77,163,226,234,238,241,243,244,245,258],[53,55,163,226,227,234,238,241,243,244,245,258],[52,56,163,226,234,238,241,243,244,245,258],[54,71,72,73,74,163,226,234,238,241,243,244,245,258],[58,70,75,76,163,226,234,238,241,243,244,245,258],[51,57,163,226,234,238,241,243,244,245,258],[58,70,75,163,226,234,238,241,243,244,245,258],[51,56,57,59,60,61,62,63,64,65,66,67,68,69,163,226,234,238,241,243,244,245,258],[98,99,100,101,163,226,234,238,241,243,244,245,258],[80,98,99,100,163,226,234,238,241,243,244,245,258],[80,99,101,163,226,234,238,241,243,244,245,258],[80,163,226,234,238,241,243,244,245,258],[163,223,224,226,234,238,241,243,244,245,258],[163,225,226,234,238,241,243,244,245,258],[226,234,238,241,243,244,245,258],[163,226,234,238,241,243,244,245,258,266],[163,226,227,232,234,237,238,241,243,244,245,247,258,263,275],[163,226,227,228,234,237,238,241,243,244,245,258],[163,226,229,234,238,241,243,244,245,258,276],[163,226,230,231,234,238,241,243,244,245,249,258],[163,226,231,234,238,241,243,244,245,258,263,272],[163,226,232,234,237,238,241,243,244,245,247,258],[163,225,226,233,234,238,241,243,244,245,258],[163,226,234,235,238,241,243,244,245,258],[163,226,234,236,237,238,241,243,244,245,258],[163,225,226,234,237,238,241,243,244,245,258],[163,226,234,237,238,239,241,243,244,245,258,263,275],[163,226,234,237,238,239,241,243,244,245,258,263,266],[163,213,226,234,237,238,240,241,243,244,245,247,258,263,275],[163,226,234,237,238,240,241,243,244,245,247,258,263,272,275],[163,226,234,238,240,241,242,243,244,245,258,263,272,275],[161,162,163,164,165,166,167,168,169,170,171,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282],[163,226,234,237,238,241,243,244,245,258],[163,226,234,238,241,243,245,258],[163,226,234,238,241,243,244,245,246,258,275],[163,226,234,237,238,241,243,244,245,247,258,263],[163,226,234,238,241,243,244,245,249,258],[163,226,234,238,241,243,244,245,250,258],[163,226,234,237,238,241,243,244,245,253,258],[163,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282],[163,226,234,238,241,243,244,245,255,258],[163,226,234,238,241,243,244,245,256,258],[163,226,231,234,238,241,243,244,245,247,258,266],[163,226,234,237,238,241,243,244,245,258,259],[163,226,234,238,241,243,244,245,258,260,276,279],[163,226,234,237,238,241,243,244,245,258,263,265,266],[163,226,234,238,241,243,244,245,258,264,266],[163,226,234,238,241,243,244,245,258,266,276],[163,226,234,238,241,243,244,245,258,267],[163,223,226,234,238,241,243,244,245,258,263,269,275],[163,226,234,238,241,243,244,245,258,263,268],[163,226,234,237,238,241,243,244,245,258,270,271],[163,226,234,238,241,243,244,245,258,270,271],[163,226,231,234,238,241,243,244,245,247,258,263,272],[163,226,234,238,241,243,244,245,258,273],[163,226,234,238,241,243,244,245,247,258,274],[163,226,234,238,240,241,243,244,245,256,258,275],[163,226,234,238,241,243,244,245,258,276,277],[163,226,231,234,238,241,243,244,245,258,277],[163,226,234,238,241,243,244,245,258,263,278],[163,226,234,238,241,243,244,245,246,258,279],[163,226,234,238,241,243,244,245,258,280],[163,226,229,234,238,241,243,244,245,258],[163,226,231,234,238,241,243,244,245,258],[163,226,234,238,241,243,244,245,258,276],[163,213,226,234,238,241,243,244,245,258],[163,226,234,238,241,243,244,245,258,275],[163,226,234,238,241,243,244,245,258,281],[163,226,234,238,241,243,244,245,253,258],[163,226,234,238,241,243,244,245,258,271],[163,213,226,234,237,238,239,241,243,244,245,253,258,263,266,275,278,279,281],[163,226,234,238,241,243,244,245,258,263,282],[122,126,128,140,141,142,145,151,163,226,234,238,241,243,244,245,258],[122,123,126,127,163,226,234,238,241,243,244,245,258],[122,163,226,234,238,241,243,244,245,258],[122,123,126,163,226,234,238,241,243,244,245,258],[122,123,163,226,234,238,241,243,244,245,258],[147,163,226,234,238,241,243,244,245,258],[117,132,133,163,226,234,238,241,243,244,245,258],[117,132,163,226,234,238,241,243,244,245,258],[125,163,226,234,238,241,243,244,245,258],[117,124,163,226,234,238,241,243,244,245,258],[117,163,226,234,238,241,243,244,245,258],[119,163,226,234,238,241,243,244,245,258],[117,118,119,120,121,163,226,234,238,241,243,244,245,258],[163,178,181,184,185,226,234,238,241,243,244,245,258,275],[163,181,226,234,238,241,243,244,245,258,263,275],[163,181,185,226,234,238,241,243,244,245,258,275],[163,226,234,238,241,243,244,245,258,263],[163,175,226,234,238,241,243,244,245,258],[163,179,226,234,238,241,243,244,245,258],[163,177,178,181,226,234,238,241,243,244,245,258,275],[163,226,234,238,241,243,244,245,247,258,272],[163,226,234,238,241,243,244,245,258,283],[163,175,226,234,238,241,243,244,245,258,283],[163,177,181,226,234,238,241,243,244,245,247,258,275],[163,172,173,174,176,180,226,234,237,238,241,243,244,245,258,263,275],[163,181,190,198,226,234,238,241,243,244,245,258],[163,173,179,226,234,238,241,243,244,245,258],[163,181,207,208,226,234,238,241,243,244,245,258],[163,173,176,181,226,234,238,241,243,244,245,258,266,275,283],[163,181,226,234,238,241,243,244,245,258],[163,177,181,226,234,238,241,243,244,245,258,275],[163,172,226,234,238,241,243,244,245,258],[163,175,176,177,179,180,181,182,183,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,208,209,210,211,212,226,234,238,241,243,244,245,258],[163,181,200,203,226,234,238,241,243,244,245,258],[163,181,190,191,192,226,234,238,241,243,244,245,258],[163,179,181,191,193,226,234,238,241,243,244,245,258],[163,180,226,234,238,241,243,244,245,258],[163,173,175,181,226,234,238,241,243,244,245,258],[163,181,185,191,193,226,234,238,241,243,244,245,258],[163,185,226,234,238,241,243,244,245,258],[163,179,181,184,226,234,238,241,243,244,245,258,275],[163,173,177,181,190,226,234,238,241,243,244,245,258],[163,181,200,226,234,238,241,243,244,245,258],[163,193,226,234,238,241,243,244,245,258],[163,175,181,207,226,234,238,241,243,244,245,258,266,281,283],[130,163,226,234,238,241,243,244,245,258],[128,148,149,151,163,226,234,238,241,243,244,245,258],[128,129,138,151,163,226,234,238,241,243,244,245,258],[117,126,128,134,151,163,226,234,238,241,243,244,245,258],[131,163,226,234,238,241,243,244,245,258],[117,128,134,137,146,150,151,163,226,234,238,241,243,244,245,258],[128,129,131,134,151,163,226,234,238,241,243,244,245,258],[128,148,149,150,151,163,226,234,238,241,243,244,245,258],[128,131,135,136,137,151,163,226,234,238,241,243,244,245,258],[117,122,126,128,129,131,134,135,136,137,138,139,140,146,148,149,150,151,152,153,158,163,226,234,238,241,243,244,245,258],[159,163,226,234,238,241,243,244,245,258],[48,49,163,226,234,238,239,241,243,244,245,258],[48,111,163,226,234,238,241,243,244,245,258],[111,112,113,114,163,226,234,238,241,243,244,245,258],[48,104,163,226,234,238,241,243,244,245,258],[104,163,226,234,238,241,243,244,245,258],[48,49,50,78,79,103,105,106,107,108,109,163,226,231,234,238,241,243,244,245,258,276,282],[48,77,163,226,234,238,241,243,244,245,258],[48,163,226,234,238,241,243,244,245,258],[49,102,163,226,234,238,241,243,244,245,258]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"dd31f9423525b3eaaba877d290a0a648f2ea774c2ff946611905e949d6078ee6","affectsGlobalScope":true,"impliedFormat":1},"002aaa2b5c035f279742899379e4b7194ed6bdd846f27cfb1489c3aad1e6d9d5","2564d83bdccf660ca2fe0c9a2eda7938e77b45d4f4cbd1717071bd98a3d6d2af",{"version":"16b81141d0c59af6f07e5fc24824c54dd6003da0ab0a2d2cedc95f8eb03ea8d3","impliedFormat":1},{"version":"6578758b0b94087beffd0ce554701365cd1e6a7428f14464ac8b88095fca4e50","impliedFormat":1},{"version":"b6c4796630a47f8b0f420519cd241e8e7701247b48ed4b205e8d057cbf7107d7","impliedFormat":1},{"version":"6256cf36c8ae7e82bff606595af8fe08a06f8478140fcf304ee2f10c7716ddc8","impliedFormat":1},{"version":"b2dbe6b053e04ec135c7ce722e0a4e9744281ea40429af96e2662cc926465519","impliedFormat":1},{"version":"ff5a6ff97e667e6baf1cf4e98f1b1d22652318e2e770baa0444e36b968a86479","impliedFormat":1},{"version":"5619706bbd7a964d7c82cd4a307457ed0327ecc86772ceb7ea0870566c6578b2","impliedFormat":1},{"version":"b48c4e15766170c5003a6273b1d8f17f854ec565ccaaebd9f700fef159b84078","impliedFormat":1},{"version":"7c774169686976056434799723bd7a48348df9d2204b928a0b77920505585214","impliedFormat":1},{"version":"5e95379e81e2d373e5235cedc4579938e39db274a32cfa32f8906e7ff6698763","impliedFormat":1},{"version":"3e697e2186544103572756d80b61fcce3842ab07abdc5a1b7b8d4b9a4136005a","impliedFormat":1},{"version":"8758b438b12ea50fb8b678d29ab0ef42d77abfb801cec481596ce6002b537a6f","impliedFormat":1},{"version":"688a28e7953ef4465f68da2718dc6438aaa16325133a8cb903bf850c63cb4a7e","impliedFormat":1},{"version":"f2c96e813200ca900d2bbf0d8e3db7c2a70180b80f559b676aab8315c9472943","impliedFormat":1},{"version":"f73cf81342d2a25b65179c262ca7c38df023969129094607d0eb52510a56f10f","impliedFormat":1},{"version":"f433d28f86313073f13b16c0a18ccdd21759390f52c8d7bf9d916645b12d16ed","impliedFormat":1},{"version":"e7d7e67bd66b30f2216e4678b97bb09629a2b31766a79119acaa30e3005ef5fb","impliedFormat":1},{"version":"e05a20aa85c7324c65643542c2d7314774c2adf510f9dcbad5d3afac74ca3dac","impliedFormat":1},{"version":"e137f087bda0256410b28743ef9a1bf57a4cafd43ffa6b62d5c17a8f5a08b3b5","impliedFormat":1},{"version":"b1e92e9b96cacb98a39acc958670ac895c3b2bb05d8810497310b6b678c46acc","impliedFormat":1},{"version":"af504042a6db047c40cc0aeb14550bbc954f194f2b8c5ad8944f2da502f45bf5","impliedFormat":1},{"version":"5b25b6ab5ad6c17f90b592162b2e9978ad8d81edf24cd3957306eb6e5edb89a9","impliedFormat":1},{"version":"24693bd77ac3be0b16e564d0ab498a397feb758ce7f4ed9f13478d566e3aafde","impliedFormat":1},{"version":"208dad548b895c7d02465de6ba79064b7c67bc4d94e5227b09f21d58790e634c","impliedFormat":1},{"version":"048c0ced65fa41fbf4bcc3d5e8e5b6f6c7f27335ceb54d401be654e821adbc08","impliedFormat":1},{"version":"e1126668c194faa56a728eb5bd2dd88dfc19460ced65c38888977a22369e4624","impliedFormat":1},{"version":"9a57d654b0a0e4bf56a8eb0aa3ede1c7d349cec6220e36b5288c26626c8688ed","impliedFormat":1},"82045568843ec70b4d71b04456ee731c55d927fe7798b4f9c0e5deb27efa6fea","7a51079d45f381f44bab0e2a87a687281def4a5ebcd87e3b8e4a29edd344a512",{"version":"14ecfc29e0c44ad4c5e50f9b597492cd8f45a2a635db8b5fe911a5da83e26cf8","impliedFormat":1},{"version":"569e762cf47aafdad508360a443c6c757e56c61db3b652b65458a7d168d139c4","impliedFormat":99},{"version":"02ed2766d79a00719ac3cc77851d54bd7197c1b12085ea12126bc2a65068223e","impliedFormat":99},{"version":"4b84373e192b7e0f8569b65eb16857098a6ee279b75d49223db2a751fdd7efde","impliedFormat":99},{"version":"5aeea312cd1d3cc5d72fc8a9c964439d771bdf41d9cce46667471b896b997473","impliedFormat":99},{"version":"1d963927f62a0d266874e19fcecf43a7c4f68487864a2c52f51fbdd7c5cc40d8","impliedFormat":99},{"version":"d7341559b385e668ca553f65003ccc5808d33a475c141798ba841992fef7c056","impliedFormat":99},{"version":"fcf502cbb816413ab8c79176938357992e95c7e0af3aa2ef835136f88f5ad995","impliedFormat":99},{"version":"5c59fd485fff665a639e97e9691a7169f069e24b42ffc1f70442c55720ad3969","impliedFormat":99},{"version":"89c6bcc4f7b19580009a50674b4da0951165c8a2202fa908735ccbe35a5090dd","impliedFormat":99},{"version":"df283af30056ef4ab9cf31350d4b40c0ed15b1032833e32dc974ade50c13f621","impliedFormat":99},{"version":"9de40cf702d52a49d6f3d36d054fc12638348ea3e1fb5f8d53ef8910e7eaa56f","impliedFormat":99},{"version":"2f844dc2e5d3e8d15a951ff3dc39c7900736d8b2be67cc21831b50e5faaa760a","impliedFormat":99},{"version":"ecbbfd67f08f18500f2faaaa5d257d5a81421e5c0d41fa497061d2870b2e39db","impliedFormat":99},{"version":"79570f4dfd82e9ae41401b22922965da128512d31790050f0eaf8bbdb7be9465","impliedFormat":99},{"version":"4b7716182d0d0349a953d1ff31ab535274c63cbb556e88d888caeb5c5602bc65","impliedFormat":99},{"version":"d51809d133c78da34a13a1b4267e29afb0d979f50acbeb4321e10d74380beeea","impliedFormat":99},{"version":"e1dafdb1db7e8b597fc0dbc9e4ea002c39b3c471be1c4439eda14cf0550afe92","impliedFormat":99},{"version":"6ea4f73a90f9914608bd1ab342ecfc67df235ad66089b21f0632264bb786a98e","impliedFormat":99},{"version":"ba0badf6398010ef0ba77947d4b52078fc84cb4f209f6b70194b3b2cfb1823d8","impliedFormat":99},{"version":"dd018ed60101a59a8e89374e62ed5ab3cb5df76640fc0ab215c9adf8fbc3c4b0","impliedFormat":99},{"version":"8d401f73380bdd30293e1923338e2544d57a9cdbd3dd34b6d24df93be866906e","impliedFormat":99},{"version":"6a33d9e50fc28d0a7431e29fd7a07d7a74ac0218c6c17f9fecbed52a1985ecb5","impliedFormat":99},{"version":"1a0dc0f6263e09fa103caa1052c4618226d157308a3cede6955d39e29700784c","signature":"3a02d67e8e78f48a03a675acf0e23f75327f7357bf36f7a31b75325806d15227"},"0fdb9cbbe2ef5f22151b9b270d1d37bfb4aad0db086f31c2aa529c7e44031bb1","a13b6da7bc3963aa95828f505c5611bd4818cd2f26667f04387c7bd4bd1da073","f04b1d340d52144853be6833b67c25df71df89fb4d7877d88bfdd49eb555aef6","11610a39c23fe381816f89226ef694a11a0e40a7091a91acfb18fb1fc460b7e7","c425e0c8945a5b26bd7edf3cc4f97211c395e620da3d10e90a216e4bbe672026","5768c5db9625db9491a0a629168e73a7d86e229289bfc604be684cc61693d45f",{"version":"d7be2cefbf78a71d3dd076089d813ec437aaf54c66a0210b4b66a19d6220ff88","signature":"e888f57c70a5655dedf190409bbc1dd992ff56f48b2f4cea147e43ca9258dcf2"},"39fa0fc4a237d6cd97ec66a4fb270773188b523ef44889edf822070dfbdcbed1","8a6413d0b2b312ff31324b3d0614a5e87cf3c7407bd90638fccd93d657fb0311","bc747c1c9511d01728265c37f9e812dbbe47bd25f4e1b1ecc0684c4aca05f252","956ac11bbac2bced8fb7d1117bac42f8af981f011068ad8823a9d05b00698d02","2292788f8fbb5a79e698ee59763b54d0df2ea9e32aba4ce034e09228eb1f4069","e76107274aed2de3eae1c262cdf50ae54cfca7b1254c56203c60e1343293a7ce",{"version":"acfb723d81eda39156251aed414c553294870bf53062429ebfcfba8a68cb4753","impliedFormat":99},{"version":"fa69a90381c2f85889722a911a732a5ee3596dc3acecda8a9aa2fa89b9615d8d","impliedFormat":99},{"version":"b5ce343886d23392be9c8280e9f24a87f1d7d3667f6672c2fe4aa61fa4ece7d4","impliedFormat":99},{"version":"57e9e1b0911874c62d743af24b5d56032759846533641d550b12a45ff404bf07","impliedFormat":99},{"version":"b0857bb28fd5236ace84280f79a25093f919fd0eff13e47cc26ea03de60a7294","impliedFormat":99},{"version":"5e43e0824f10cd8c48e7a8c5c673638488925a12c31f0f9e0957965c290eb14c","impliedFormat":99},{"version":"854cd3a3375ffc4e7a92b2168dd065d7ff2614b43341038a65cca865a44c00c5","impliedFormat":99},{"version":"ef13c73d6157a32933c612d476c1524dd674cf5b9a88571d7d6a0d147544d529","impliedFormat":99},{"version":"3b0a56d056d81a011e484b9c05d5e430711aaecd561a788bad1d0498aad782c7","impliedFormat":99},{"version":"05c7aef6a4e496b93c2e682cced8903c0dfe6340d04f3fe616176e2782193435","impliedFormat":99},{"version":"2f863ee9b873a65d9c3338ea7aaddbdb41a9673f062f06983d712bd01c25dc6b","impliedFormat":99},{"version":"67aa128c2bc170b93794f191feffc65a4b33e878db211cfcb7658c4b72f7a1f5","impliedFormat":99},{"version":"ac3d263474022e9a14c43f588f485d549641d839b159ecc971978b90f34bdf6b","impliedFormat":99},{"version":"10073cdcf56982064c5337787cc59b79586131e1b28c106ede5bff362f912b70","impliedFormat":99},{"version":"ff0a83c9a0489a627e264ffcb63f2264b935b20a502afa3a018848139e3d8575","impliedFormat":99},{"version":"324ac98294dab54fbd580c7d0e707d94506d7b2c3d5efe981a8495f02cf9ad96","impliedFormat":99},{"version":"9ec72eb493ff209b470467e24264116b6a8616484bca438091433a545dfba17e","impliedFormat":99},{"version":"c35b8117804c639c53c87f2c23e0c786df61d552e513bd5179f5b88e29964838","impliedFormat":99},{"version":"c609331c6ed4ad4af54e101088c6a4dcb48f8db7b0b97e44a6efeb130f4331bd","impliedFormat":99},{"version":"bcbd3becd08b4515225880abea0dbfbbf0d1181ce3af8f18f72f61edbe4febfb","impliedFormat":99},{"version":"67acaedb46832d66c15f1b09fb7b6a0b7f41bdbf8eaa586ec70459b3e8896eb9","impliedFormat":99},{"version":"4535ab977ee871e956eb7bebe2db5de79f5d5ec7dfbbf1d35e08f4a2d6630dac","impliedFormat":99},{"version":"b79b5ed99f26ffb2f8ae4bdcc4b34a9542197dc3fa96cfb425c2a81e618cff28","impliedFormat":99},{"version":"31fd7c12f6e27154efb52a916b872509a771880f3b20f2dfd045785c13aa813f","impliedFormat":99},{"version":"b481de4ab5379bd481ca12fc0b255cdc47341629a22c240a89cdb4e209522be2","impliedFormat":99},{"version":"bdd14f07b4eca0b4b5203b85b8dbc4d084c749fa590bee5ea613e1641dcd3b29","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"4e258d11c899cb9ff36b4b5c53df59cf4a5ccae9a9931529686e77431e0a3518","affectsGlobalScope":true,"impliedFormat":99},{"version":"a5ae67a67f786ffe92d34b55467a40fb50fb0093e92388cadce6168fa42690fd","impliedFormat":99},{"version":"e666e31d323fef5642f87db0da48a83e58f0aaf9e3823e87eabd8ec7e0441a36","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":1},{"version":"6987dfb4b0c4e02112cc4e548e7a77b3d9ddfeffa8c8a2db13ceac361a4567d9","impliedFormat":99},{"version":"a534e61c2f06a147d97aebad720db97dffd8066b7142212e46bcbcdcb640b81a","impliedFormat":99},{"version":"ddf569d04470a4d629090d43a16735185001f3fcf0ae036ead99f2ceab62be48","impliedFormat":99},{"version":"b413fbc6658fe2774f8bf9a15cf4c53e586fc38a2d5256b3b9647da242c14389","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"53c448183c7177c83d3eb0b40824cf8952721a6584cf22052adc24f778986732","impliedFormat":99},{"version":"0a5bc32362b0559b9bcf0a6a83136c4442dbbd0edecd671538a5e03454b6dff0","affectsGlobalScope":true,"impliedFormat":99},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"438b41419b1df9f1fbe33b5e1b18f5853432be205991d1b19f5b7f351675541e","affectsGlobalScope":true,"impliedFormat":1},{"version":"096116f8fedc1765d5bd6ef360c257b4a9048e5415054b3bf3c41b07f8951b0b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"074de5b2fdead0165a2757e3aaef20f27a6347b1c36adea27d51456795b37682","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"24371e69a38fc33e268d4a8716dbcda430d6c2c414a99ff9669239c4b8f40dea","impliedFormat":1},{"version":"ccab02f3920fc75c01174c47fcf67882a11daf16baf9e81701d0a94636e94556","impliedFormat":1},{"version":"3e11fce78ad8c0e1d1db4ba5f0652285509be3acdd519529bc8fcef85f7dafd9","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"c63b9ada8c72f95aac5db92aea07e5e87ec810353cdf63b2d78f49a58662cf6c","impliedFormat":1},{"version":"1cc2a09e1a61a5222d4174ab358a9f9de5e906afe79dbf7363d871a7edda3955","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"b64d4d1c5f877f9c666e98e833f0205edb9384acc46e98a1fef344f64d6aba44","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"c9381908473a1c92cb8c516b184e75f4d226dad95c3a85a5af35f670064d9a2f","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"435b3711465425770ed2ee2f1cf00ce071835265e0851a7dc4600ab4b007550e","impliedFormat":1},{"version":"7e49f52a159435fc8df4de9dc377ef5860732ca2dc9efec1640531d3cf5da7a3","impliedFormat":1},{"version":"dd4bde4bdc2e5394aed6855e98cf135dfdf5dd6468cad842e03116d31bbcc9bc","impliedFormat":1},{"version":"4d4e879009a84a47c05350b8dca823036ba3a29a3038efed1be76c9f81e45edf","affectsGlobalScope":true,"impliedFormat":1},{"version":"237ba5ac2a95702a114a309e39c53a5bddff5f6333b325db9764df9b34f3502b","impliedFormat":1},{"version":"9ba13b47cb450a438e3076c4a3f6afb9dc85e17eae50f26d4b2d72c0688c9251","impliedFormat":1},{"version":"b64cd4401633ea4ecadfd700ddc8323a13b63b106ac7127c1d2726f32424622c","impliedFormat":1},{"version":"37c6e5fe5715814412b43cc9b50b24c67a63c4e04e753e0d1305970d65417a60","impliedFormat":1},{"version":"1d024184fb57c58c5c91823f9d10b4915a4867b7934e89115fd0d861a9df27c8","impliedFormat":1},{"version":"ee0e4946247f842c6dd483cbb60a5e6b484fee07996e3a7bc7343dfb68a04c5d","impliedFormat":1},{"version":"ef051f42b7e0ef5ca04552f54c4552eac84099d64b6c5ad0ef4033574b6035b8","impliedFormat":1},{"version":"853a43154f1d01b0173d9cbd74063507ece57170bad7a3b68f3fa1229ad0a92f","impliedFormat":1},{"version":"56231e3c39a031bfb0afb797690b20ed4537670c93c0318b72d5180833d98b72","impliedFormat":1},{"version":"5cc7c39031bfd8b00ad58f32143d59eb6ffc24f5d41a20931269011dccd36c5e","impliedFormat":1},{"version":"b0b69c61b0f0ec8ca15db4c8c41f6e77f4cacb784d42bca948f42dea33e8757e","affectsGlobalScope":true,"impliedFormat":1},{"version":"f96a48183254c00d24575401f1a761b4ce4927d927407e7862a83e06ce5d6964","impliedFormat":1},{"version":"cc25940cfb27aa538e60d465f98bb5068d4d7d33131861ace43f04fe6947d68f","impliedFormat":1},{"version":"f83fb2b1338afbb3f9d733c7d6e8b135826c41b0518867df0c0ace18ae1aa270","impliedFormat":1},{"version":"01ff95aa1443e3f7248974e5a771f513cb2ac158c8898f470a1792f817bee497","impliedFormat":1},{"version":"757227c8b345c57d76f7f0e3bbad7a91ffca23f1b2547cbed9e10025816c9cb7","impliedFormat":1},{"version":"42a05d8f239f74587d4926aba8cc54792eed8e8a442c7adc9b38b516642aadfe","impliedFormat":1},{"version":"5d21b58d60383cc6ab9ad3d3e265d7d25af24a2c9b506247e0e50b0a884920be","impliedFormat":1},{"version":"101f482fd48cb4c7c0468dcc6d62c843d842977aea6235644b1edd05e81fbf22","impliedFormat":1},{"version":"ae6757460f37078884b1571a3de3ebaf724d827d7e1d53626c02b3c2a408ac63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9451a46a89ed209e2e08329e6cac59f89356eae79a7230f916d8cc38725407c7","impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"3ef397f12387eff17f550bc484ea7c27d21d43816bbe609d495107f44b97e933","impliedFormat":1},{"version":"1023282e2ba810bc07905d3668349fbd37a26411f0c8f94a70ef3c05fe523fcf","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"e236b5eba291f51bdf32c231673e6cab81b5410850e61f51a7a524dddadc0f95","impliedFormat":1},{"version":"f7ba0e839daa0702e3ff1a1a871c0d8ea2d586ce684dd8a72c786c36a680b1d9","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f2c62938251b45715fd2a9887060ec4fbc8724727029d1cbce373747252bdd7","impliedFormat":1},{"version":"e3ace08b6bbd84655d41e244677b474fd995923ffef7149ddb68af8848b60b05","impliedFormat":1},{"version":"132580b0e86c48fab152bab850fc57a4b74fe915c8958d2ccb052b809a44b61c","impliedFormat":1},{"version":"af4ab0aa8908fc9a655bb833d3bc28e117c4f0e1038c5a891546158beb25accb","impliedFormat":1},{"version":"69c9a5a9392e8564bd81116e1ed93b13205201fb44cb35a7fde8c9f9e21c4b23","impliedFormat":1},{"version":"5f8fc37f8434691ffac1bfd8fc2634647da2c0e84253ab5d2dd19a7718915b35","impliedFormat":1},{"version":"5981c2340fd8b076cae8efbae818d42c11ffc615994cb060b1cd390795f1be2b","impliedFormat":1},{"version":"f64deb26664af64dc274637343bde8d82f930c77af05a412c7d310b77207a448","impliedFormat":1},{"version":"ed4f674fc8c0c993cc7e145069ac44129e03519b910c62be206a0cc777bdc60b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0250da3eb85c99624f974e77ef355cdf86f43980251bc371475c2b397ba55bcd","impliedFormat":1},{"version":"f1c93e046fb3d9b7f8249629f4b63dc068dd839b824dd0aa39a5e68476dc9420","impliedFormat":1},{"version":"3d3a5f27ffbc06c885dd4d5f9ee20de61faf877fe2c3a7051c4825903d9a7fdc","impliedFormat":1},{"version":"12806f9f085598ef930edaf2467a5fa1789a878fba077cd27e85dc5851e11834","impliedFormat":1},{"version":"bce309f4d9b67c18d4eeff5bba6cf3e67b2b0aead9f03f75d6060c553974d7ba","impliedFormat":1},{"version":"a43fe41c33d0a192a0ecaf9b92e87bef3709c9972e6d53c42c49251ccb962d69","impliedFormat":1},{"version":"a177959203c017fad3ecc4f3d96c8757a840957a4959a3ae00dab9d35961ca6c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6fc727ccf9b36e257ff982ea0badeffbfc2c151802f741bddff00c6af3b784cf","impliedFormat":1},{"version":"2a00d005e3af99cd1cfa75220e60c61b04bfb6be7ca7453bfe2ef6cca37cc03c","impliedFormat":1},{"version":"4844a4c9b4b1e812b257676ed8a80b3f3be0e29bf05e742cc2ea9c3c6865e6c6","impliedFormat":1},{"version":"064878a60367e0407c42fb7ba02a2ea4d83257357dc20088e549bd4d89433e9c","impliedFormat":1},{"version":"14d4bd22d1b05824971b98f7e91b2484c90f1a684805c330476641417c3d9735","impliedFormat":1},{"version":"c3877fef8a43cd434f9728f25a97575b0eb73d92f38b5c87c840daccc3e21d97","impliedFormat":1},{"version":"b484ec11ba00e3a2235562a41898d55372ccabe607986c6fa4f4aba72093749f","impliedFormat":1},{"version":"1dbd83860e7634f9c236647f45dbc5d3c4f9eba8827d87209d6e9826fdf4dbd5","impliedFormat":1},{"version":"41ef7992c555671a8fe54db302788adefa191ded810a50329b79d20a6772d14c","impliedFormat":1},{"version":"041a7781b9127ab568d2cdcce62c58fdea7c7407f40b8c50045d7866a2727130","impliedFormat":1},{"version":"b37f83e7deea729aa9ce5593f78905afb45b7532fdff63041d374f60059e7852","impliedFormat":1},{"version":"e1cb68f3ef3a8dd7b2a9dfb3de482ed6c0f1586ba0db4e7d73c1d2147b6ffc51","impliedFormat":1},{"version":"55cdbeebe76a1fa18bbd7e7bf73350a2173926bd3085bb050cf5a5397025ee4e","impliedFormat":1}],"root":[50,78,79,[103,116]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":1,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":7},"referencedMap":[[80,1],[142,1],[145,2],[144,1],[143,1],[48,1],[117,1],[248,1],[96,1],[86,1],[98,3],[87,4],[85,5],[94,6],[97,7],[89,8],[90,9],[88,10],[91,11],[92,12],[93,11],[95,1],[81,1],[83,13],[82,13],[84,14],[156,15],[158,16],[157,17],[155,18],[154,1],[60,1],[71,19],[54,20],[72,19],[73,21],[74,21],[59,1],[61,20],[62,20],[63,22],[64,22],[65,23],[66,23],[51,1],[67,23],[57,24],[68,20],[52,20],[69,23],[55,21],[56,25],[53,26],[75,27],[77,28],[58,29],[76,30],[70,31],[102,32],[101,33],[100,34],[99,35],[149,1],[141,1],[46,1],[47,1],[9,1],[8,1],[2,1],[10,1],[11,1],[12,1],[13,1],[14,1],[15,1],[16,1],[17,1],[3,1],[18,1],[19,1],[4,1],[20,1],[24,1],[21,1],[22,1],[23,1],[25,1],[26,1],[27,1],[5,1],[28,1],[29,1],[30,1],[31,1],[6,1],[35,1],[32,1],[33,1],[34,1],[36,1],[7,1],[37,1],[42,1],[43,1],[38,1],[39,1],[40,1],[41,1],[1,1],[44,1],[45,1],[49,1],[223,36],[224,36],[225,37],[163,38],[226,39],[227,40],[228,41],[161,1],[229,42],[230,43],[231,44],[232,45],[233,46],[234,47],[235,47],[236,48],[237,49],[238,50],[239,51],[164,1],[162,1],[240,52],[241,53],[242,54],[283,55],[243,56],[244,57],[245,56],[246,58],[247,59],[249,60],[250,61],[251,61],[252,61],[253,62],[254,63],[255,64],[256,65],[257,66],[258,67],[259,67],[260,68],[261,1],[262,1],[263,69],[264,70],[265,69],[266,71],[267,72],[268,73],[269,74],[270,75],[271,76],[272,77],[273,78],[274,79],[275,80],[276,81],[277,82],[278,83],[279,84],[280,85],[165,56],[166,1],[167,86],[168,87],[169,1],[170,88],[171,1],[214,89],[215,90],[216,91],[217,91],[218,92],[219,1],[220,39],[221,93],[222,90],[281,94],[282,95],[146,96],[128,97],[123,98],[127,99],[147,100],[148,101],[132,1],[134,102],[133,103],[140,1],[126,104],[125,105],[118,106],[120,107],[122,108],[121,1],[124,106],[119,1],[190,109],[202,110],[187,111],[203,112],[212,113],[178,114],[179,115],[177,116],[211,117],[206,118],[210,119],[181,120],[199,121],[180,122],[209,123],[175,124],[176,118],[182,125],[183,1],[189,126],[186,125],[173,127],[213,128],[204,129],[193,130],[192,125],[194,131],[197,132],[191,133],[195,134],[207,117],[184,135],[185,136],[198,137],[174,112],[201,138],[200,125],[188,136],[196,139],[205,1],[172,1],[208,140],[130,1],[131,141],[150,142],[139,143],[135,144],[136,98],[153,145],[151,146],[137,147],[152,148],[129,1],[138,149],[159,150],[160,151],[79,152],[112,153],[111,1],[115,154],[113,153],[114,153],[109,155],[106,155],[108,155],[105,156],[107,155],[116,155],[104,1],[110,157],[78,158],[50,159],[103,160]],"affectedFilesPendingEmit":[[79,51],[112,51],[111,51],[115,51],[113,51],[114,51],[109,51],[106,51],[108,51],[105,51],[107,51],[116,51],[104,51],[110,51],[78,51],[50,51],[103,51]],"emitSignatures":[50,78,79,103,104,105,106,107,108,109,110,111,112,113,114,115,116],"version":"5.9.3"} \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md index 7b1c01f..ba5f403 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -9,11 +9,13 @@ This directory contains utility scripts for manual testing of the Git Integratio Generates test files for manual testing scenarios. **Usage:** + ```bash ./scripts/generate-test-files.sh ``` **Generated Files:** + - `test-untracked.ts` - Untracked TypeScript file - `test-large.ts` - Large file with 10,500 lines - `test-binary.bin` - Binary file for testing @@ -21,6 +23,7 @@ Generates test files for manual testing scenarios. - `test-documentation.md` - Markdown documentation file **When to use:** + - Before starting manual testing - To quickly set up test scenarios - To verify system handles different file types @@ -32,11 +35,13 @@ Generates test files for manual testing scenarios. Removes all test files generated by `generate-test-files.sh`. **Usage:** + ```bash ./scripts/cleanup-test-files.sh ``` **Removed Files:** + - All `test-*.ts` files - All `test-*.json` files - All `test-*.md` files @@ -44,6 +49,7 @@ Removes all test files generated by `generate-test-files.sh`. - All `test-*.png` files **When to use:** + - After completing manual testing - To clean up workspace - Before committing changes @@ -55,11 +61,13 @@ Removes all test files generated by `generate-test-files.sh`. Verifies that the manual testing environment is properly configured. **Usage:** + ```bash ./scripts/verify-manual-test-setup.sh ``` **Checks:** + - ✓ Documentation files exist - ✓ Script files exist and are executable - ✓ Package directories exist @@ -72,10 +80,12 @@ Verifies that the manual testing environment is properly configured. - ✓ Git repository initialized **Exit Codes:** + - `0` - All checks passed or only warnings - `1` - Errors found, manual testing not ready **When to use:** + - Before starting manual testing - After building packages - To troubleshoot setup issues @@ -85,6 +95,7 @@ Verifies that the manual testing environment is properly configured. ## Quick Workflow ### Initial Setup + ```bash # 1. Verify setup ./scripts/verify-manual-test-setup.sh @@ -94,6 +105,7 @@ Verifies that the manual testing environment is properly configured. ``` ### After Testing + ```bash # Clean up test files ./scripts/cleanup-test-files.sh @@ -114,12 +126,14 @@ chmod +x scripts/*.sh ## Troubleshooting ### "Permission denied" error + ```bash # Make scripts executable chmod +x scripts/*.sh ``` ### "Command not found" error + ```bash # Ensure you're in the project root directory cd /path/to/CodeLink @@ -129,6 +143,7 @@ bash scripts/generate-test-files.sh ``` ### Scripts don't work on Windows + ```bash # Use Git Bash or WSL # Or run commands manually from the script diff --git a/scripts/setup-git-hooks.sh b/scripts/setup-git-hooks.sh new file mode 100755 index 0000000..e22abfd --- /dev/null +++ b/scripts/setup-git-hooks.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Setup script for Git hooks +# Run this script to install pre-commit hooks for the CodeLink project + +set -e + +echo "🔧 Setting up Git hooks for CodeLink..." +echo "" + +# Check if .git directory exists +if [ ! -d ".git" ]; then + echo "❌ Error: .git directory not found. Are you in the repository root?" + exit 1 +fi + +# Create hooks directory if it doesn't exist +mkdir -p .git/hooks + +# Copy pre-commit hook +echo "📋 Installing pre-commit hook..." +cp .github/pre-commit-hook.sh .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit +echo "✅ Pre-commit hook installed" +echo "" + +echo "✨ Git hooks setup complete!" +echo "" +echo "The pre-commit hook will now run automatically before each commit." +echo "It will check:" +echo " - ESLint (code quality)" +echo " - TypeScript compilation (type safety)" +echo " - Prettier formatting (code style)" +echo "" +echo "To bypass the hook (not recommended), use: git commit --no-verify" +echo "" +echo "To manually run pre-commit checks: npm run precommit" diff --git a/test-mobile-client.js b/test-mobile-client.js deleted file mode 100644 index 5b9f85e..0000000 --- a/test-mobile-client.js +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env node - -/** - * Test script to send a SYNC_FULL_CONTEXT message to the mobile client - * Usage: node test-mobile-client.js - */ - -const { io } = require('socket.io-client'); - -const RELAY_URL = 'http://localhost:8080'; - -console.log('Connecting to relay server...'); -const socket = io(RELAY_URL); - -socket.on('connect', () => { - console.log('Connected to relay server'); - - // Send ping to register as extension client - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - - console.log('Sending ping to register as extension client...'); - socket.emit('message', JSON.stringify(ping)); - - // Wait for pong, then send test message - socket.on('message', (data) => { - const message = JSON.parse(data); - console.log('Received:', message); - - if (message.type === 'pong') { - console.log('Registered as extension client'); - - // Send test SYNC_FULL_CONTEXT message - const testMessage = { - id: crypto.randomUUID(), - type: 'SYNC_FULL_CONTEXT', - payload: { - fileName: 'src/example.ts', - originalFile: 'const x = 1;\nconst y = 2;\n\nfunction hello() {\n console.log("Hello");\n}', - modifiedFile: 'const x = 1;\nconst y = 3;\nconst z = 4;\n\nfunction hello() {\n console.log("Hello World!");\n}', - isDirty: true, - timestamp: Date.now(), - }, - timestamp: Date.now(), - }; - - console.log('\nSending SYNC_FULL_CONTEXT message...'); - console.log('Payload:', testMessage.payload); - socket.emit('message', JSON.stringify(testMessage)); - - console.log('\n✅ Test message sent!'); - console.log('Check your mobile client browser - you should see the diff viewer now.'); - - // Keep connection open for a bit - setTimeout(() => { - console.log('\nDisconnecting...'); - socket.disconnect(); - process.exit(0); - }, 2000); - } - }); -}); - -socket.on('connect_error', (error) => { - console.error('Connection error:', error.message); - console.error('\nMake sure the relay server is running:'); - console.error(' cd packages/relay-server'); - console.error(' npm run dev'); - process.exit(1); -}); - -socket.on('disconnect', () => { - console.log('Disconnected from relay server'); -}); diff --git a/test-mocks/vscode.ts b/test-mocks/vscode.ts deleted file mode 100644 index 8bb1826..0000000 --- a/test-mocks/vscode.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Mock VS Code API for testing - */ - -export const workspace = { - workspaceFolders: [], - textDocuments: [], - asRelativePath: (pathOrUri: string | any, includeWorkspaceFolder?: boolean) => { - if (typeof pathOrUri === 'string') { - return pathOrUri.split('/').pop() || pathOrUri; - } - return pathOrUri.fsPath?.split('/').pop() || ''; - }, - onDidChangeTextDocument: () => ({ dispose: () => {} }), -}; - -export const window = { - activeTextEditor: undefined, - onDidChangeActiveTextEditor: () => ({ dispose: () => {} }), - showInformationMessage: () => Promise.resolve(), - showErrorMessage: () => Promise.resolve(), - createOutputChannel: () => ({ - appendLine: () => {}, - dispose: () => {}, - }), -}; - -export class Uri { - static file(path: string) { - return { fsPath: path }; - } - - fsPath: string = ''; -} - -export interface Disposable { - dispose(): void; -} - -export interface TextDocument { - uri: Uri; - isDirty: boolean; - getText(): string; -} - -export interface TextEditor { - document: TextDocument; -} diff --git a/test-runner.js b/test-runner.js new file mode 100644 index 0000000..74a2233 --- /dev/null +++ b/test-runner.js @@ -0,0 +1,17 @@ +const { execSync } = require('child_process'); + +try { + console.log('Running Dashboard tests...\n'); + const output = execSync('npx vitest run tests/unit/mobile-client/Dashboard.test.tsx --reporter=verbose --no-coverage', { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + maxBuffer: 10 * 1024 * 1024 + }); + console.log(output); + console.log('\n✓ Tests completed successfully'); +} catch (error) { + if (error.stdout) console.log('STDOUT:\n', error.stdout); + if (error.stderr) console.log('STDERR:\n', error.stderr); + console.log('\n✗ Tests failed with exit code:', error.status); + process.exit(error.status || 1); +} diff --git a/tests/e2e-integration.test.ts b/tests/e2e-integration.test.ts deleted file mode 100644 index bd588de..0000000 --- a/tests/e2e-integration.test.ts +++ /dev/null @@ -1,1101 +0,0 @@ -import { describe, it, expect, afterAll } from 'vitest'; -import { Server as SocketIOServer } from 'socket.io'; -import { io as ioClient, Socket as ClientSocket } from 'socket.io-client'; -import { startServer, mobileClients, extensionClients } from '../packages/relay-server/src/index'; -import { FileContextPayload, SyncFullContextMessage, PingMessage } from '../packages/protocol/src/index'; -import * as fs from 'fs/promises'; -import * as path from 'path'; -import { simpleGit, SimpleGit } from 'simple-git'; -import { tmpdir } from 'os'; - -/** - * End-to-End Integration Test for Git Integration & File Diffing - * - * This test verifies the complete pipeline: - * 1. Set up test Git repository with known files - * 2. Start relay server in test mode - * 3. Simulate VS Code extension behavior - * 4. Simulate mobile client behavior - * 5. Verify SYNC_FULL_CONTEXT message is sent - * 6. Verify message is routed through relay - * 7. Verify diff is received on mobile - * 8. Verify timing is under 2000ms - * - * Requirements: 7.5 - */ - -describe('End-to-End Integration Test', () => { - let relayServer: SocketIOServer; - let extensionClient: ClientSocket; - let mobileClient: ClientSocket; - let testRepoPath: string; - let git: SimpleGit; - const RELAY_PORT = 8081; // Use different port to avoid conflicts - const RELAY_URL = `http://localhost:${RELAY_PORT}`; - - beforeAll(async () => { - // Start relay server - relayServer = startServer(RELAY_PORT); - console.log('[E2E] Relay server started on port', RELAY_PORT); - - // Wait for server to be ready - await new Promise(resolve => setTimeout(resolve, 500)); - }); - - afterAll(async () => { - // Clean up relay server - if (relayServer) { - await new Promise((resolve) => { - relayServer.close(() => { - console.log('[E2E] Relay server closed'); - resolve(); - }); - }); - } - }); - - beforeEach(async () => { - // Create temporary test Git repository - testRepoPath = path.join(tmpdir(), `codelink-test-${Date.now()}`); - await fs.mkdir(testRepoPath, { recursive: true }); - - git = simpleGit(testRepoPath); - await git.init(); - await git.addConfig('user.name', 'Test User'); - await git.addConfig('user.email', 'test@example.com'); - - // Create initial file and commit - const testFilePath = path.join(testRepoPath, 'test.ts'); - await fs.writeFile(testFilePath, 'const original = "content";\n'); - await git.add('test.ts'); - await git.commit('Initial commit'); - - console.log('[E2E] Test Git repository created at', testRepoPath); - - // Clear client sets - mobileClients.clear(); - extensionClients.clear(); - }); - - afterEach(async () => { - // Disconnect clients - if (extensionClient?.connected) { - extensionClient.disconnect(); - } - if (mobileClient?.connected) { - mobileClient.disconnect(); - } - - // Clean up test repository - try { - await fs.rm(testRepoPath, { recursive: true, force: true }); - console.log('[E2E] Test repository cleaned up'); - } catch (error) { - console.error('[E2E] Error cleaning up test repository:', error); - } - - // Wait for cleanup - await new Promise(resolve => setTimeout(resolve, 100)); - }); - - it('should complete end-to-end flow from file edit to mobile display within 2000ms', async () => { - const startTime = Date.now(); - let _receivedPayload: FileContextPayload | null = null; - - // Step 1: Connect mobile client and register - mobileClient = ioClient(RELAY_URL, { - reconnectionDelay: 100, - reconnectionDelayMax: 500, - }); - - await new Promise((resolve) => { - mobileClient.on('connect', () => { - console.log('[E2E] Mobile client connected'); - - // Send ping to register as mobile client - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - - // Wait for registration - setTimeout(resolve, 100); - }); - }); - - // Step 2: Set up mobile client message listener - const mobileMessagePromise = new Promise((resolve) => { - mobileClient.on('message', (data: string) => { - console.log('[E2E] Mobile client received message'); - const message = JSON.parse(data); - - if (message.type === 'SYNC_FULL_CONTEXT') { - console.log('[E2E] Mobile client received SYNC_FULL_CONTEXT'); - _receivedPayload = message.payload; - resolve(message.payload); - } - }); - }); - - // Step 3: Connect extension client and register - extensionClient = ioClient(RELAY_URL, { - reconnectionDelay: 100, - reconnectionDelayMax: 500, - }); - - await new Promise((resolve) => { - extensionClient.on('connect', () => { - console.log('[E2E] Extension client connected'); - - // Send ping to register as extension client - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - - // Wait for registration - setTimeout(resolve, 100); - }); - }); - - // Step 4: Simulate file edit in VS Code - const testFilePath = path.join(testRepoPath, 'test.ts'); - const modifiedContent = 'const modified = "new content";\n'; - await fs.writeFile(testFilePath, modifiedContent); - console.log('[E2E] File modified'); - - // Step 5: Simulate VS Code extension pipeline - // (Git Integration → Diff Generator → WebSocket) - - // Fetch HEAD version - const headContent = await git.show(['HEAD:test.ts']); - console.log('[E2E] Fetched HEAD version'); - - // Read current file content - const currentContent = await fs.readFile(testFilePath, 'utf-8'); - console.log('[E2E] Read current file content'); - - // Create FileContextPayload - const payload: FileContextPayload = { - fileName: 'test.ts', - originalFile: headContent, - modifiedFile: currentContent, - isDirty: true, - timestamp: Date.now(), - }; - - // Create SYNC_FULL_CONTEXT message - const message: SyncFullContextMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - // Step 6: Send message from extension to relay server - extensionClient.emit('message', JSON.stringify(message)); - console.log('[E2E] Extension sent SYNC_FULL_CONTEXT message'); - - // Step 7: Wait for mobile client to receive the message - const receivedPayloadResult = await Promise.race([ - mobileMessagePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout waiting for message')), 3000) - ), - ]); - - // Step 8: Verify the message was received correctly - expect(receivedPayloadResult).not.toBeNull(); - expect(receivedPayloadResult?.fileName).toBe('test.ts'); - expect(receivedPayloadResult?.originalFile).toBe(headContent); - expect(receivedPayloadResult?.modifiedFile).toBe(modifiedContent); - expect(receivedPayloadResult?.isDirty).toBe(true); - expect(receivedPayloadResult?.timestamp).toBeGreaterThan(0); - - // Step 9: Verify timing is under 2000ms - const endTime = Date.now(); - const totalTime = endTime - startTime; - console.log(`[E2E] Total time: ${totalTime}ms`); - - expect(totalTime).toBeLessThan(2000); - }); - - it('should handle untracked files correctly', async () => { - // Connect clients - mobileClient = ioClient(RELAY_URL); - extensionClient = ioClient(RELAY_URL); - - await Promise.all([ - new Promise((resolve) => { - mobileClient.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - new Promise((resolve) => { - extensionClient.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - ]); - - // Set up mobile client listener - const mobileMessagePromise = new Promise((resolve) => { - mobileClient.on('message', (data: string) => { - const message = JSON.parse(data); - if (message.type === 'SYNC_FULL_CONTEXT') { - resolve(message.payload); - } - }); - }); - - // Create new untracked file - const newFilePath = path.join(testRepoPath, 'newfile.ts'); - const newFileContent = 'const newFile = "untracked";\n'; - await fs.writeFile(newFilePath, newFileContent); - - // Simulate extension behavior for untracked file - // (getHeadVersion should return empty string for untracked files) - const payload: FileContextPayload = { - fileName: 'newfile.ts', - originalFile: '', // Empty for untracked files - modifiedFile: newFileContent, - isDirty: false, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - extensionClient.emit('message', JSON.stringify(message)); - - // Verify mobile client receives the message - const receivedPayload = await Promise.race([ - mobileMessagePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout')), 2000) - ), - ]); - - expect(receivedPayload).not.toBeNull(); - expect(receivedPayload?.fileName).toBe('newfile.ts'); - expect(receivedPayload?.originalFile).toBe(''); // Empty for untracked - expect(receivedPayload?.modifiedFile).toBe(newFileContent); - }); - - it('should route messages to multiple mobile clients', async () => { - // Connect extension client - extensionClient = ioClient(RELAY_URL); - await new Promise((resolve) => { - extensionClient.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }); - - // Connect multiple mobile clients - const mobileClient1 = ioClient(RELAY_URL); - const mobileClient2 = ioClient(RELAY_URL); - const mobileClient3 = ioClient(RELAY_URL); - - await Promise.all([ - new Promise((resolve) => { - mobileClient1.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient1.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - new Promise((resolve) => { - mobileClient2.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient2.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - new Promise((resolve) => { - mobileClient3.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient3.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - ]); - - // Set up listeners for all mobile clients - const receivedPayloads: FileContextPayload[] = []; - const promises = [mobileClient1, mobileClient2, mobileClient3].map((client) => { - return new Promise((resolve) => { - client.on('message', (data: string) => { - const message = JSON.parse(data); - if (message.type === 'SYNC_FULL_CONTEXT') { - receivedPayloads.push(message.payload); - resolve(message.payload); - } - }); - }); - }); - - // Send message from extension - const payload: FileContextPayload = { - fileName: 'test.ts', - originalFile: 'original', - modifiedFile: 'modified', - isDirty: true, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - extensionClient.emit('message', JSON.stringify(message)); - - // Wait for all mobile clients to receive the message - await Promise.all(promises); - - // Verify all clients received the message - expect(receivedPayloads).toHaveLength(3); - receivedPayloads.forEach((received) => { - expect(received.fileName).toBe('test.ts'); - expect(received.originalFile).toBe('original'); - expect(received.modifiedFile).toBe('modified'); - expect(received.isDirty).toBe(true); - }); - - // Clean up - mobileClient1.disconnect(); - mobileClient2.disconnect(); - mobileClient3.disconnect(); - }); - - it('should handle no-change scenario correctly', async () => { - // Connect clients - mobileClient = ioClient(RELAY_URL); - extensionClient = ioClient(RELAY_URL); - - await Promise.all([ - new Promise((resolve) => { - mobileClient.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - new Promise((resolve) => { - extensionClient.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - ]); - - // Set up mobile client listener - const mobileMessagePromise = new Promise((resolve) => { - mobileClient.on('message', (data: string) => { - const message = JSON.parse(data); - if (message.type === 'SYNC_FULL_CONTEXT') { - resolve(message.payload); - } - }); - }); - - // Fetch HEAD version (no changes) - const testFilePath = path.join(testRepoPath, 'test.ts'); - const headContent = await git.show(['HEAD:test.ts']); - const currentContent = await fs.readFile(testFilePath, 'utf-8'); - - // Both should be the same (no changes) - expect(currentContent).toBe(headContent); - - // Send message with no changes - const payload: FileContextPayload = { - fileName: 'test.ts', - originalFile: headContent, - modifiedFile: currentContent, - isDirty: false, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - extensionClient.emit('message', JSON.stringify(message)); - - // Verify mobile client receives the message - const receivedPayload = await Promise.race([ - mobileMessagePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout')), 2000) - ), - ]); - - expect(receivedPayload).not.toBeNull(); - expect(receivedPayload?.originalFile).toBe(receivedPayload?.modifiedFile); - expect(receivedPayload?.isDirty).toBe(false); - }); - - it('should verify message structure completeness', async () => { - // Connect clients - mobileClient = ioClient(RELAY_URL); - extensionClient = ioClient(RELAY_URL); - - await Promise.all([ - new Promise((resolve) => { - mobileClient.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - new Promise((resolve) => { - extensionClient.on('connect', () => { - const ping: PingMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - ]); - - // Set up mobile client listener - const mobileMessagePromise = new Promise((resolve) => { - mobileClient.on('message', (data: string) => { - const message = JSON.parse(data); - if (message.type === 'SYNC_FULL_CONTEXT') { - resolve(message); - } - }); - }); - - // Send complete message - const payload: FileContextPayload = { - fileName: 'test.ts', - originalFile: 'original content', - modifiedFile: 'modified content', - isDirty: true, - timestamp: Date.now(), - }; - - const message: SyncFullContextMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'SYNC_FULL_CONTEXT', - payload, - }; - - extensionClient.emit('message', JSON.stringify(message)); - - // Verify message structure - const receivedMessage = await Promise.race([ - mobileMessagePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout')), 2000) - ), - ]); - - // Verify all required fields are present - expect(receivedMessage).not.toBeNull(); - expect(receivedMessage?.id).toBeDefined(); - expect(receivedMessage?.timestamp).toBeDefined(); - expect(receivedMessage?.type).toBe('SYNC_FULL_CONTEXT'); - expect(receivedMessage?.payload).toBeDefined(); - expect(receivedMessage?.payload.fileName).toBeDefined(); - expect(receivedMessage?.payload.originalFile).toBeDefined(); - expect(receivedMessage?.payload.modifiedFile).toBeDefined(); - expect(receivedMessage?.payload.isDirty).toBeDefined(); - expect(receivedMessage?.payload.timestamp).toBeDefined(); - }); -}); - -/** - * End-to-End Integration Test for WebSocket Prompt Injection - * - * This test verifies the complete prompt injection pipeline: - * 1. Mobile client sends INJECT_PROMPT message - * 2. Relay server routes message to extension client - * 3. Extension client processes prompt injection - * 4. Extension client sends INJECT_PROMPT_RESPONSE back - * 5. Mobile client receives response - * - * Requirements: 2.1, 2.4, 2.5 - */ -describe('WebSocket Prompt Injection Integration Test', () => { - let relayServer: SocketIOServer; - let extensionClient: ClientSocket; - let mobileClient: ClientSocket; - const RELAY_PORT = 8082; // Use different port to avoid conflicts - const RELAY_URL = `http://localhost:${RELAY_PORT}`; - - beforeAll(async () => { - // Start relay server - relayServer = startServer(RELAY_PORT); - console.log('[E2E-Prompt] Relay server started on port', RELAY_PORT); - - // Wait for server to be ready - await new Promise(resolve => setTimeout(resolve, 500)); - }); - - afterAll(async () => { - // Clean up relay server - if (relayServer) { - await new Promise((resolve) => { - relayServer.close(() => { - console.log('[E2E-Prompt] Relay server closed'); - resolve(); - }); - }); - } - }); - - beforeEach(async () => { - // Clear client sets - mobileClients.clear(); - extensionClients.clear(); - }); - - afterEach(async () => { - // Disconnect clients - if (extensionClient?.connected) { - extensionClient.disconnect(); - } - if (mobileClient?.connected) { - mobileClient.disconnect(); - } - - // Wait for cleanup - await new Promise(resolve => setTimeout(resolve, 100)); - }); - - it('should complete end-to-end prompt injection flow: mobile → relay → extension → mobile', async () => { - // Step 1: Connect extension client and register - extensionClient = ioClient(RELAY_URL, { - reconnectionDelay: 100, - reconnectionDelayMax: 500, - }); - - await new Promise((resolve) => { - extensionClient.on('connect', () => { - console.log('[E2E-Prompt] Extension client connected'); - - // Send ping to register as extension client - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - - // Wait for registration - setTimeout(resolve, 100); - }); - }); - - // Step 2: Set up extension client to handle INJECT_PROMPT messages - // Simulate extension behavior: receive prompt, send response - extensionClient.on('message', (data: string) => { - const message = JSON.parse(data); - console.log('[E2E-Prompt] Extension received message type:', message.type); - - if (message.type === 'INJECT_PROMPT') { - console.log('[E2E-Prompt] Extension processing prompt injection'); - - // Simulate successful prompt injection - const response = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT_RESPONSE', - success: true, - editorUsed: 'TestEditor', - commandUsed: 'test.injectPrompt', - originalRequestId: message.id, // Include original request ID - }; - - extensionClient.emit('message', JSON.stringify(response)); - console.log('[E2E-Prompt] Extension sent response'); - } - }); - - // Step 3: Connect mobile client and register - mobileClient = ioClient(RELAY_URL, { - reconnectionDelay: 100, - reconnectionDelayMax: 500, - }); - - await new Promise((resolve) => { - mobileClient.on('connect', () => { - console.log('[E2E-Prompt] Mobile client connected'); - - // Send ping to register as mobile client - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - - // Wait for registration - setTimeout(resolve, 100); - }); - }); - - // Step 4: Set up mobile client message listener for response - const mobileResponsePromise = new Promise((resolve) => { - mobileClient.on('message', (data: string) => { - const message = JSON.parse(data); - console.log('[E2E-Prompt] Mobile received message type:', message.type); - - if (message.type === 'INJECT_PROMPT_RESPONSE') { - console.log('[E2E-Prompt] Mobile received INJECT_PROMPT_RESPONSE'); - resolve(message); - } - }); - }); - - // Step 5: Send INJECT_PROMPT message from mobile - const promptMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT', - prompt: 'Test prompt from mobile client', - }; - - mobileClient.emit('message', JSON.stringify(promptMessage)); - console.log('[E2E-Prompt] Mobile sent INJECT_PROMPT message'); - - // Step 6: Wait for response - const response = await Promise.race([ - mobileResponsePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout waiting for response')), 3000) - ), - ]); - - // Step 7: Verify response - expect(response).not.toBeNull(); - expect(response.type).toBe('INJECT_PROMPT_RESPONSE'); - expect(response.success).toBe(true); - expect(response.editorUsed).toBe('TestEditor'); - expect(response.commandUsed).toBe('test.injectPrompt'); - expect(response.id).toBeDefined(); - expect(response.timestamp).toBeGreaterThan(0); - }); - - it('should handle error when no extension client is connected', async () => { - // Step 1: Connect mobile client only (no extension) - mobileClient = ioClient(RELAY_URL, { - reconnectionDelay: 100, - reconnectionDelayMax: 500, - }); - - await new Promise((resolve) => { - mobileClient.on('connect', () => { - console.log('[E2E-Prompt] Mobile client connected'); - - // Send ping to register as mobile client - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - - // Wait for registration - setTimeout(resolve, 100); - }); - }); - - // Step 2: Set up mobile client message listener for error response - const mobileResponsePromise = new Promise((resolve) => { - mobileClient.on('message', (data: string) => { - const message = JSON.parse(data); - - if (message.type === 'INJECT_PROMPT_RESPONSE') { - resolve(message); - } - }); - }); - - // Step 3: Send INJECT_PROMPT message from mobile - const promptMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT', - prompt: 'Test prompt with no extension', - }; - - mobileClient.emit('message', JSON.stringify(promptMessage)); - console.log('[E2E-Prompt] Mobile sent INJECT_PROMPT with no extension available'); - - // Step 4: Wait for error response - const response = await Promise.race([ - mobileResponsePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout waiting for error response')), 3000) - ), - ]); - - // Step 5: Verify error response - expect(response).not.toBeNull(); - expect(response.type).toBe('INJECT_PROMPT_RESPONSE'); - expect(response.success).toBe(false); - expect(response.error).toBeDefined(); - expect(response.error).toContain('No extension client'); - }); - - it('should handle prompt injection failure from extension', async () => { - // Step 1: Connect extension client and register - extensionClient = ioClient(RELAY_URL, { - reconnectionDelay: 100, - reconnectionDelayMax: 500, - }); - - await new Promise((resolve) => { - extensionClient.on('connect', () => { - console.log('[E2E-Prompt] Extension client connected'); - - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - - setTimeout(resolve, 100); - }); - }); - - // Step 2: Set up extension client to simulate injection failure - extensionClient.on('message', (data: string) => { - const message = JSON.parse(data); - - if (message.type === 'INJECT_PROMPT') { - console.log('[E2E-Prompt] Extension simulating injection failure'); - - // Simulate failed prompt injection - const response = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT_RESPONSE', - success: false, - error: 'Command execution failed: editor not responding', - editorUsed: 'TestEditor', - commandUsed: 'test.injectPrompt', - originalRequestId: message.id, - }; - - extensionClient.emit('message', JSON.stringify(response)); - } - }); - - // Step 3: Connect mobile client and register - mobileClient = ioClient(RELAY_URL, { - reconnectionDelay: 100, - reconnectionDelayMax: 500, - }); - - await new Promise((resolve) => { - mobileClient.on('connect', () => { - console.log('[E2E-Prompt] Mobile client connected'); - - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - - setTimeout(resolve, 100); - }); - }); - - // Step 4: Set up mobile client message listener - const mobileResponsePromise = new Promise((resolve) => { - mobileClient.on('message', (data: string) => { - const message = JSON.parse(data); - - if (message.type === 'INJECT_PROMPT_RESPONSE') { - resolve(message); - } - }); - }); - - // Step 5: Send INJECT_PROMPT message from mobile - const promptMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT', - prompt: 'Test prompt that will fail', - }; - - mobileClient.emit('message', JSON.stringify(promptMessage)); - - // Step 6: Wait for failure response - const response = await Promise.race([ - mobileResponsePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout waiting for response')), 3000) - ), - ]); - - // Step 7: Verify failure response - expect(response).not.toBeNull(); - expect(response.type).toBe('INJECT_PROMPT_RESPONSE'); - expect(response.success).toBe(false); - expect(response.error).toBeDefined(); - expect(response.error).toContain('Command execution failed'); - expect(response.editorUsed).toBe('TestEditor'); - expect(response.commandUsed).toBe('test.injectPrompt'); - }); - - it('should handle multiple prompt injections sequentially', async () => { - // Step 1: Connect extension client - extensionClient = ioClient(RELAY_URL); - - await new Promise((resolve) => { - extensionClient.on('connect', () => { - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }); - - // Set up extension to handle prompts - let promptCount = 0; - extensionClient.on('message', (data: string) => { - const message = JSON.parse(data); - - if (message.type === 'INJECT_PROMPT') { - promptCount++; - const response = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT_RESPONSE', - success: true, - editorUsed: 'TestEditor', - commandUsed: `test.injectPrompt.${promptCount}`, - originalRequestId: message.id, - }; - - extensionClient.emit('message', JSON.stringify(response)); - } - }); - - // Step 2: Connect mobile client - mobileClient = ioClient(RELAY_URL); - - await new Promise((resolve) => { - mobileClient.on('connect', () => { - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }); - - // Step 3: Send multiple prompts and collect responses - const responses: any[] = []; - const responsePromises: Promise[] = []; - - for (let i = 0; i < 3; i++) { - const responsePromise = new Promise((resolve) => { - const handler = (data: string) => { - const message = JSON.parse(data); - if (message.type === 'INJECT_PROMPT_RESPONSE' && responses.length === i) { - responses.push(message); - resolve(message); - } - }; - mobileClient.on('message', handler); - }); - - responsePromises.push(responsePromise); - - const promptMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT', - prompt: `Test prompt ${i + 1}`, - }; - - mobileClient.emit('message', JSON.stringify(promptMessage)); - - // Wait a bit between prompts - await new Promise(resolve => setTimeout(resolve, 100)); - } - - // Wait for all responses - await Promise.all(responsePromises); - - // Verify all responses - expect(responses).toHaveLength(3); - responses.forEach((response, index) => { - expect(response.success).toBe(true); - expect(response.editorUsed).toBe('TestEditor'); - }); - }); - - it('should verify prompt injection message structure', async () => { - // Connect clients - extensionClient = ioClient(RELAY_URL); - mobileClient = ioClient(RELAY_URL); - - await Promise.all([ - new Promise((resolve) => { - extensionClient.on('connect', () => { - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'extension', - }; - extensionClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - new Promise((resolve) => { - mobileClient.on('connect', () => { - const ping = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'ping', - source: 'mobile', - }; - mobileClient.emit('message', JSON.stringify(ping)); - setTimeout(resolve, 100); - }); - }), - ]); - - // Capture the message received by extension - const extensionMessagePromise = new Promise((resolve) => { - extensionClient.on('message', (data: string) => { - const message = JSON.parse(data); - if (message.type === 'INJECT_PROMPT') { - resolve(message); - - // Send response - const response = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT_RESPONSE', - success: true, - editorUsed: 'TestEditor', - commandUsed: 'test.command', - originalRequestId: message.id, - }; - extensionClient.emit('message', JSON.stringify(response)); - } - }); - }); - - // Send prompt from mobile - const promptMessage = { - id: crypto.randomUUID(), - timestamp: Date.now(), - type: 'INJECT_PROMPT', - prompt: 'Verify message structure', - }; - - mobileClient.emit('message', JSON.stringify(promptMessage)); - - // Verify message structure received by extension - const receivedMessage = await Promise.race([ - extensionMessagePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Timeout')), 2000) - ), - ]); - - expect(receivedMessage).not.toBeNull(); - expect(receivedMessage.id).toBeDefined(); - expect(receivedMessage.timestamp).toBeDefined(); - expect(receivedMessage.type).toBe('INJECT_PROMPT'); - expect(receivedMessage.prompt).toBe('Verify message structure'); - }); -}); diff --git a/tests/package-compilation.test.ts b/tests/package-compilation.test.ts deleted file mode 100644 index 4f0668d..0000000 --- a/tests/package-compilation.test.ts +++ /dev/null @@ -1,157 +0,0 @@ -import * as fc from 'fast-check'; -import * as fs from 'fs'; -import * as path from 'path'; - -// Feature: codelink-initialization, Property 6: All packages compile successfully -describe('Property 6: All packages compile successfully', () => { - it('should compile all packages without TypeScript errors', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const packagesDir = path.join(rootDir, 'packages'); - - // Check if packages directory exists - if (!fs.existsSync(packagesDir)) { - return true; // Skip if packages don't exist yet - } - - const packageDirs = fs.readdirSync(packagesDir).filter((name) => { - const fullPath = path.join(packagesDir, name); - return fs.statSync(fullPath).isDirectory(); - }); - - for (const pkgDir of packageDirs) { - const pkgPath = path.join(packagesDir, pkgDir); - const pkgJsonPath = path.join(pkgPath, 'package.json'); - const distPath = path.join(pkgPath, 'dist'); - - if (fs.existsSync(pkgJsonPath)) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); - - // Check if package has a build script - if (pkgJson.scripts && pkgJson.scripts.build) { - // Verify dist directory exists (should be created by build) - if (!fs.existsSync(distPath)) { - throw new Error( - `${pkgDir} has a build script but dist/ directory does not exist. Run build first.` - ); - } - - // Verify dist directory contains output files - const distFiles = fs.readdirSync(distPath); - if (distFiles.length === 0) { - throw new Error(`${pkgDir}/dist/ directory is empty after build`); - } - - // Check if this is a Vite package (has vite.config.ts) - const isVitePackage = fs.existsSync(path.join(pkgPath, 'vite.config.ts')); - - if (isVitePackage) { - // For Vite packages, check for bundled assets - const assetsDir = path.join(distPath, 'assets'); - if (fs.existsSync(assetsDir)) { - const assetFiles = fs.readdirSync(assetsDir); - const hasJsFiles = assetFiles.some((file) => file.endsWith('.js')); - if (!hasJsFiles) { - throw new Error( - `${pkgDir}/dist/assets/ does not contain bundled JavaScript files` - ); - } - } - } else { - // For TypeScript packages, verify JavaScript and type definition files - const hasJsFiles = distFiles.some((file) => file.endsWith('.js')); - if (!hasJsFiles) { - throw new Error(`${pkgDir}/dist/ does not contain compiled JavaScript files`); - } - - const hasDtsFiles = distFiles.some((file) => file.endsWith('.d.ts')); - if (!hasDtsFiles) { - throw new Error(`${pkgDir}/dist/ does not contain type definition files`); - } - } - } - } - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should verify TypeScript compilation produces valid output', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const packagesDir = path.join(rootDir, 'packages'); - - // Check if packages directory exists - if (!fs.existsSync(packagesDir)) { - return true; // Skip if packages don't exist yet - } - - const packageDirs = fs.readdirSync(packagesDir).filter((name) => { - const fullPath = path.join(packagesDir, name); - return fs.statSync(fullPath).isDirectory(); - }); - - for (const pkgDir of packageDirs) { - const pkgPath = path.join(packagesDir, pkgDir); - const pkgJsonPath = path.join(pkgPath, 'package.json'); - const tsconfigPath = path.join(pkgPath, 'tsconfig.json'); - const distPath = path.join(pkgPath, 'dist'); - - if ( - fs.existsSync(tsconfigPath) && - fs.existsSync(distPath) && - fs.existsSync(pkgJsonPath) - ) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); - - // Skip Vite packages (they don't produce TypeScript compiled output) - const isVitePackage = fs.existsSync(path.join(pkgPath, 'vite.config.ts')); - if (isVitePackage) { - continue; - } - - const mainEntry = pkgJson.main; - - if (!mainEntry) { - throw new Error(`${pkgDir}/package.json does not specify a main entry point`); - } - - const mainJsPath = path.join(pkgPath, mainEntry); - const mainDtsPath = path.join(pkgPath, mainEntry.replace('.js', '.d.ts')); - - if (!fs.existsSync(mainJsPath)) { - throw new Error(`${pkgDir} main entry file does not exist: ${mainEntry}`); - } - - if (!fs.existsSync(mainDtsPath)) { - throw new Error( - `${pkgDir} type definition file does not exist: ${mainEntry.replace('.js', '.d.ts')}` - ); - } - - // Verify the files are not empty - const jsContent = fs.readFileSync(mainJsPath, 'utf-8'); - if (jsContent.trim().length === 0) { - throw new Error(`${pkgDir} main entry file is empty: ${mainEntry}`); - } - - const dtsContent = fs.readFileSync(mainDtsPath, 'utf-8'); - if (dtsContent.trim().length === 0) { - throw new Error( - `${pkgDir} type definition file is empty: ${mainEntry.replace('.js', '.d.ts')}` - ); - } - } - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); diff --git a/tests/protocol-imports.test.ts b/tests/protocol-imports.test.ts deleted file mode 100644 index 3cad509..0000000 --- a/tests/protocol-imports.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import * as fc from 'fast-check'; -import * as fs from 'fs'; -import * as path from 'path'; - -// Feature: codelink-initialization, Property 7: Protocol package exports are importable -describe('Property 7: Protocol package exports are importable', () => { - it('should allow vscode-extension to import PingMessage from @codelink/protocol', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const extensionSrcPath = path.join( - rootDir, - 'packages', - 'vscode-extension', - 'src', - 'extension.ts' - ); - - // Check if extension source exists - if (!fs.existsSync(extensionSrcPath)) { - throw new Error('vscode-extension/src/extension.ts does not exist'); - } - - const extensionSrc = fs.readFileSync(extensionSrcPath, 'utf-8'); - - // Verify the extension imports from @codelink/protocol - const hasProtocolImport = extensionSrc.includes('@codelink/protocol'); - if (!hasProtocolImport) { - throw new Error('vscode-extension does not import from @codelink/protocol'); - } - - // Verify SyncFullContextMessage is imported or used (actual type used by extension) - const usesSyncFullContextMessage = extensionSrc.includes('SyncFullContextMessage'); - if (!usesSyncFullContextMessage) { - throw new Error('vscode-extension does not use SyncFullContextMessage type'); - } - - // Verify the package.json has the dependency - const pkgJsonPath = path.join(rootDir, 'packages', 'vscode-extension', 'package.json'); - if (fs.existsSync(pkgJsonPath)) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); - const hasDependency = pkgJson.dependencies && pkgJson.dependencies['@codelink/protocol']; - if (!hasDependency) { - throw new Error( - 'vscode-extension package.json does not list @codelink/protocol as a dependency' - ); - } - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should allow relay-server to import ProtocolMessage from @codelink/protocol', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const serverSrcPath = path.join(rootDir, 'packages', 'relay-server', 'src', 'index.ts'); - - // Check if server source exists - if (!fs.existsSync(serverSrcPath)) { - throw new Error('relay-server/src/index.ts does not exist'); - } - - const serverSrc = fs.readFileSync(serverSrcPath, 'utf-8'); - - // Verify the server imports from @codelink/protocol - const hasProtocolImport = serverSrc.includes('@codelink/protocol'); - if (!hasProtocolImport) { - throw new Error('relay-server does not import from @codelink/protocol'); - } - - // Verify ProtocolMessage is imported or used - const usesProtocolMessage = serverSrc.includes('ProtocolMessage'); - if (!usesProtocolMessage) { - throw new Error('relay-server does not use ProtocolMessage type'); - } - - // Verify the package.json has the dependency - const pkgJsonPath = path.join(rootDir, 'packages', 'relay-server', 'package.json'); - if (fs.existsSync(pkgJsonPath)) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); - const hasDependency = pkgJson.dependencies && pkgJson.dependencies['@codelink/protocol']; - if (!hasDependency) { - throw new Error( - 'relay-server package.json does not list @codelink/protocol as a dependency' - ); - } - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should allow mobile-client to import PongMessage from @codelink/protocol', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const clientSrcPath = path.join(rootDir, 'packages', 'mobile-client', 'src', 'App.tsx'); - - // Check if client source exists - if (!fs.existsSync(clientSrcPath)) { - throw new Error('mobile-client/src/App.tsx does not exist'); - } - - const clientSrc = fs.readFileSync(clientSrcPath, 'utf-8'); - - // Verify the client imports from @codelink/protocol - const hasProtocolImport = clientSrc.includes('@codelink/protocol'); - if (!hasProtocolImport) { - throw new Error('mobile-client does not import from @codelink/protocol'); - } - - // Verify FileContextPayload is imported or used (actual type used by mobile client) - const usesFileContextPayload = clientSrc.includes('FileContextPayload'); - if (!usesFileContextPayload) { - throw new Error('mobile-client does not use FileContextPayload type'); - } - - // Verify the package.json has the dependency - const pkgJsonPath = path.join(rootDir, 'packages', 'mobile-client', 'package.json'); - if (fs.existsSync(pkgJsonPath)) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); - const hasDependency = pkgJson.dependencies && pkgJson.dependencies['@codelink/protocol']; - if (!hasDependency) { - throw new Error( - 'mobile-client package.json does not list @codelink/protocol as a dependency' - ); - } - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); diff --git a/tests/protocol-package.test.ts b/tests/protocol-package.test.ts deleted file mode 100644 index 95b30f6..0000000 --- a/tests/protocol-package.test.ts +++ /dev/null @@ -1,162 +0,0 @@ -import * as fc from 'fast-check'; -import * as fs from 'fs'; -import * as path from 'path'; - -// Feature: codelink-initialization, Property 2: All package.json files contain required fields -describe('Property 2: All package.json files contain required fields', () => { - it('should have required fields in all package.json files', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const packagesDir = path.join(rootDir, 'packages'); - - // Check if packages directory exists - if (!fs.existsSync(packagesDir)) { - return true; // Skip if packages don't exist yet - } - - const packageDirs = fs.readdirSync(packagesDir).filter((name) => { - const fullPath = path.join(packagesDir, name); - return fs.statSync(fullPath).isDirectory(); - }); - - for (const pkgDir of packageDirs) { - const pkgJsonPath = path.join(packagesDir, pkgDir, 'package.json'); - - if (fs.existsSync(pkgJsonPath)) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); - - // Required fields for all packages - if (!pkgJson.name) { - throw new Error(`${pkgDir}/package.json missing required field: name`); - } - if (!pkgJson.version) { - throw new Error(`${pkgDir}/package.json missing required field: version`); - } - if (!pkgJson.scripts) { - throw new Error(`${pkgDir}/package.json missing required field: scripts`); - } - if (!pkgJson.scripts.build) { - throw new Error(`${pkgDir}/package.json missing required script: build`); - } - if (!pkgJson.scripts.dev) { - throw new Error(`${pkgDir}/package.json missing required script: dev`); - } - - // VS Code extension specific requirements - if (pkgDir === 'vscode-extension') { - if (!pkgJson.engines) { - throw new Error(`${pkgDir}/package.json missing required field: engines`); - } - if (!pkgJson.activationEvents) { - throw new Error(`${pkgDir}/package.json missing required field: activationEvents`); - } - } - - // Mobile client specific requirements - if (pkgDir === 'mobile-client') { - if (pkgJson.type !== 'module') { - throw new Error( - `${pkgDir}/package.json missing or incorrect field: type (should be "module")` - ); - } - } - } - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); - -// Feature: codelink-initialization, Property 3: All TypeScript configurations extend base configuration -describe('Property 3: All TypeScript configurations extend base configuration', () => { - it('should extend tsconfig.base.json in all package tsconfig files', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const packagesDir = path.join(rootDir, 'packages'); - - // Check if packages directory exists - if (!fs.existsSync(packagesDir)) { - return true; // Skip if packages don't exist yet - } - - const packageDirs = fs.readdirSync(packagesDir).filter((name) => { - const fullPath = path.join(packagesDir, name); - return fs.statSync(fullPath).isDirectory(); - }); - - for (const pkgDir of packageDirs) { - const tsconfigPath = path.join(packagesDir, pkgDir, 'tsconfig.json'); - - if (fs.existsSync(tsconfigPath)) { - const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8')); - - if (!tsconfig.extends) { - throw new Error(`${pkgDir}/tsconfig.json missing "extends" field`); - } - - // Verify it extends the base config - const extendsPath = tsconfig.extends; - if (!extendsPath.includes('tsconfig.base.json')) { - throw new Error( - `${pkgDir}/tsconfig.json does not extend tsconfig.base.json (extends: ${extendsPath})` - ); - } - } - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); - -// Feature: codelink-initialization, Property 5: All packages have appropriate entry points -describe('Property 5: All packages have appropriate entry points', () => { - it('should define entry points in package.json for packages that produce output', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const packagesDir = path.join(rootDir, 'packages'); - - // Check if packages directory exists - if (!fs.existsSync(packagesDir)) { - return true; // Skip if packages don't exist yet - } - - const packageDirs = fs.readdirSync(packagesDir).filter((name) => { - const fullPath = path.join(packagesDir, name); - return fs.statSync(fullPath).isDirectory(); - }); - - for (const pkgDir of packageDirs) { - const pkgJsonPath = path.join(packagesDir, pkgDir, 'package.json'); - - if (fs.existsSync(pkgJsonPath)) { - const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); - - // All packages should have a main entry point - if (!pkgJson.main) { - throw new Error(`${pkgDir}/package.json missing "main" entry point`); - } - - // Verify main points to dist directory - if (!pkgJson.main.includes('dist')) { - throw new Error( - `${pkgDir}/package.json main entry point should point to dist/ directory (got: ${pkgJson.main})` - ); - } - } - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); diff --git a/tests/readme-documentation.test.ts b/tests/readme-documentation.test.ts deleted file mode 100644 index 1c74473..0000000 --- a/tests/readme-documentation.test.ts +++ /dev/null @@ -1,220 +0,0 @@ -import * as fc from 'fast-check'; -import * as fs from 'fs'; -import * as path from 'path'; - -// Feature: codelink-initialization, Property 8: README contains required documentation sections -describe('Property 8: README contains required documentation sections', () => { - it('should have README.md file in root directory', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - throw new Error('README.md file does not exist in root directory'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should contain architecture overview section', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - return true; // Skip if README doesn't exist yet - } - - const content = fs.readFileSync(readmePath, 'utf-8'); - - // Check for architecture overview section - if (!content.includes('Architecture') && !content.includes('architecture')) { - throw new Error('README.md missing architecture overview section'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should document the three main components', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - return true; // Skip if README doesn't exist yet - } - - const content = fs.readFileSync(readmePath, 'utf-8'); - - // Check for VS Code extension documentation - if (!content.includes('VS Code') && !content.includes('vscode-extension')) { - throw new Error('README.md missing VS Code extension documentation'); - } - - // Check for relay server documentation - if (!content.includes('relay') && !content.includes('Relay')) { - throw new Error('README.md missing relay server documentation'); - } - - // Check for mobile client documentation - if (!content.includes('mobile') && !content.includes('Mobile')) { - throw new Error('README.md missing mobile client documentation'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should contain setup instructions', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - return true; // Skip if README doesn't exist yet - } - - const content = fs.readFileSync(readmePath, 'utf-8'); - - // Check for setup/installation section - if (!content.includes('Setup') && !content.includes('Installation')) { - throw new Error('README.md missing setup/installation section'); - } - - // Check for npm install command - if (!content.includes('npm install')) { - throw new Error('README.md missing npm install command in setup instructions'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should contain development instructions', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - return true; // Skip if README doesn't exist yet - } - - const content = fs.readFileSync(readmePath, 'utf-8'); - - // Check for development section - if (!content.includes('Development') && !content.includes('Running')) { - throw new Error('README.md missing development instructions section'); - } - - // Check for npm run dev command - if (!content.includes('npm run dev')) { - throw new Error('README.md missing npm run dev command in development instructions'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should explain core principles', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - return true; // Skip if README doesn't exist yet - } - - const content = fs.readFileSync(readmePath, 'utf-8'); - - // Check for core principles section - if (!content.includes('Principles') && !content.includes('principles')) { - throw new Error('README.md missing core principles section'); - } - - // Check for key principles - const lowerContent = content.toLowerCase(); - - if (!lowerContent.includes('cloud') && !lowerContent.includes('ide')) { - throw new Error('README.md missing explanation of "no cloud IDE" principle'); - } - - if (!lowerContent.includes('approval') || !lowerContent.includes('human')) { - throw new Error('README.md missing explanation of "human approval required" principle'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should document unified diff as primary UI artifact', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - return true; // Skip if README doesn't exist yet - } - - const content = fs.readFileSync(readmePath, 'utf-8'); - const lowerContent = content.toLowerCase(); - - // Check for unified diff or diff mention - if (!lowerContent.includes('diff')) { - throw new Error('README.md missing documentation about unified diff UI'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should document code quality scripts', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const readmePath = path.join(rootDir, 'README.md'); - - if (!fs.existsSync(readmePath)) { - return true; // Skip if README doesn't exist yet - } - - const content = fs.readFileSync(readmePath, 'utf-8'); - - // Check for lint command - if (!content.includes('npm run lint') && !content.includes('lint')) { - throw new Error('README.md missing lint script documentation'); - } - - // Check for format command - if (!content.includes('npm run format') && !content.includes('format')) { - throw new Error('README.md missing format script documentation'); - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); diff --git a/tests/root-config.test.ts b/tests/root-config.test.ts deleted file mode 100644 index db64854..0000000 --- a/tests/root-config.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import * as fc from 'fast-check'; -import * as fs from 'fs'; -import * as path from 'path'; - -// Feature: codelink-initialization, Property 1: Required project structure exists -describe('Property 1: Required project structure exists', () => { - it('should have all required root configuration files', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - - // Required root files - const requiredFiles = [ - 'package.json', - 'tsconfig.base.json', - '.eslintrc.json', - '.prettierrc.json', - '.gitignore', - ]; - - for (const file of requiredFiles) { - const filePath = path.join(rootDir, file); - const exists = fs.existsSync(filePath); - if (!exists) { - throw new Error(`Required file missing: ${file}`); - } - } - - // Required packages directory - const packagesDir = path.join(rootDir, 'packages'); - if (!fs.existsSync(packagesDir)) { - throw new Error('Required directory missing: packages/'); - } - - return true; - }), - { numRuns: 100 } - ); - }); - - it('should have packages directory structure', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - const packagesDir = path.join(rootDir, 'packages'); - - // Check packages directory exists - if (!fs.existsSync(packagesDir)) { - throw new Error('packages/ directory does not exist'); - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); - -// Feature: codelink-initialization, Property 4: Configuration files contain no placeholder content -describe('Property 4: Configuration files contain no placeholder content', () => { - it('should not contain placeholder markers in configuration files', () => { - fc.assert( - fc.property(fc.constant(null), () => { - const rootDir = path.resolve(__dirname, '..'); - - const configFiles = [ - 'package.json', - 'tsconfig.base.json', - '.eslintrc.json', - '.prettierrc.json', - ]; - - const placeholderPatterns = [/TODO/i, /FIXME/i, /PLACEHOLDER/i, /CHANGEME/i]; - - for (const file of configFiles) { - const filePath = path.join(rootDir, file); - if (fs.existsSync(filePath)) { - const content = fs.readFileSync(filePath, 'utf-8'); - - for (const pattern of placeholderPatterns) { - if (pattern.test(content)) { - throw new Error( - `Configuration file ${file} contains placeholder content matching ${pattern}` - ); - } - } - } - } - - return true; - }), - { numRuns: 100 } - ); - }); -}); diff --git a/tsconfig.json b/tsconfig.json index e8592df..26d1f7b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,12 @@ "compilerOptions": { "outDir": "./dist", "rootDir": ".", - "types": ["vitest/globals", "node"] + "types": ["vitest/globals", "node"], + "paths": { + "@testing-library/react-native": [ + "./node_modules/@testing-library/react-native/build/index.d.ts" + ] + } }, "include": [ "tests/**/*", @@ -11,5 +16,6 @@ "packages/protocol/src/**/*", "packages/relay-server/src/**/*", "packages/vscode-extension/src/**/*" - ] + ], + "exclude": ["node_modules/@testing-library/react-native/src"] } diff --git a/vitest.config.ts b/vitest.config.ts index 00f4bd0..ed73f66 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,17 +1,89 @@ import { defineConfig } from 'vitest/config'; import path from 'path'; +/** + * Root Vitest configuration + * Combines Node.js and React Native test environments + */ export default defineConfig({ test: { - globals: true, - // Use jsdom for mobile-client tests, node for everything else environment: 'node', - environmentMatchGlobs: [ - ['packages/mobile-client/**', 'jsdom'], + include: [ + 'tests/unit/protocol/**/*.test.ts', + 'tests/unit/relay-server/**/*.test.ts', + 'tests/unit/vscode-extension/**/*.test.ts', + 'tests/unit/mobile-client/**/*.test.tsx', + 'tests/unit/mobile-client/**/*.test.ts', + 'tests/integration/**/*.test.ts', + 'tests/property/**/*.test.ts', + 'tests/performance/**/*.test.ts' ], - alias: { - vscode: path.resolve(__dirname, './test-mocks/vscode.ts'), + exclude: [ + 'tests/unit/mobile-client/components.test.tsx' + ], + setupFiles: ['./tests/setup/test-setup.ts', './tests/setup/react-native-testing-setup.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'html', 'json', 'lcov'], + include: [ + 'packages/protocol/src/**/*.ts', + 'packages/relay-server/src/**/*.ts', + 'packages/vscode-extension/src/**/*.ts', + 'packages/mobile-client/src/**/*.ts', + 'packages/mobile-client/src/**/*.tsx' + ], + exclude: [ + 'tests/**', + '**/*.test.ts', + '**/*.test.tsx', + '**/dist/**', + '**/node_modules/**', + '**/*.config.js', + '**/*.config.ts' + ], + thresholds: { + lines: 80, + functions: 80, + branches: 80, + statements: 80 + } }, - setupFiles: ['./packages/mobile-client/src/test-setup.ts'], + globals: true, + testTimeout: 10000, + // Disable source map resolution to prevent loading TypeScript sources + sourcemap: false, + // Use jsdom for React Native component tests + environmentMatchGlobs: [ + ['tests/unit/mobile-client/**', 'jsdom'] + ], + // Transform node_modules that need transpilation + server: { + deps: { + inline: [ + 'react-native', + '@testing-library/react-native', + ] + } + } }, + resolve: { + // Use array form so we can include regex-based aliases for deep imports + alias: [ + { find: '@codelink/protocol', replacement: path.resolve(__dirname, './packages/protocol/src') }, + // Alias react-native to our mock for testing + { find: 'react-native', replacement: path.resolve(__dirname, './tests/setup/react-native-mock.ts') }, + { find: 'react-native/', replacement: path.resolve(__dirname, './packages/mobile-client/node_modules/react-native/') }, + // Resolve React from root node_modules (monorepo setup) + { find: 'react', replacement: path.resolve(__dirname, './node_modules/react') }, + { find: 'react-dom', replacement: path.resolve(__dirname, './node_modules/react-dom') }, + // Explicitly resolve @testing-library/react-native from root node_modules + { find: '@testing-library/react-native', replacement: path.resolve(__dirname, './node_modules/@testing-library/react-native/build/index.js') }, + // Ensure deep imports like @testing-library/react-native/src/... map to the compiled build/ equivalents + { find: /^@testing-library\/react-native\/src\/(.*)/, replacement: path.resolve(__dirname, './node_modules/@testing-library/react-native/build/') + '$1' }, + // Fallback mapping for other deep imports under the package root + { find: '@testing-library/react-native/', replacement: path.resolve(__dirname, './node_modules/@testing-library/react-native/build/') } + ], + conditions: ['import', 'module', 'browser', 'default'], + extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'] + } });