diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 176e6a5..0000000 --- a/.claude/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "enabledPlugins": { - "expo@claude-plugins-official": true - } -} diff --git a/.eas/workflows/build-android.yml b/.eas/workflows/build-android.yml deleted file mode 100644 index a958a84..0000000 --- a/.eas/workflows/build-android.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Build Android APK - -on: - workflow_dispatch: - inputs: - profile: - type: choice - description: EAS build profile to use. - default: production - options: - - preview - - production - -jobs: - build_android: - name: Build Android APK - type: build - environment: ${{ inputs.profile }} - params: - platform: android - profile: ${{ inputs.profile }} - message: Android ${{ inputs.profile }} APK from ${{ github.ref_name }} diff --git a/.eas/workflows/publish-updates.yml b/.eas/workflows/publish-updates.yml deleted file mode 100644 index 5f807f4..0000000 --- a/.eas/workflows/publish-updates.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Publish OTA updates - -on: - push: - branches: ['main'] - paths: - - 'app/**' - - 'components/**' - - 'hooks/**' - - 'lib/**' - - 'types/**' - - 'assets/**' - - 'App.tsx' - - 'index.ts' - - 'global.css' - - 'tailwind.config.js' - - 'babel.config.js' - - 'metro.config.js' - workflow_dispatch: - inputs: - channel: - type: choice - description: Update channel to publish. - default: production - options: - - preview - - production - environment: - type: choice - description: EAS environment to use for the update job. - default: production - options: - - preview - - production - message: - description: Optional update message override. - required: false - -jobs: - publish_main: - if: ${{ github.event_name == 'push' }} - name: Publish production update - type: update - environment: production - params: - channel: production - platform: all - - publish_manual: - if: ${{ github.event_name == 'workflow_dispatch' }} - name: Publish selected update - type: update - environment: ${{ inputs.environment }} - params: - channel: ${{ inputs.channel }} - message: ${{ inputs.message }} - platform: all diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..12287c6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto +*.gradle text eol=lf +*.kt text eol=lf +*.kts text eol=lf +*.properties text eol=lf +*.xml text eol=lf +*.yml text eol=lf +*.md text eol=lf +gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/.gitea/workflows/build-android.yml b/.gitea/workflows/build-android.yml index 1dcbccf..316dcb6 100644 --- a/.gitea/workflows/build-android.yml +++ b/.gitea/workflows/build-android.yml @@ -1,29 +1,21 @@ -name: CodexBar Mobile Build +name: android-release on: push: branches: - main - paths: - - "**/*.ts" - - "**/*.tsx" - - "**/*.js" - - "**/*.json" - - ".gitea/workflows/**" + tags: + - 'v*' + workflow_dispatch: jobs: - build-android: + build: runs-on: ubuntu-latest steps: - - name: 🏗 Setup repo - uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v4 - - name: 🏗 Setup Node - uses: actions/setup-node@v2 - with: - node-version: 22 - - - name: 🏗 Setup Java + - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: temurin @@ -46,62 +38,48 @@ jobs: - name: Set up Gradle cache uses: gradle/actions/setup-gradle@v3 - - name: 🏗 Setup Expo and EAS - uses: expo/expo-github-action@v8 - with: - token: ${{ secrets.EXPO_TOKEN }} - eas-version: latest - packager: npm - - - name: 📦 Install dependencies - run: npm ci --legacy-peer-deps - - - name: 👷 Build app + - name: Write release keystore + env: + CODEXMOBILE_KEYSTORE_BASE64: ${{ secrets.CODEXMOBILE_KEYSTORE_BASE64 }} + CODEXMOBILE_KEYSTORE_PASSWORD: ${{ secrets.CODEXMOBILE_KEYSTORE_PASSWORD }} + CODEXMOBILE_KEY_ALIAS: ${{ secrets.CODEXMOBILE_KEY_ALIAS }} + CODEXMOBILE_KEY_PASSWORD: ${{ secrets.CODEXMOBILE_KEY_PASSWORD }} run: | - eas build --local \ - --non-interactive \ - --output=./app-build \ - --platform=android \ - --profile=preview + if [ -z "$CODEXMOBILE_KEYSTORE_BASE64" ] || [ -z "$CODEXMOBILE_KEYSTORE_PASSWORD" ] || [ -z "$CODEXMOBILE_KEY_ALIAS" ] || [ -z "$CODEXMOBILE_KEY_PASSWORD" ]; then + echo "Missing release signing secrets" >&2 + exit 1 + fi + echo "$CODEXMOBILE_KEYSTORE_BASE64" | base64 -d > "$HOME/codexmobile-release.jks" + { + echo "CODEXMOBILE_STORE_FILE=$HOME/codexmobile-release.jks" + echo "CODEXMOBILE_STORE_PASSWORD=$CODEXMOBILE_KEYSTORE_PASSWORD" + echo "CODEXMOBILE_KEY_ALIAS=$CODEXMOBILE_KEY_ALIAS" + echo "CODEXMOBILE_KEY_PASSWORD=$CODEXMOBILE_KEY_PASSWORD" + } >> "$GITHUB_ENV" - - name: 📝 Rename build to APK - run: mv app-build codexbar-release.apk - - - name: 🗜 Zip APK - run: zip codexbar-release.zip codexbar-release.apk - - - name: 📤 Upload build artifact - uses: actions/upload-artifact@v3 - with: - name: codexbar-android-preview-build - path: codexbar-release.zip - if-no-files-found: error - - release: - runs-on: ubuntu-latest - needs: [build-android] - steps: - - name: 🏗 Setup repo - uses: actions/checkout@v2 - - - name: 📥 Download Android artifact - uses: actions/download-artifact@v3 - with: - name: codexbar-android-preview-build - - - name: 🏷 Create tag + - name: Build release APK run: | - TAG="codexbar-build-$(git rev-parse --short HEAD)" - git tag "$TAG" - git push origin "$TAG" - echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV + chmod +x gradlew + ./gradlew assembleRelease - - name: 🚀 Create release - uses: softprops/action-gh-release@v1 + - name: Compute release tag + run: | + if [[ "${GITHUB_REF}" == refs/tags/* ]]; then + echo "RELEASE_TAG=${GITHUB_REF_NAME}" >> "$GITHUB_ENV" + else + echo "RELEASE_TAG=main-${GITHUB_RUN_NUMBER}-${GITHUB_SHA::7}" >> "$GITHUB_ENV" + fi + + - name: Publish Gitea release + uses: akkuman/gitea-release-action@v1 + env: + NODE_OPTIONS: --experimental-fetch with: tag_name: ${{ env.RELEASE_TAG }} - name: ${{ env.RELEASE_TAG }} - files: codexbar-release.zip - generate_release_notes: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + target_commitish: ${{ github.sha }} + files: | + app/build/outputs/apk/release/*.apk + body: | + CodexMobile release built from ${{ github.ref_name }} at ${{ github.sha }}. + prerelease: false + draft: false diff --git a/.gitignore b/.gitignore index d914c32..e697753 100644 --- a/.gitignore +++ b/.gitignore @@ -1,41 +1,16 @@ -# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files - -# dependencies -node_modules/ - -# Expo -.expo/ -dist/ -web-build/ -expo-env.d.ts - -# Native +.gradle/ +build/ +app/build/ +local.properties +keystore.properties .kotlin/ -*.orig.* *.jks +*.keystore *.p8 *.p12 *.key -*.mobileprovision - -# Metro -.metro-health-check* - -# debug -npm-debug.* -yarn-debug.* -yarn-error.* - -# macOS -.DS_Store *.pem - -# local env files +*.orig.* +.env.ci .env*.local - -# typescript -*.tsbuildinfo - -# generated native folders -/ios -/android +.DS_Store diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index a26b4bb..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,3 +0,0 @@ -# Expo HAS CHANGED - -Read the exact versioned docs at https://docs.expo.dev/versions/v56.0.0/ before writing any code. diff --git a/App.tsx b/App.tsx deleted file mode 100644 index 0329d0c..0000000 --- a/App.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { StatusBar } from 'expo-status-bar'; -import { StyleSheet, Text, View } from 'react-native'; - -export default function App() { - return ( - - Open up App.tsx to start working on your app! - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#fff', - alignItems: 'center', - justifyContent: 'center', - }, -}); diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 078aeeb..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,70 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -@AGENTS.md - -## Commands - -```bash -npx expo start # Start Expo dev server (scan QR with Expo Go) -npx expo start --android -npx expo start --ios -npx expo start --web - -eas build --profile preview --platform android # Build APK via EAS -eas build --profile production --platform android -``` - -There is no test suite or lint script configured in package.json. - -## Architecture - -This is an Expo SDK 56 app that monitors AI service usage limits for **Codex CLI** and **Claude.ai**. It fetches usage data from their private REST APIs using credentials the user provides. - -### Navigation (Expo Router v3) - -``` -app/index.tsx → checks onboarding state, redirects -app/onboarding/ → stack: welcome → codex → claude → done -app/(tabs)/ - _layout.tsx → bottom tab navigator (4 tabs) - index.tsx → Dashboard: both services side-by-side - codex.tsx → Codex CLI detailed view - claude.tsx → Claude.ai detailed view (not yet in git) - settings.tsx → Settings (not yet in git) -``` - -### Data Flow - -Each service follows the same pattern: - -1. **Hook** (`hooks/useCodexUsage.ts`, `hooks/useClaudeUsage.ts`) — manages auth + usage state, persists credentials to SecureStore, exposes `refresh()` / `clear()`. -2. **API module** (`lib/api/codexApi.ts`, `lib/api/claudeApi.ts`) — thin fetch wrappers with no side effects. -3. **Screen** — calls the hook, renders `ServiceStatusCard` or the detailed usage UI. - -### Credential Storage - -All credentials live in `expo-secure-store` (never AsyncStorage). Keys: - -- `codex_auth` — serialized `CodexAuth` object (Bearer token + optional account ID), imported from the user's `auth.json` file via `expo-document-picker`. -- `claude_session_key` — cookie value used as `Cookie: sessionKey=…` on claude.ai API calls. - -`TOKEN_EXPIRED` errors automatically clear the stored credential and prompt re-entry. - -### Styling - -NativeWind v4 (Tailwind CSS for React Native). Brand colors: -- Codex: `#10a37f` (teal) -- Claude: `#d97706` (amber) - -Use Tailwind utility classes on all components. Dark mode is supported via `dark:` variants. - -### Key Types - -- `lib/types/codex.ts` — `CodexAuth`, `CodexUsageResponse`, `UsageWindow` -- `lib/types/claude.ts` — `ClaudeOrg`, `ClaudeUsageResponse`, `ClaudeWindowUsage` - -### Path Alias - -`@/` maps to the repo root (configured in `tsconfig.json`). Use `@/components/...`, `@/lib/...`, `@/hooks/...` everywhere. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c473d3f --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# CodexMobile + +Native Android app for monitoring Codex CLI and Claude.ai usage windows, reset credits, and local quota reminders. + +## Build + +```bash +./gradlew assembleDebug +``` + +Release builds require signing values from environment variables or `keystore.properties`: + +```properties +CODEXMOBILE_STORE_FILE=/path/to/codexmobile-release.jks +CODEXMOBILE_STORE_PASSWORD=... +CODEXMOBILE_KEY_ALIAS=codexmobile-release +CODEXMOBILE_KEY_PASSWORD=... +``` + +CI secrets are generated into `.env.ci` for copying into Gitea. diff --git a/app.json b/app.json deleted file mode 100644 index 205c738..0000000 --- a/app.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "expo": { - "name": "Codexbar", - "slug": "codexbar-mobile", - "description": "Monitor Codex CLI and Claude.ai usage limits, resets, and credits at a glance.", - "scheme": "codexbar", - "version": "1.0.0", - "runtimeVersion": { - "policy": "appVersion" - }, - "updates": { - "url": "https://u.expo.dev/9196c5ee-4c6e-4229-9a99-54b50afe38e8" - }, - "orientation": "portrait", - "icon": "./assets/icon.png", - "backgroundColor": "#090D11", - "primaryColor": "#10A37F", - "userInterfaceStyle": "automatic", - "ios": { - "bundleIdentifier": "dev.reversed.codexbar", - "buildNumber": "1", - "supportsTablet": true, - "config": { - "usesNonExemptEncryption": false - } - }, - "android": { - "package": "dev.reversed.codexbar", - "versionCode": 1, - "adaptiveIcon": { - "backgroundColor": "#090D11", - "foregroundImage": "./assets/android-icon-foreground.png", - "backgroundImage": "./assets/android-icon-background.png", - "monochromeImage": "./assets/android-icon-monochrome.png" - }, - "predictiveBackGestureEnabled": true - }, - "web": { - "bundler": "metro", - "output": "static", - "favicon": "./assets/favicon.png" - }, - "plugins": [ - "expo-router", - [ - "expo-splash-screen", - { - "image": "./assets/splash-icon.png", - "imageWidth": 220, - "resizeMode": "contain", - "backgroundColor": "#090D11", - "dark": { - "image": "./assets/splash-icon.png", - "backgroundColor": "#090D11" - } - } - ], - [ - "expo-secure-store", - { - "configureAndroidBackup": true, - "faceIDPermission": "Allow Codexbar to access your securely stored credentials." - } - ], - "expo-document-picker", - [ - "expo-notifications", - { - "icon": "./assets/notification-icon.png", - "color": "#10A37F", - "defaultChannel": "usage-alerts" - } - ], - "expo-font" - ], - "experiments": { - "typedRoutes": true - }, - "extra": { - "router": {}, - "eas": { - "projectId": "9196c5ee-4c6e-4229-9a99-54b50afe38e8" - } - }, - "owner": "spacebanane" - } -} diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx deleted file mode 100644 index 8da326f..0000000 --- a/app/(tabs)/_layout.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Tabs } from "expo-router"; -import { useColorScheme } from "react-native"; -import { useSafeAreaInsets } from "react-native-safe-area-context"; -import { MaterialIcons } from "@expo/vector-icons"; -import { COLORS } from "@/lib/constants"; - -export default function TabLayout() { - const colorScheme = useColorScheme(); - const isDark = colorScheme === "dark"; - const insets = useSafeAreaInsets(); - - return ( - - ( - - ), - }} - /> - - - ( - - ), - }} - /> - - ); -} diff --git a/app/(tabs)/claude.tsx b/app/(tabs)/claude.tsx deleted file mode 100644 index 5ffb790..0000000 --- a/app/(tabs)/claude.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { - ScrollView, - View, - Text, - TouchableOpacity, - TextInput, - ActivityIndicator, - RefreshControl, - KeyboardAvoidingView, - Platform, -} from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { MaterialIcons } from "@expo/vector-icons"; -import { useClaudeUsage } from "@/hooks/useClaudeUsage"; -import { UsageStat } from "@/components/UsageStat"; -import { ErrorMessage } from "@/components/ErrorMessage"; -import { LastUpdated } from "@/components/LastUpdated"; -import { ScreenErrorBoundary } from "@/components/ScreenErrorBoundary"; -import { COLORS } from "@/lib/constants"; - -function ClaudeTabContent() { - const { - auth, - pendingKey, - setPendingKey, - pendingOrg, - setPendingOrg, - usage, - lastFetchedAt, - status, - error, - keyValidationError, - canSaveKey, - saveKey, - refresh, - clearKey, - } = useClaudeUsage(); - - return ( - - - - } - > - {/* Header */} - - - - - - - Claude.ai - - - Usage windows - - - - - {/* Configuration card */} - - - Configuration - - - {auth ? ( - - - - - Connected - - - {auth.sessionKey.slice(0, 10)}… - - - - - Clear - - - - ) : ( - - - {keyValidationError && ( - - {keyValidationError} - - )} - - - - Save Session Key - - - - - Where to find it - - - Chrome DevTools → Application → Cookies → claude.ai → copy{" "} - sessionKey - {" "}and optionally{" "} - lastActiveOrg - - - - )} - - - {/* Usage card */} - - - Usage - - - {status === "idle" && !auth && ( - - - - Enter your session key to see usage windows - - - )} - {status === "loading" && !usage && ( - - )} - {status === "error" && error && } - {usage && ( - - - - - {(usage.seven_day_sonnet || usage.seven_day_opus) && ( - - - By Model (7-day) - - {usage.seven_day_sonnet && ( - - )} - {usage.seven_day_opus && ( - - )} - - )} - - - - - )} - - - - - ); -} - -export default function ClaudeTab() { - return ( - - - - ); -} diff --git a/app/(tabs)/codex.tsx b/app/(tabs)/codex.tsx deleted file mode 100644 index 4f505a6..0000000 --- a/app/(tabs)/codex.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import { - ScrollView, - View, - Text, - TouchableOpacity, - ActivityIndicator, - RefreshControl, -} from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { MaterialIcons } from "@expo/vector-icons"; -import { useCodexUsage } from "@/hooks/useCodexUsage"; -import { UsageStat } from "@/components/UsageStat"; -import { ErrorMessage } from "@/components/ErrorMessage"; -import { LastUpdated } from "@/components/LastUpdated"; -import { ScreenErrorBoundary } from "@/components/ScreenErrorBoundary"; -import { COLORS } from "@/lib/constants"; -import { windowLabel } from "@/lib/timeUtils"; -import type { CodexResetCredit } from "@/types/codex"; - -function formatResetStatus(status?: string) { - if (!status) return "Unknown"; - return status.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase()); -} - -function ResetCreditRow({ credit }: { credit: CodexResetCredit }) { - return ( - - - - Credit {credit.index} - - - - {formatResetStatus(credit.status)} - - - - {credit.timeUntilExpiry && ( - - Expires in {credit.timeUntilExpiry} - - )} - {credit.expiresAtLocal && ( - - Expires {credit.expiresAtLocal} - - )} - {credit.grantedAtLocal && ( - - Granted {credit.grantedAtLocal} - - )} - - ); -} - -function CodexTabContent() { - const { - auth, - usage, - lastFetchedAt, - status, - error, - importAuthFile, - refresh, - clearAuth, - } = - useCodexUsage(); - const resetCoupons = usage?.resetCoupons; - const availableResetCredits = - resetCoupons?.credits?.filter((credit) => credit.status === "available") ?? []; - - return ( - - - } - > - {/* Header */} - - - - - - - Codex CLI - - - Rate limits & credits - - - - - {/* Configuration card */} - - - Configuration - - - {auth ? ( - - - - - Connected - - {auth.accountId && ( - - {auth.accountId.slice(0, 10)}… - - )} - - - - Clear - - - - ) : ( - - - - - Import auth.json - - - - Located at ~/.codex/auth.json - - - )} - - - {/* Usage card */} - - - Usage - - - {status === "idle" && !auth && ( - - - - Import auth.json to see your rate limits - - - )} - {status === "loading" && !usage && ( - - )} - {status === "error" && error && } - {usage && ( - - {/* Plan badge */} - - - - {usage.planType ?? "codex"} - - - - - {usage.primary && ( - - )} - {usage.secondary && ( - - )} - - {/* Credits */} - - - Credits - - {usage.credits.unlimited ? ( - - - - Unlimited - - - ) : usage.credits.hasCredits ? ( - - ${Number(usage.credits.balance).toFixed(2)} remaining - - ) : ( - No credits - )} - - - {resetCoupons && ( - - - Reset Credits - - - {resetCoupons.availableCount ?? 0} available - - {typeof resetCoupons.totalEarnedCount === "number" && ( - - {resetCoupons.totalEarnedCount} earned total - - )} - {resetCoupons.nextExpiringCredit?.expiresAtLocal && ( - - Next expires {resetCoupons.nextExpiringCredit.expiresAtLocal} - - )} - {resetCoupons.nextExpiringCredit?.timeUntilExpiry && ( - - In {resetCoupons.nextExpiringCredit.timeUntilExpiry} - - )} - {availableResetCredits.length > 0 && ( - - - Available Now - - {availableResetCredits.map((credit) => ( - - ))} - - )} - {resetCoupons.source !== "live_api" && ( - - Source: {resetCoupons.sourceDescription} - - )} - - )} - - - - - )} - - - - ); -} - -export default function CodexTab() { - return ( - - - - ); -} diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx deleted file mode 100644 index a29d099..0000000 --- a/app/(tabs)/index.tsx +++ /dev/null @@ -1,338 +0,0 @@ -import { - ScrollView, - View, - Text, - TouchableOpacity, - RefreshControl, - ActivityIndicator, -} from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { router, useFocusEffect } from "expo-router"; -import { useCallback, useEffect } from "react"; -import { MaterialIcons } from "@expo/vector-icons"; -import { useCodexUsage } from "@/hooks/useCodexUsage"; -import { useClaudeUsage } from "@/hooks/useClaudeUsage"; -import { onUsageDataLoaded } from "@/lib/notifications"; -import { ProgressBar } from "@/components/ProgressBar"; -import { ResetCountdown } from "@/components/ResetCountdown"; -import { LastUpdated } from "@/components/LastUpdated"; -import { ErrorMessage } from "@/components/ErrorMessage"; -import { ScreenErrorBoundary } from "@/components/ScreenErrorBoundary"; -import { COLORS, getUsageColor } from "@/lib/constants"; -import { windowLabel } from "@/lib/timeUtils"; - -function UsageRow({ - label, - percent, - resetAtSeconds, - resetAtISO, -}: { - label: string; - percent: number; - resetAtSeconds?: number; - resetAtISO?: string; -}) { - const color = getUsageColor(percent); - return ( - - - - {label} - - - {Math.round(percent)}% used - - - - - - ); -} - -function SetupPrompt({ label }: { label: string }) { - return ( - - - {label} - - router.navigate("/(tabs)/settings")} - className="flex-row items-center self-start gap-x-1.5 px-3 py-2 rounded-xl border border-neutral-200 dark:border-neutral-700" - > - - Set up in Settings - - - - - ); -} - -function DashboardTabContent() { - const codex = useCodexUsage(); - const claude = useClaudeUsage(); - - // Fire daily digest reschedule + threshold check whenever fresh data arrives - useEffect(() => { - if (codex.usage || claude.usage) { - void onUsageDataLoaded( - claude.usage, - codex.usage - ); - } - }, [codex.lastFetchedAt, claude.lastFetchedAt]); - - useFocusEffect( - useCallback(() => { - void codex.reloadCredentials(); - void claude.reloadCredentials(); - }, [codex.reloadCredentials, claude.reloadCredentials]) - ); - - const isRefreshing = - codex.status === "loading" || claude.status === "loading"; - - const handleRefresh = () => { - void codex.refresh(); - void claude.refresh(); - }; - - const connectedCount = [codex.auth, claude.auth].filter(Boolean).length; - - return ( - - - } - > - {/* Header */} - - - - - - - - Codexbar - - - {connectedCount === 0 - ? "No services connected" - : connectedCount === 2 - ? "2 services connected" - : "1 of 2 services connected"} - - - - - - - - - {/* Codex card */} - - - - - - - - - - Codex CLI - - - - {codex.usage?.planType && ( - - - {codex.usage.planType} - - - )} - {codex.auth && codex.status === "error" && ( - - )} - {codex.status === "success" && !codex.usage?.planType && ( - - )} - - - - {!codex.auth && ( - - )} - {codex.auth && codex.status === "loading" && !codex.usage && ( - - )} - {codex.auth && codex.status === "error" && ( - - )} - {codex.usage && ( - - {codex.usage.primary && ( - - )} - {codex.usage.secondary && ( - - )} - {!codex.usage.credits.unlimited && - codex.usage.credits.hasCredits && ( - - - - ${Number(codex.usage.credits.balance).toFixed(2)}{" "} - credits remaining - - - )} - {codex.usage.credits.unlimited && ( - - - - Unlimited credits - - - )} - - {!!codex.usage.resetCoupons && ( - - - - - {codex.usage.resetCoupons.availableCount ?? 0} reset credits - available - - - {!!codex.usage.resetCoupons.nextExpiringCredit?.timeUntilExpiry && ( - - Next expires in {codex.usage.resetCoupons.nextExpiringCredit.timeUntilExpiry} - - )} - - )} - - - - )} - - - - {/* Claude card */} - - - - - - - - - - Claude.ai - - - {claude.auth && claude.status === "error" && ( - - )} - {claude.status === "success" && ( - - )} - - - {!claude.auth && ( - - )} - {claude.auth && claude.status === "loading" && !claude.usage && ( - - )} - {claude.auth && claude.status === "error" && ( - - )} - {claude.usage && ( - - - - {(claude.usage.seven_day_sonnet || - claude.usage.seven_day_opus) && ( - - - By Model (7-day) - - {claude.usage.seven_day_sonnet && ( - - )} - {claude.usage.seven_day_opus && ( - - )} - - )} - - - - - )} - - - - - ); -} - -export default function DashboardTab() { - return ( - - - - ); -} diff --git a/app/(tabs)/settings.tsx b/app/(tabs)/settings.tsx deleted file mode 100644 index f3fc121..0000000 --- a/app/(tabs)/settings.tsx +++ /dev/null @@ -1,580 +0,0 @@ -import { useEffect, useState, useCallback } from "react"; -import { - View, - Text, - TouchableOpacity, - Alert, - ScrollView, - TextInput, - Switch, - KeyboardAvoidingView, -} from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { router, useFocusEffect } from "expo-router"; -import { MaterialIcons } from "@expo/vector-icons"; -import { - loadCodexAuth, - clearCodexAuth, - saveCodexAuth, - loadClaudeSessionKey, - clearClaudeSessionKey, - saveClaudeSessionKey, - saveClaudeLastActiveOrg, - clearClaudeLastActiveOrg, -} from "@/lib/storage"; -import { pickAndReadCodexAuth } from "@/lib/fileReader"; -import { resetOnboarding } from "@/lib/setupState"; -import { useNotificationSettings } from "@/hooks/useNotificationSettings"; -import { - isClaudeSessionKeyValid, - validateClaudeSessionKey, -} from "@/lib/claudeCredentials"; -import { COLORS } from "@/lib/constants"; -import { formatTime, parseTimeInput } from "@/lib/timeUtils"; -import { ScreenErrorBoundary } from "@/components/ScreenErrorBoundary"; -import type { CodexAuth } from "@/types/codex"; -import Constants from "expo-constants"; - -function humanizeImportError(code: string): string { - if (code === "DOCUMENT_NOT_READABLE") { - return "The selected file could not be read. Try copying auth.json into Files or Downloads and import it again."; - } - return code; -} -function SettingRow({ - icon, - label, - value, - onPress, - destructive, - disabled, -}: { - icon: React.ComponentProps["name"]; - label: string; - value?: string; - onPress?: () => void; - destructive?: boolean; - disabled?: boolean; -}) { - return ( - - - - - - - {label} - - {value && ( - - {value} - - )} - - {onPress && !disabled && ( - - )} - - ); -} - -function SectionHeader({ title }: { title: string }) { - return ( - - {title} - - ); -} - -function SectionCard({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} - -function Divider() { - return ; -} - -function SettingsTabContent() { - const [codexAuth, setCodexAuth] = useState(null); - const [claudeKey, setClaudeKey] = useState(null); - const [pendingKey, setPendingKey] = useState(""); - const [pendingOrg, setPendingOrg] = useState(""); - const [claudeError, setClaudeError] = useState(null); - - const notif = useNotificationSettings(); - const [timeInput, setTimeInput] = useState(""); - const [timeError, setTimeError] = useState(null); - const [thresholdInput, setThresholdInput] = useState(""); - - // Sync local text inputs when settings load - useEffect(() => { - if (notif.loaded) { - setTimeInput(formatTime(notif.settings.dailyHour, notif.settings.dailyMinute)); - setThresholdInput(String(notif.settings.thresholdPct)); - } - }, [notif.loaded]); - - const reload = useCallback(() => { - Promise.all([loadCodexAuth(), loadClaudeSessionKey()]).then( - ([codex, claude]) => { - setCodexAuth(codex); - setClaudeKey(claude); - } - ); - }, []); - - useEffect(() => { - reload(); - }, [reload]); - - useFocusEffect( - useCallback(() => { - reload(); - }, [reload]) - ); - - const handleImportCodex = async () => { - try { - const auth = await pickAndReadCodexAuth(); - await saveCodexAuth(auth); - setCodexAuth(auth); - } catch (e: unknown) { - const msg = e instanceof Error ? e.message : "UNKNOWN_ERROR"; - if (msg !== "PICKER_CANCELLED") { - Alert.alert("Import failed", humanizeImportError(msg)); - } - } - }; - - const handleSaveClaude = async () => { - const trimmed = pendingKey.trim(); - const validationError = validateClaudeSessionKey(trimmed); - if (validationError) { - setClaudeError(validationError); - return; - } - const orgTrimmed = pendingOrg.trim() || undefined; - await saveClaudeSessionKey(trimmed); - if (orgTrimmed) await saveClaudeLastActiveOrg(orgTrimmed); - else await clearClaudeLastActiveOrg(); - setClaudeKey(trimmed); - setPendingKey(""); - setPendingOrg(""); - setClaudeError(null); - }; - - const handleClearCodex = () => { - Alert.alert( - "Clear Codex credentials", - "This will remove your stored auth.json data. You can re-import it anytime.", - [ - { text: "Cancel", style: "cancel" }, - { - text: "Clear", - style: "destructive", - onPress: async () => { - await clearCodexAuth(); - setCodexAuth(null); - }, - }, - ] - ); - }; - - const handleClearClaude = () => { - Alert.alert( - "Clear Claude session key", - "Your session key will be removed. You can re-enter it anytime.", - [ - { text: "Cancel", style: "cancel" }, - { - text: "Clear", - style: "destructive", - onPress: async () => { - await clearClaudeSessionKey(); - setClaudeKey(null); - }, - }, - ] - ); - }; - - const handleResetSetup = () => { - Alert.alert( - "Re-run Setup Wizard", - "This will clear all credentials and restart the setup flow.", - [ - { text: "Cancel", style: "cancel" }, - { - text: "Reset & Re-run", - style: "destructive", - onPress: async () => { - await Promise.all([ - clearCodexAuth(), - clearClaudeSessionKey(), - resetOnboarding(), - ]); - router.replace("/onboarding"); - }, - }, - ] - ); - }; - - const handleTimeBlur = useCallback(() => { - const parsed = parseTimeInput(timeInput); - if (parsed) { - void notif.update({ dailyHour: parsed.hour, dailyMinute: parsed.minute }); - setTimeInput(formatTime(parsed.hour, parsed.minute)); - setTimeError(null); - } else { - setTimeError("Use HH:MM format, from 00:00 to 23:59."); - } - }, [timeInput, notif]); - - const handleThresholdBlur = useCallback(() => { - const n = parseInt(thresholdInput, 10); - if (!isNaN(n) && n >= 1 && n <= 99) { - void notif.update({ thresholdPct: n }); - } else { - setThresholdInput(String(notif.settings.thresholdPct)); - } - }, [thresholdInput, notif]); - - const canSaveClaude = isClaudeSessionKeyValid(pendingKey); - const inlineClaudeError = - claudeError ?? (pendingKey ? validateClaudeSessionKey(pendingKey) : null); - const appVersion = Constants.expoConfig?.version ?? "1.0.0"; - - return ( - - - - {/* Header */} - - - Settings - - - - {/* Codex CLI section */} - - - {codexAuth ? ( - <> - - - - - ) : ( - - )} - - - {/* Claude.ai section */} - - - {claudeKey ? ( - <> - - - - - ) : ( - - {inlineClaudeError && ( - - {inlineClaudeError} - - )} - { - setPendingKey(t); - setClaudeError(null); - }} - placeholder="sk-ant-… (required)" - placeholderTextColor="#a3a3a3" - autoCapitalize="none" - autoCorrect={false} - secureTextEntry - className="border border-neutral-200 dark:border-neutral-700 rounded-xl px-3 py-3 text-sm text-neutral-900 dark:text-white bg-neutral-50 dark:bg-neutral-800 mb-2" - /> - - - - Save Session Key - - - - Chrome DevTools → Application → Cookies → claude.ai →{" "} - sessionKey - - - )} - - - {/* Notifications section */} - - - {notif.permissionStatus !== "granted" ? ( - { - const granted = await notif.askPermissions(); - if (!granted && notif.permissionStatus === "denied") { - Alert.alert( - "Notifications blocked", - "Go to Settings → CodexBar → Notifications to enable them." - ); - } - }} - className="flex-row items-center gap-x-3 py-3.5 px-4" - > - - - - - - Enable notifications - - - {notif.permissionStatus === "denied" - ? "Blocked — open system Settings to allow" - : "Required to receive alerts"} - - - {notif.permissionStatus !== "denied" && ( - - - Allow - - - )} - - ) : ( - <> - {/* Daily digest */} - - - - - - - Daily digest - - - Daily reminder with last-known usage - - - void notif.update({ dailyEnabled: v })} - trackColor={{ false: COLORS.disabled, true: COLORS.codex }} - thumbColor="white" - /> - - - {notif.settings.dailyEnabled && ( - <> - - - - - - - - Time - - { - setTimeInput(value); - setTimeError(null); - }} - onBlur={handleTimeBlur} - placeholder="09:00" - placeholderTextColor={COLORS.muted} - keyboardType="numbers-and-punctuation" - returnKeyType="done" - maxLength={5} - className="text-sm font-mono text-neutral-600 dark:text-neutral-300 text-right" - style={{ minWidth: 52 }} - /> - - {timeError && ( - - {timeError} - - )} - - - )} - - - - {/* Threshold alert */} - - - - - - - Low quota alert - - - Alert when weekly quota runs low - - - void notif.update({ thresholdEnabled: v })} - trackColor={{ false: COLORS.disabled, true: COLORS.claude }} - thumbColor="white" - /> - - - {notif.settings.thresholdEnabled && ( - <> - - - - - - - Alert below - - - - - % remaining - - - - - )} - - )} - - - {/* App section */} - - - - - - - - - - ); -} - -export default function SettingsTab() { - return ( - - - - ); -} diff --git a/app/_layout.tsx b/app/_layout.tsx deleted file mode 100644 index 109c5e4..0000000 --- a/app/_layout.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import "../global.css"; -import { Stack } from "expo-router"; -import { SafeAreaProvider } from "react-native-safe-area-context"; -import { StatusBar } from "expo-status-bar"; -import "@/lib/notifications"; // registers setNotificationHandler on app start - -export default function RootLayout() { - return ( - - - - - ); -} diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..4c2288d --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,140 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +def getVersionCode = { + def stdout = new ByteArrayOutputStream() + try { + exec { + commandLine 'git', 'rev-list', '--count', 'HEAD' + standardOutput = stdout + errorOutput = new ByteArrayOutputStream() + ignoreExitValue = true + } + def count = stdout.toString().trim() + return count.isInteger() ? count.toInteger() : 1 + } catch (ignored) { + return 1 + } +} + +def signingPropertiesFile = rootProject.file('keystore.properties') +def signingProperties = new Properties() +if (signingPropertiesFile.exists()) { + signingPropertiesFile.withInputStream(signingProperties.&load) +} + +def readSigningValue = { String... keys -> + keys.collect { key -> System.getenv(key) ?: signingProperties.getProperty(key) } + .find { value -> value != null && !value.trim().isEmpty() } +} + +def releaseKeystorePath = readSigningValue('CODEXMOBILE_STORE_FILE', 'CODEXMOBILE_KEYSTORE_FILE') +def releaseKeystorePassword = readSigningValue('CODEXMOBILE_STORE_PASSWORD', 'CODEXMOBILE_KEYSTORE_PASSWORD') +def releaseKeyAlias = readSigningValue('CODEXMOBILE_KEY_ALIAS') +def releaseKeyPassword = readSigningValue('CODEXMOBILE_KEY_PASSWORD') +def hasReleaseSigning = [releaseKeystorePath, releaseKeystorePassword, releaseKeyAlias, releaseKeyPassword].every { it } +def releaseSigningHelp = '''Release signing is not configured. + +Provide these values either as environment variables or in keystore.properties: +- CODEXMOBILE_STORE_FILE or CODEXMOBILE_KEYSTORE_FILE +- CODEXMOBILE_STORE_PASSWORD or CODEXMOBILE_KEYSTORE_PASSWORD +- CODEXMOBILE_KEY_ALIAS +- CODEXMOBILE_KEY_PASSWORD +''' + +android { + namespace 'dev.reversed.codexbarmobile' + compileSdk 34 + + signingConfigs { + if (hasReleaseSigning) { + release { + storeFile rootProject.file(releaseKeystorePath) + storePassword releaseKeystorePassword + keyAlias releaseKeyAlias + keyPassword releaseKeyPassword + } + } + } + + defaultConfig { + applicationId 'dev.reversed.codexbarmobile' + minSdk 26 + targetSdk 34 + versionCode getVersionCode() + versionName '1.0.0' + vectorDrawables.useSupportLibrary = true + } + + buildTypes { + debug { + applicationIdSuffix '.debug' + versionNameSuffix '-debug' + } + release { + if (hasReleaseSigning) { + signingConfig signingConfigs.release + } + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = '17' + } + + buildFeatures { + compose true + } + + composeOptions { + kotlinCompilerExtensionVersion '1.5.14' + } + + packaging { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } +} + +gradle.taskGraph.whenReady { graph -> + def needsSignedRelease = graph.allTasks.any { task -> + task.project == project && + task.name.toLowerCase().contains('release') && + !task.name.toLowerCase().contains('lint') && + !task.name.toLowerCase().contains('unittest') && + !task.name.toLowerCase().contains('signingreport') + } + + if (needsSignedRelease && !hasReleaseSigning) { + throw new GradleException(releaseSigningHelp) + } +} + +dependencies { + implementation 'androidx.core:core-ktx:1.13.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.4' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4' + implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4' + implementation 'androidx.activity:activity-compose:1.9.2' + implementation platform('androidx.compose:compose-bom:2024.06.00') + implementation 'androidx.compose.ui:ui' + implementation 'androidx.compose.ui:ui-tooling-preview' + implementation 'androidx.compose.material3:material3' + implementation 'androidx.compose.material:material-icons-extended' + implementation 'androidx.security:security-crypto:1.1.0-alpha06' + implementation 'com.google.errorprone:error_prone_annotations:2.28.0' + implementation 'com.squareup.okhttp3:okhttp:4.12.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1' + debugImplementation 'androidx.compose.ui:ui-tooling' +} diff --git a/app/index.tsx b/app/index.tsx deleted file mode 100644 index 9d8b5e9..0000000 --- a/app/index.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useEffect } from "react"; -import { View, ActivityIndicator } from "react-native"; -import { router } from "expo-router"; -import { hasCompletedOnboarding } from "@/lib/setupState"; -import { COLORS } from "@/lib/constants"; - -export default function Index() { - useEffect(() => { - hasCompletedOnboarding().then((done) => { - router.replace(done ? "/(tabs)" : "/onboarding"); - }); - }, []); - - return ( - - - - ); -} diff --git a/app/onboarding/_layout.tsx b/app/onboarding/_layout.tsx deleted file mode 100644 index e30c6af..0000000 --- a/app/onboarding/_layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Stack } from "expo-router"; - -export default function OnboardingLayout() { - return ( - - ); -} diff --git a/app/onboarding/claude.tsx b/app/onboarding/claude.tsx deleted file mode 100644 index 4eaabb3..0000000 --- a/app/onboarding/claude.tsx +++ /dev/null @@ -1,236 +0,0 @@ -import { useState, useCallback, useEffect } from "react"; -import { - View, - Text, - TouchableOpacity, - TextInput, - KeyboardAvoidingView, - ScrollView, -} from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { router } from "expo-router"; -import { MaterialIcons } from "@expo/vector-icons"; -import { - saveClaudeSessionKey, - saveClaudeLastActiveOrg, - clearClaudeLastActiveOrg, - loadClaudeSessionKey, - loadClaudeLastActiveOrg, -} from "@/lib/storage"; -import { - isClaudeSessionKeyValid, - validateClaudeSessionKey, -} from "@/lib/claudeCredentials"; -import { COLORS } from "@/lib/constants"; - -export default function OnboardingClaudeScreen() { - const [savedKey, setSavedKey] = useState(null); - const [savedOrg, setSavedOrg] = useState(null); - const [pendingKey, setPendingKey] = useState(""); - const [pendingOrg, setPendingOrg] = useState(""); - const [error, setError] = useState(null); - - useEffect(() => { - Promise.all([loadClaudeSessionKey(), loadClaudeLastActiveOrg()]).then( - ([k, o]) => { - if (k) setSavedKey(k); - if (o) setSavedOrg(o); - } - ); - }, []); - - const canSave = isClaudeSessionKeyValid(pendingKey); - const inlineError = - error ?? (pendingKey ? validateClaudeSessionKey(pendingKey) : null); - - const handleSave = useCallback(async () => { - const trimmed = pendingKey.trim(); - const validationError = validateClaudeSessionKey(trimmed); - if (validationError) { - setError(validationError); - return; - } - const orgTrimmed = pendingOrg.trim() || undefined; - await saveClaudeSessionKey(trimmed); - if (orgTrimmed) await saveClaudeLastActiveOrg(orgTrimmed); - else await clearClaudeLastActiveOrg(); - setSavedKey(trimmed); - setSavedOrg(orgTrimmed ?? null); - setPendingKey(""); - setPendingOrg(""); - setError(null); - }, [pendingKey, pendingOrg]); - - return ( - - - - - {/* Top: back + step indicator */} - - router.back()} - className="w-9 h-9 rounded-xl bg-neutral-900 items-center justify-center" - > - - - - - - - - - 2 - - - - - - {/* Content */} - - - - - - Connect Claude.ai - - - Enter your session key to monitor your Claude.ai usage windows. - - - {savedKey ? ( - - - - - - - Connected - - {savedKey.slice(0, 16)}… - - - { - setSavedKey(null); - setSavedOrg(null); - setPendingKey(""); - setPendingOrg(""); - }} - > - Change - - - {savedOrg && ( - - - org: {savedOrg.slice(0, 8)}… - - - )} - - ) : ( - - {inlineError && ( - - {inlineError} - - )} - { - setPendingKey(t); - setError(null); - }} - placeholder="sk-ant-… (required)" - placeholderTextColor="#525252" - autoCapitalize="none" - autoCorrect={false} - secureTextEntry - className="border border-neutral-800 rounded-xl px-4 py-3.5 text-sm text-white bg-neutral-900 mb-3" - /> - - - - Save Session Key - - - - - How to find your credentials - - - Open Claude.ai in Chrome → DevTools (F12) → Application → Cookies → claude.ai{"\n"} - Copy sessionKey and optionally lastActiveOrg - - - - )} - - - {/* Bottom actions */} - - router.push("/onboarding/done")} - className="rounded-2xl py-4 items-center" - style={{ - backgroundColor: savedKey ? COLORS.claude : "#1a1a1a", - }} - > - - Continue - - - router.push("/onboarding/done")} - className="py-3 items-center" - > - Skip for now - - - - - - - ); -} diff --git a/app/onboarding/codex.tsx b/app/onboarding/codex.tsx deleted file mode 100644 index 6c3f50a..0000000 --- a/app/onboarding/codex.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { useState, useCallback, useEffect } from "react"; -import { View, Text, TouchableOpacity, ActivityIndicator } from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { router } from "expo-router"; -import { MaterialIcons } from "@expo/vector-icons"; -import { pickAndReadCodexAuth } from "@/lib/fileReader"; -import { saveCodexAuth, loadCodexAuth } from "@/lib/storage"; -import type { CodexAuth } from "@/types/codex"; -import { COLORS } from "@/lib/constants"; - -function humanizeImportError(code: string): string { - if (code === "DOCUMENT_NOT_READABLE") { - return "The selected file could not be read. Try copying auth.json into Files or Downloads and import it again."; - } - return code; -} - -export default function OnboardingCodexScreen() { - const [auth, setAuth] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - useEffect(() => { - loadCodexAuth().then((stored) => { - if (stored) setAuth(stored); - }); - }, []); - - const importFile = useCallback(async () => { - setLoading(true); - setError(null); - try { - const parsed = await pickAndReadCodexAuth(); - await saveCodexAuth(parsed); - setAuth(parsed); - } catch (e: unknown) { - const msg = e instanceof Error ? e.message : "UNKNOWN_ERROR"; - if (msg !== "PICKER_CANCELLED") setError(humanizeImportError(msg)); - } finally { - setLoading(false); - } - }, []); - - return ( - - - {/* Top: back + step indicator */} - - router.back()} - className="w-9 h-9 rounded-xl bg-neutral-900 items-center justify-center" - > - - - - - 1 - - - - 2 - - - - - - {/* Content */} - - - - - - Connect Codex CLI - - - Import your{" "} - - ~/.codex/auth.json - {" "} - file to track your rate limits and credits. - - - {/* Status / action */} - {auth ? ( - - - - - - Imported - {auth.accountId && ( - - {auth.accountId.slice(0, 12)}… - - )} - - - Re-import - - - ) : ( - - {error && ( - - {error} - - )} - - {loading ? ( - - ) : ( - - - - Import auth.json - - - )} - - - Located at ~/.codex/auth.json on your Mac - - - )} - - - {/* Bottom actions */} - - router.push("/onboarding/claude")} - className="rounded-2xl py-4 items-center" - style={{ backgroundColor: auth ? COLORS.codex : "#1a1a1a" }} - > - - Continue - - - router.push("/onboarding/claude")} - className="py-3 items-center" - > - Skip for now - - - - - ); -} diff --git a/app/onboarding/done.tsx b/app/onboarding/done.tsx deleted file mode 100644 index f3dee71..0000000 --- a/app/onboarding/done.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { useEffect, useState } from "react"; -import { View, Text, TouchableOpacity } from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { router } from "expo-router"; -import { MaterialIcons } from "@expo/vector-icons"; -import { markOnboardingComplete } from "@/lib/setupState"; -import { loadCodexAuth, loadClaudeSessionKey } from "@/lib/storage"; -import { COLORS } from "@/lib/constants"; - -export default function OnboardingDoneScreen() { - const [codexConfigured, setCodexConfigured] = useState(false); - const [claudeConfigured, setClaudeConfigured] = useState(false); - - useEffect(() => { - Promise.all([loadCodexAuth(), loadClaudeSessionKey()]).then( - ([codex, claude]) => { - setCodexConfigured(!!codex); - setClaudeConfigured(!!claude); - } - ); - }, []); - - const handleEnterApp = async () => { - await markOnboardingComplete(); - router.replace("/(tabs)"); - }; - - const noneConfigured = !codexConfigured && !claudeConfigured; - - return ( - - - {/* Icon */} - - - - - {/* Title */} - - {noneConfigured ? "Almost there" : "You're all set!"} - - - {noneConfigured - ? "No services configured yet. You can set them up anytime in Settings." - : "Your services are connected and ready to monitor."} - - - {/* Summary cards */} - - - - - - - - Codex CLI - - - {codexConfigured ? "Auth imported" : "Not configured"} - - - - - - - - - - - Claude.ai - - - {claudeConfigured ? "Session saved" : "Not configured"} - - - - - - {/* CTA */} - - Open App - - - - ); -} diff --git a/app/onboarding/index.tsx b/app/onboarding/index.tsx deleted file mode 100644 index 462dd4d..0000000 --- a/app/onboarding/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { View, Text, TouchableOpacity } from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; -import { router } from "expo-router"; -import { MaterialIcons } from "@expo/vector-icons"; -import { COLORS } from "@/lib/constants"; - -export default function WelcomeScreen() { - return ( - - - {/* Logo + title */} - - - - - - - - - - - Codexbar - - - Monitor your Codex CLI and Claude.ai{"\n"}usage limits at a glance. - - - - {/* Feature pills */} - - - - - - - Codex CLI - - Rate limits · Credits · Windows - - - - - - - - - Claude.ai - - 5-hour · 7-day · Model usage - - - - - - {/* CTA */} - - router.push("/onboarding/codex")} - className="rounded-2xl py-4 items-center" - style={{ backgroundColor: COLORS.codex }} - > - Get Started - - - You can configure services at any time in Settings - - - - - ); -} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..2908a65 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,2 @@ +-dontwarn okhttp3.** +-dontwarn okio.** diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1707225 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/java/dev/reversed/codexbarmobile/AppStorage.kt b/app/src/main/java/dev/reversed/codexbarmobile/AppStorage.kt new file mode 100644 index 0000000..ec4d40b --- /dev/null +++ b/app/src/main/java/dev/reversed/codexbarmobile/AppStorage.kt @@ -0,0 +1,282 @@ +package dev.reversed.codexbarmobile + +import android.content.Context +import android.content.SharedPreferences +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey +import org.json.JSONArray +import org.json.JSONObject + +class AppStorage(context: Context) { + private val prefs: SharedPreferences + + init { + val masterKey = MasterKey.Builder(context) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + prefs = EncryptedSharedPreferences.create( + context, + "codexmobile_secure", + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, + ) + } + + fun hasCompletedOnboarding(): Boolean = prefs.getBoolean(KEY_ONBOARDING_DONE, false) + + fun markOnboardingComplete() { + prefs.edit().putBoolean(KEY_ONBOARDING_DONE, true).apply() + } + + fun resetOnboarding() { + prefs.edit().remove(KEY_ONBOARDING_DONE).apply() + } + + fun saveCodexAuth(auth: CodexAuth) { + prefs.edit().putString(KEY_CODEX_AUTH, JSONObject().apply { + put("accessToken", auth.accessToken) + putNullable("accountId", auth.accountId) + }.toString()).apply() + } + + fun loadCodexAuth(): CodexAuth? = prefs.getString(KEY_CODEX_AUTH, null)?.let { raw -> + runCatching { + val json = JSONObject(raw) + CodexAuth( + accessToken = json.getString("accessToken"), + accountId = json.optStringOrNull("accountId"), + ) + }.getOrNull() + } + + fun clearCodexAuth() { + prefs.edit().remove(KEY_CODEX_AUTH).remove(KEY_CODEX_USAGE_CACHE).apply() + } + + fun saveClaudeAuth(auth: ClaudeAuth) { + prefs.edit().putString(KEY_CLAUDE_AUTH, JSONObject().apply { + put("sessionKey", auth.sessionKey) + putNullable("lastActiveOrg", auth.lastActiveOrg) + }.toString()).apply() + } + + fun loadClaudeAuth(): ClaudeAuth? = prefs.getString(KEY_CLAUDE_AUTH, null)?.let { raw -> + runCatching { + val json = JSONObject(raw) + ClaudeAuth( + sessionKey = json.getString("sessionKey"), + lastActiveOrg = json.optStringOrNull("lastActiveOrg"), + ) + }.getOrNull() + } + + fun clearClaudeAuth() { + prefs.edit().remove(KEY_CLAUDE_AUTH).remove(KEY_CLAUDE_USAGE_CACHE).apply() + } + + fun saveCodexUsageCache(cache: UsageCache) { + prefs.edit().putString(KEY_CODEX_USAGE_CACHE, JSONObject().apply { + put("lastFetchedAt", cache.lastFetchedAt) + put("data", cache.data.toJson()) + }.toString()).apply() + } + + fun loadCodexUsageCache(): UsageCache? = prefs.getString(KEY_CODEX_USAGE_CACHE, null)?.let { raw -> + runCatching { + val json = JSONObject(raw) + UsageCache( + data = json.getJSONObject("data").toCodexUsage(), + lastFetchedAt = json.getLong("lastFetchedAt"), + ) + }.getOrNull() + } + + fun saveClaudeUsageCache(cache: UsageCache) { + prefs.edit().putString(KEY_CLAUDE_USAGE_CACHE, JSONObject().apply { + put("lastFetchedAt", cache.lastFetchedAt) + put("data", cache.data.toJson()) + }.toString()).apply() + } + + fun loadClaudeUsageCache(): UsageCache? = prefs.getString(KEY_CLAUDE_USAGE_CACHE, null)?.let { raw -> + runCatching { + val json = JSONObject(raw) + UsageCache( + data = json.getJSONObject("data").toClaudeUsage(), + lastFetchedAt = json.getLong("lastFetchedAt"), + ) + }.getOrNull() + } + + fun loadNotificationSettings(): NotificationSettings = NotificationSettings( + dailyEnabled = prefs.getBoolean(KEY_DAILY_ENABLED, false), + dailyHour = prefs.getInt(KEY_DAILY_HOUR, 9), + dailyMinute = prefs.getInt(KEY_DAILY_MINUTE, 0), + thresholdEnabled = prefs.getBoolean(KEY_THRESHOLD_ENABLED, false), + thresholdPct = prefs.getInt(KEY_THRESHOLD_PCT, 20), + ) + + fun saveNotificationSettings(settings: NotificationSettings) { + prefs.edit() + .putBoolean(KEY_DAILY_ENABLED, settings.dailyEnabled) + .putInt(KEY_DAILY_HOUR, settings.dailyHour) + .putInt(KEY_DAILY_MINUTE, settings.dailyMinute) + .putBoolean(KEY_THRESHOLD_ENABLED, settings.thresholdEnabled) + .putInt(KEY_THRESHOLD_PCT, settings.thresholdPct) + .apply() + } + + fun loadThresholdLastFired(): String? = prefs.getString(KEY_THRESHOLD_LAST_FIRED, null) + + fun saveThresholdLastFired(date: String) { + prefs.edit().putString(KEY_THRESHOLD_LAST_FIRED, date).apply() + } + + companion object { + private const val KEY_ONBOARDING_DONE = "codexmobile_onboarding_v1" + private const val KEY_CODEX_AUTH = "codexmobile_codex_auth" + private const val KEY_CLAUDE_AUTH = "codexmobile_claude_auth" + private const val KEY_CODEX_USAGE_CACHE = "codexmobile_codex_usage_cache" + private const val KEY_CLAUDE_USAGE_CACHE = "codexmobile_claude_usage_cache" + private const val KEY_DAILY_ENABLED = "codexmobile_daily_enabled" + private const val KEY_DAILY_HOUR = "codexmobile_daily_hour" + private const val KEY_DAILY_MINUTE = "codexmobile_daily_minute" + private const val KEY_THRESHOLD_ENABLED = "codexmobile_threshold_enabled" + private const val KEY_THRESHOLD_PCT = "codexmobile_threshold_pct" + private const val KEY_THRESHOLD_LAST_FIRED = "codexmobile_threshold_last_fired" + + fun parseCodexAuthJson(text: String): CodexAuth { + val json = JSONObject(text) + val tokens = json.optJSONObject("tokens") + val accessToken = tokens?.optStringOrNull("access_token") + ?: json.optStringOrNull("accessToken") + ?: throw IllegalArgumentException("MISSING_ACCESS_TOKEN") + val accountId = tokens?.optStringOrNull("account_id") + ?: json.optStringOrNull("accountId") + ?: json.optStringOrNull("account_id") + return CodexAuth(accessToken = accessToken, accountId = accountId) + } + } +} + +fun JSONObject.optStringOrNull(name: String): String? = if (has(name) && !isNull(name)) { + optString(name).takeIf { it.isNotBlank() } +} else null + +fun JSONObject.optDoubleOrNull(name: String): Double? = if (has(name) && !isNull(name)) optDouble(name) else null + +fun JSONObject.optLongOrNull(name: String): Long? = if (has(name) && !isNull(name)) optLong(name) else null + +fun JSONObject.optIntOrNull(name: String): Int? = if (has(name) && !isNull(name)) optInt(name) else null + +fun JSONObject.putNullable(name: String, value: Any?) { + if (value == null) put(name, JSONObject.NULL) else put(name, value) +} + +fun UsageWindow.toJson(): JSONObject = JSONObject().apply { + put("usedPercent", usedPercent) + putNullable("resetsAt", resetsAt) + putNullable("resetsAtIso", resetsAtIso) + putNullable("windowSeconds", windowSeconds) +} + +fun JSONObject.toUsageWindow(): UsageWindow = UsageWindow( + usedPercent = getDouble("usedPercent"), + resetsAt = optLongOrNull("resetsAt"), + resetsAtIso = optStringOrNull("resetsAtIso"), + windowSeconds = optLongOrNull("windowSeconds"), +) + +fun CodexUsage.toJson(): JSONObject = JSONObject().apply { + putNullable("planType", planType) + putNullable("rateLimitReachedType", rateLimitReachedType) + putNullable("primary", primary?.toJson()) + putNullable("secondary", secondary?.toJson()) + put("credits", JSONObject().apply { + put("hasCredits", credits.hasCredits) + put("unlimited", credits.unlimited) + put("balance", credits.balance) + }) + putNullable("resetCoupons", resetCoupons?.toJson()) +} + +fun JSONObject.toCodexUsage(): CodexUsage { + val creditsJson = getJSONObject("credits") + return CodexUsage( + planType = optStringOrNull("planType"), + rateLimitReachedType = optStringOrNull("rateLimitReachedType"), + primary = optJSONObject("primary")?.toUsageWindow(), + secondary = optJSONObject("secondary")?.toUsageWindow(), + credits = CodexCredits( + hasCredits = creditsJson.optBoolean("hasCredits"), + unlimited = creditsJson.optBoolean("unlimited"), + balance = creditsJson.optDouble("balance", 0.0), + ), + resetCoupons = optJSONObject("resetCoupons")?.toResetCoupons(), + ) +} + +fun ResetCoupons.toJson(): JSONObject = JSONObject().apply { + put("source", source) + put("sourceDescription", sourceDescription) + putNullable("availableCount", availableCount) + putNullable("totalEarnedCount", totalEarnedCount) + put("credits", JSONArray().also { arr -> credits.forEach { arr.put(it.toJson()) } }) + putNullable("nextExpiringCredit", nextExpiringCredit?.toJson()) + putNullable("error", error) +} + +fun ResetCredit.toJson(): JSONObject = JSONObject().apply { + put("index", index) + putNullable("status", status) + putNullable("grantedAt", grantedAt) + putNullable("expiresAt", expiresAt) + putNullable("timeUntilExpiry", timeUntilExpiry) +} + +fun JSONObject.toResetCoupons(): ResetCoupons { + val arr = optJSONArray("credits") ?: JSONArray() + val credits = (0 until arr.length()).mapNotNull { arr.optJSONObject(it)?.toResetCredit() } + return ResetCoupons( + source = optString("source", "unavailable"), + sourceDescription = optString("sourceDescription", "Reset-credit endpoint unavailable"), + availableCount = optIntOrNull("availableCount"), + totalEarnedCount = optIntOrNull("totalEarnedCount"), + credits = credits, + nextExpiringCredit = optJSONObject("nextExpiringCredit")?.toResetCredit(), + error = optStringOrNull("error"), + ) +} + +fun JSONObject.toResetCredit(): ResetCredit = ResetCredit( + index = optInt("index"), + status = optStringOrNull("status"), + grantedAt = optStringOrNull("grantedAt"), + expiresAt = optStringOrNull("expiresAt"), + timeUntilExpiry = optStringOrNull("timeUntilExpiry"), +) + +fun ClaudeUsage.toJson(): JSONObject = JSONObject().apply { + put("fiveHour", fiveHour.toJson()) + put("sevenDay", sevenDay.toJson()) + putNullable("sevenDaySonnet", sevenDaySonnet?.toJson()) + putNullable("sevenDayOpus", sevenDayOpus?.toJson()) +} + +fun ClaudeWindowUsage.toJson(): JSONObject = JSONObject().apply { + put("utilization", utilization) + putNullable("resetsAt", resetsAt) +} + +fun JSONObject.toClaudeUsage(): ClaudeUsage = ClaudeUsage( + fiveHour = getJSONObject("fiveHour").toClaudeWindowUsage(), + sevenDay = getJSONObject("sevenDay").toClaudeWindowUsage(), + sevenDaySonnet = optJSONObject("sevenDaySonnet")?.toClaudeWindowUsage(), + sevenDayOpus = optJSONObject("sevenDayOpus")?.toClaudeWindowUsage(), +) + +fun JSONObject.toClaudeWindowUsage(): ClaudeWindowUsage = ClaudeWindowUsage( + utilization = getDouble("utilization"), + resetsAt = optStringOrNull("resetsAt"), +) diff --git a/app/src/main/java/dev/reversed/codexbarmobile/AppViewModel.kt b/app/src/main/java/dev/reversed/codexbarmobile/AppViewModel.kt new file mode 100644 index 0000000..ae4d636 --- /dev/null +++ b/app/src/main/java/dev/reversed/codexbarmobile/AppViewModel.kt @@ -0,0 +1,256 @@ +package dev.reversed.codexbarmobile + +import android.app.Application +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class AppViewModel(application: Application) : AndroidViewModel(application) { + private val storage = AppStorage(application) + private val api = UsageApi() + + var screen by androidx.compose.runtime.mutableStateOf(AppScreen.Splash) + private set + var tab by androidx.compose.runtime.mutableStateOf(MainTab.Dashboard) + private set + + var codexAuth by androidx.compose.runtime.mutableStateOf(null) + private set + var codexUsage by androidx.compose.runtime.mutableStateOf(null) + private set + var codexLastFetchedAt by androidx.compose.runtime.mutableStateOf(null) + private set + var codexStatus by androidx.compose.runtime.mutableStateOf(LoadStatus.Idle) + private set + var codexError by androidx.compose.runtime.mutableStateOf(null) + private set + + var claudeAuth by androidx.compose.runtime.mutableStateOf(null) + private set + var claudeUsage by androidx.compose.runtime.mutableStateOf(null) + private set + var claudeLastFetchedAt by androidx.compose.runtime.mutableStateOf(null) + private set + var claudeStatus by androidx.compose.runtime.mutableStateOf(LoadStatus.Idle) + private set + var claudeError by androidx.compose.runtime.mutableStateOf(null) + private set + + var notificationSettings by androidx.compose.runtime.mutableStateOf(NotificationSettings()) + private set + + init { + loadInitialState() + } + + fun selectTab(next: MainTab) { + tab = next + } + + fun goTo(next: AppScreen) { + screen = next + } + + fun openMain() { + storage.markOnboardingComplete() + screen = AppScreen.Main + } + + fun resetSetup() { + storage.clearCodexAuth() + storage.clearClaudeAuth() + storage.resetOnboarding() + codexAuth = null + codexUsage = null + codexLastFetchedAt = null + codexStatus = LoadStatus.Idle + codexError = null + claudeAuth = null + claudeUsage = null + claudeLastFetchedAt = null + claudeStatus = LoadStatus.Idle + claudeError = null + screen = AppScreen.Welcome + tab = MainTab.Dashboard + } + + fun importCodexAuthText(text: String) { + viewModelScope.launch { + runCatching { AppStorage.parseCodexAuthJson(text) } + .onSuccess { auth -> + storage.saveCodexAuth(auth) + codexAuth = auth + codexError = null + refreshCodex() + } + .onFailure { codexError = humanizeImportError(it.message ?: "INVALID_JSON") } + } + } + + fun saveClaude(sessionKey: String, lastActiveOrg: String?) { + val trimmed = sessionKey.trim() + val validationError = validateClaudeSessionKey(trimmed) + if (validationError != null) { + claudeError = validationError + return + } + val auth = ClaudeAuth(trimmed, lastActiveOrg?.trim()?.takeIf { it.isNotBlank() }) + storage.saveClaudeAuth(auth) + claudeAuth = auth + claudeError = null + refreshClaude() + } + + fun clearCodex() { + storage.clearCodexAuth() + codexAuth = null + codexUsage = null + codexLastFetchedAt = null + codexStatus = LoadStatus.Idle + codexError = null + } + + fun clearClaude() { + storage.clearClaudeAuth() + claudeAuth = null + claudeUsage = null + claudeLastFetchedAt = null + claudeStatus = LoadStatus.Idle + claudeError = null + } + + fun refreshAll() { + refreshCodex() + refreshClaude() + } + + fun refreshCodex() { + val auth = codexAuth ?: return + viewModelScope.launch { + codexStatus = LoadStatus.Loading + codexError = null + runCatchingWithRetry { api.fetchCodexUsage(auth) } + .onSuccess { usage -> + val fetchedAt = System.currentTimeMillis() + codexUsage = usage + codexLastFetchedAt = fetchedAt + codexStatus = LoadStatus.Success + storage.saveCodexUsageCache(UsageCache(usage, fetchedAt)) + syncNotifications() + } + .onFailure { error -> + if (error.message == "TOKEN_EXPIRED") clearCodex() + codexStatus = LoadStatus.Error + codexError = humanizeError(error) + } + } + } + + fun refreshClaude() { + val auth = claudeAuth ?: return + viewModelScope.launch { + claudeStatus = LoadStatus.Loading + claudeError = null + runCatchingWithRetry { api.fetchClaudeUsage(auth) } + .onSuccess { usage -> + val fetchedAt = System.currentTimeMillis() + claudeUsage = usage + claudeLastFetchedAt = fetchedAt + claudeStatus = LoadStatus.Success + storage.saveClaudeUsageCache(UsageCache(usage, fetchedAt)) + syncNotifications() + } + .onFailure { error -> + if (error.message == "TOKEN_EXPIRED") clearClaude() + claudeStatus = LoadStatus.Error + claudeError = humanizeError(error) + } + } + } + + fun updateNotificationSettings(settings: NotificationSettings) { + notificationSettings = settings + storage.saveNotificationSettings(settings) + syncNotifications() + } + + private fun loadInitialState() { + codexAuth = storage.loadCodexAuth() + claudeAuth = storage.loadClaudeAuth() + notificationSettings = storage.loadNotificationSettings() + storage.loadCodexUsageCache()?.let { + codexUsage = it.data + codexLastFetchedAt = it.lastFetchedAt + codexStatus = LoadStatus.Success + } + storage.loadClaudeUsageCache()?.let { + claudeUsage = it.data + claudeLastFetchedAt = it.lastFetchedAt + claudeStatus = LoadStatus.Success + } + screen = if (storage.hasCompletedOnboarding()) AppScreen.Main else AppScreen.Welcome + refreshAll() + } + + private fun syncNotifications() { + val context = getApplication() + if (notificationSettings.dailyEnabled) { + NotificationScheduler.scheduleDailyDigest( + context = context, + hour = notificationSettings.dailyHour, + minute = notificationSettings.dailyMinute, + body = buildDailyDigestBody(claudeUsage, codexUsage), + ) + } else { + NotificationScheduler.cancelDailyDigest(context) + } + maybeFireThresholdAlert(context, storage, notificationSettings, claudeUsage, codexUsage) + } + + private suspend fun runCatchingWithRetry(block: suspend () -> T): Result { + return runCatching { block() }.recoverCatching { first -> + if (!shouldRetry(first)) throw first + delay(RETRY_DELAY_MS) + block() + } + } + + private fun shouldRetry(error: Throwable): Boolean = when (error.message) { + "TOKEN_EXPIRED", "NO_ORGS_FOUND", "INVALID_CODEX_RESPONSE", "INVALID_CLAUDE_RESPONSE" -> false + else -> true + } + + private fun humanizeImportError(code: String): String = when (code) { + "MISSING_ACCESS_TOKEN" -> "That auth.json does not contain a Codex access token." + "INVALID_JSON" -> "That file is not valid JSON." + else -> "The selected file could not be read. Try another copy of auth.json." + } + + private fun humanizeError(error: Throwable): String = when (val message = error.message) { + "TOKEN_EXPIRED" -> "Credentials expired. Reconnect this service." + "NO_ORGS_FOUND" -> "No Claude organizations were found for this session." + null -> "Something went wrong. Pull to retry." + else -> if (message.startsWith("HTTP_ERROR_")) "Service request failed (${message.removePrefix("HTTP_ERROR_")}). Pull to retry." else message + } + + companion object { + private const val RETRY_DELAY_MS = 5_000L + } +} + +private val claudeSessionPattern = Regex("^sk-ant-[A-Za-z0-9_-]+$") + +fun validateClaudeSessionKey(value: String): String? { + val key = value.trim() + return when { + !key.startsWith("sk-ant-") -> "Session key must start with sk-ant-." + key.length <= 40 -> "Session key looks too short. Paste the complete cookie value." + !claudeSessionPattern.matches(key) -> "Session key contains unexpected characters." + else -> null + } +} + +fun isClaudeSessionKeyValid(value: String): Boolean = validateClaudeSessionKey(value) == null diff --git a/app/src/main/java/dev/reversed/codexbarmobile/MainActivity.kt b/app/src/main/java/dev/reversed/codexbarmobile/MainActivity.kt new file mode 100644 index 0000000..1225d99 --- /dev/null +++ b/app/src/main/java/dev/reversed/codexbarmobile/MainActivity.kt @@ -0,0 +1,855 @@ +package dev.reversed.codexbarmobile + +import android.Manifest +import android.net.Uri +import android.os.Build +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Alarm +import androidx.compose.material.icons.rounded.AutoAwesome +import androidx.compose.material.icons.rounded.BarChart +import androidx.compose.material.icons.rounded.CheckCircle +import androidx.compose.material.icons.rounded.DeleteOutline +import androidx.compose.material.icons.rounded.Home +import androidx.compose.material.icons.rounded.Info +import androidx.compose.material.icons.rounded.Notifications +import androidx.compose.material.icons.rounded.Psychology +import androidx.compose.material.icons.rounded.Refresh +import androidx.compose.material.icons.rounded.RestartAlt +import androidx.compose.material.icons.rounded.Settings +import androidx.compose.material.icons.rounded.UploadFile +import androidx.compose.material.icons.rounded.Warning +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.AssistChip +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import java.time.Instant +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import kotlin.math.roundToInt + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + CodexMobileTheme { + val vm: AppViewModel = viewModel() + CodexMobileApp(vm) + } + } + } +} + +@Composable +private fun CodexMobileApp(vm: AppViewModel) { + val context = LocalContext.current + val pickCodexAuth = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? -> + if (uri != null) { + val text = context.contentResolver.openInputStream(uri)?.bufferedReader()?.use { it.readText() } + if (text != null) vm.importCodexAuthText(text) + } + } + val requestNotifications = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) {} + + val pickAuth = { pickCodexAuth.launch(arrayOf("application/json", "text/*", "*/*")) } + val askNotifications = { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + requestNotifications.launch(Manifest.permission.POST_NOTIFICATIONS) + } + } + + when (vm.screen) { + AppScreen.Splash -> SplashScreen() + AppScreen.Welcome -> WelcomeScreen(vm) + AppScreen.OnboardingCodex -> OnboardingCodexScreen(vm, pickAuth) + AppScreen.OnboardingClaude -> OnboardingClaudeScreen(vm) + AppScreen.OnboardingDone -> OnboardingDoneScreen(vm) + AppScreen.Main -> MainScreen(vm, pickAuth, askNotifications) + } +} + +@Composable +private fun SplashScreen() { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + CircularProgressIndicator(color = CodexGreen) + } +} + +@Composable +private fun WelcomeScreen(vm: AppViewModel) { + OnboardingShell { + Spacer(Modifier.height(32.dp)) + AppMark(size = 72) + Spacer(Modifier.height(28.dp)) + Text("CodexMobile", style = MaterialTheme.typography.displaySmall, fontWeight = FontWeight.Black) + Text( + "Monitor Codex CLI and Claude.ai usage limits without a web stack.", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 12.dp), + ) + Spacer(Modifier.weight(1f)) + FeaturePill(Icons.Rounded.AutoAwesome, "Codex CLI", "Rate limits, credits, reset coupons", CodexGreen) + Spacer(Modifier.height(12.dp)) + FeaturePill(Icons.Rounded.Psychology, "Claude.ai", "5-hour, 7-day, and model windows", ClaudeAmber) + Spacer(Modifier.weight(1f)) + PrimaryButton("Get started", CodexGreen) { vm.goTo(AppScreen.OnboardingCodex) } + Text( + "You can configure services later in Settings.", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 12.dp), + ) + } +} + +@Composable +private fun OnboardingCodexScreen(vm: AppViewModel, pickAuth: () -> Unit) { + OnboardingShell { + StepHeader(1, 2) + Spacer(Modifier.height(36.dp)) + ServiceIcon(Icons.Rounded.AutoAwesome, CodexGreen) + Text("Connect Codex CLI", style = MaterialTheme.typography.headlineLarge, fontWeight = FontWeight.Bold) + Text( + "Import your ~/.codex/auth.json file to track rate limits, credits, and reset coupons.", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 12.dp), + ) + Spacer(Modifier.height(24.dp)) + vm.codexError?.let { ErrorCard(it) } + if (vm.codexAuth != null) { + ConnectedCard("Imported", vm.codexAuth?.accountId?.take(16), CodexGreen) + TextButton(onClick = pickAuth) { Text("Re-import auth.json") } + } else { + PrimaryButton("Import auth.json", CodexGreen, icon = Icons.Rounded.UploadFile, onClick = pickAuth) + Text("File picker accepts the Codex auth JSON export.", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + Spacer(Modifier.weight(1f)) + PrimaryButton("Continue", if (vm.codexAuth != null) CodexGreen else MutedButton) { vm.goTo(AppScreen.OnboardingClaude) } + TextButton(onClick = { vm.goTo(AppScreen.OnboardingClaude) }) { Text("Skip for now") } + } +} + +@Composable +private fun OnboardingClaudeScreen(vm: AppViewModel) { + var key by remember { mutableStateOf("") } + var org by remember { mutableStateOf("") } + val inlineError = if (key.isBlank()) null else validateClaudeSessionKey(key) + OnboardingShell { + StepHeader(2, 2) + Spacer(Modifier.height(36.dp)) + ServiceIcon(Icons.Rounded.Psychology, ClaudeAmber) + Text("Connect Claude.ai", style = MaterialTheme.typography.headlineLarge, fontWeight = FontWeight.Bold) + Text( + "Paste your sessionKey cookie and optionally lastActiveOrg to monitor Claude usage windows.", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 12.dp), + ) + Spacer(Modifier.height(24.dp)) + if (vm.claudeAuth != null) { + ConnectedCard("Connected", vm.claudeAuth?.sessionKey?.take(16), ClaudeAmber) + TextButton(onClick = { vm.clearClaude() }) { Text("Change session key") } + } else { + (vm.claudeError ?: inlineError)?.let { ErrorCard(it) } + OutlinedTextField( + value = key, + onValueChange = { key = it }, + label = { Text("sessionKey") }, + visualTransformation = PasswordVisualTransformation(), + singleLine = true, + modifier = Modifier.fillMaxWidth(), + ) + Spacer(Modifier.height(10.dp)) + OutlinedTextField( + value = org, + onValueChange = { org = it }, + label = { Text("lastActiveOrg (optional)") }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + ) + Spacer(Modifier.height(12.dp)) + PrimaryButton("Save session key", if (isClaudeSessionKeyValid(key)) ClaudeAmber else MutedButton) { + vm.saveClaude(key, org) + } + HelpCard("Find it in Chrome DevTools > Application > Cookies > claude.ai > sessionKey.") + } + Spacer(Modifier.weight(1f)) + PrimaryButton("Continue", if (vm.claudeAuth != null) ClaudeAmber else MutedButton) { vm.goTo(AppScreen.OnboardingDone) } + TextButton(onClick = { vm.goTo(AppScreen.OnboardingDone) }) { Text("Skip for now") } + } +} + +@Composable +private fun OnboardingDoneScreen(vm: AppViewModel) { + OnboardingShell(horizontalAlignment = Alignment.CenterHorizontally) { + Spacer(Modifier.weight(1f)) + ServiceIcon(if (vm.codexAuth != null || vm.claudeAuth != null) Icons.Rounded.CheckCircle else Icons.Rounded.Info, CodexGreen, 84) + Text( + if (vm.codexAuth == null && vm.claudeAuth == null) "Almost there" else "You're all set", + style = MaterialTheme.typography.headlineLarge, + fontWeight = FontWeight.Black, + ) + Text( + if (vm.codexAuth == null && vm.claudeAuth == null) "No services are configured yet. Settings can finish setup anytime." else "Your connected services are ready to monitor.", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 12.dp), + ) + Spacer(Modifier.height(28.dp)) + SummaryRow("Codex CLI", if (vm.codexAuth != null) "Auth imported" else "Not configured", vm.codexAuth != null, CodexGreen) + SummaryRow("Claude.ai", if (vm.claudeAuth != null) "Session saved" else "Not configured", vm.claudeAuth != null, ClaudeAmber) + Spacer(Modifier.weight(1f)) + PrimaryButton("Open app", CodexGreen) { vm.openMain() } + } +} + +@Composable +private fun MainScreen(vm: AppViewModel, pickAuth: () -> Unit, askNotifications: () -> Unit) { + Scaffold( + bottomBar = { + NavigationBar { + MainTab.entries.forEach { item -> + NavigationBarItem( + selected = vm.tab == item, + onClick = { vm.selectTab(item) }, + icon = { Icon(item.icon, null) }, + label = { Text(item.label) }, + ) + } + } + }, + ) { padding -> + Box(Modifier.padding(padding)) { + when (vm.tab) { + MainTab.Dashboard -> DashboardScreen(vm) + MainTab.Codex -> CodexScreen(vm, pickAuth) + MainTab.Claude -> ClaudeScreen(vm) + MainTab.Settings -> SettingsScreen(vm, pickAuth, askNotifications) + } + } + } +} + +@Composable +private fun DashboardScreen(vm: AppViewModel) { + ScreenColumn { + Header("CodexMobile", connectedSummary(vm), Icons.Rounded.BarChart, CodexGreen) { vm.refreshAll() } + ServiceCard("Codex CLI", Icons.Rounded.AutoAwesome, CodexGreen, vm.codexStatus, vm.codexError, vm.codexAuth != null) { + vm.codexUsage?.let { CodexUsageContent(it, vm.codexLastFetchedAt, compact = true) } + ?: EmptyState("Import auth.json in Settings to see Codex rate limits.") { vm.selectTab(MainTab.Settings) } + } + ServiceCard("Claude.ai", Icons.Rounded.Psychology, ClaudeAmber, vm.claudeStatus, vm.claudeError, vm.claudeAuth != null) { + vm.claudeUsage?.let { ClaudeUsageContent(it, vm.claudeLastFetchedAt) } + ?: EmptyState("Add a session key in Settings to see Claude usage.") { vm.selectTab(MainTab.Settings) } + } + } +} + +@Composable +private fun CodexScreen(vm: AppViewModel, pickAuth: () -> Unit) { + ScreenColumn { + Header("Codex CLI", "Rate limits and reset credits", Icons.Rounded.AutoAwesome, CodexGreen) { vm.refreshCodex() } + ConfigCard( + connected = vm.codexAuth != null, + label = vm.codexAuth?.accountId?.take(16), + color = CodexGreen, + connectLabel = "Import auth.json", + onConnect = pickAuth, + onClear = vm::clearCodex, + ) + vm.codexError?.let { ErrorCard(it) } + UsageSurface(vm.codexStatus) { + vm.codexUsage?.let { CodexUsageContent(it, vm.codexLastFetchedAt, compact = false) } + ?: EmptyState("Import Codex auth.json to load usage windows.") { pickAuth() } + } + } +} + +@Composable +private fun ClaudeScreen(vm: AppViewModel) { + var key by remember { mutableStateOf("") } + var org by remember { mutableStateOf("") } + ScreenColumn { + Header("Claude.ai", "Usage windows", Icons.Rounded.Psychology, ClaudeAmber) { vm.refreshClaude() } + if (vm.claudeAuth != null) { + ConfigCard( + connected = true, + label = vm.claudeAuth?.sessionKey?.take(16), + color = ClaudeAmber, + connectLabel = "Save session key", + onConnect = {}, + onClear = vm::clearClaude, + ) + } else { + ClaudeCredentialCard(key, org, vm.claudeError, onKey = { key = it }, onOrg = { org = it }) { vm.saveClaude(key, org) } + } + UsageSurface(vm.claudeStatus) { + vm.claudeUsage?.let { ClaudeUsageContent(it, vm.claudeLastFetchedAt) } + ?: EmptyState("Enter a Claude session key to load usage windows.") + } + } +} + +@Composable +private fun SettingsScreen(vm: AppViewModel, pickAuth: () -> Unit, askNotifications: () -> Unit) { + var key by remember { mutableStateOf("") } + var org by remember { mutableStateOf("") } + var showResetDialog by remember { mutableStateOf(false) } + val context = LocalContext.current + ScreenColumn { + Text("Settings", style = MaterialTheme.typography.headlineLarge, fontWeight = FontWeight.Black) + SectionTitle("Codex CLI") + ConfigCard(vm.codexAuth != null, vm.codexAuth?.accountId?.take(16), CodexGreen, "Import auth.json", pickAuth, vm::clearCodex) + SectionTitle("Claude.ai") + if (vm.claudeAuth != null) { + ConfigCard(true, vm.claudeAuth?.sessionKey?.take(16), ClaudeAmber, "Save session key", {}, vm::clearClaude) + } else { + ClaudeCredentialCard(key, org, vm.claudeError, onKey = { key = it }, onOrg = { org = it }) { vm.saveClaude(key, org) } + } + SectionTitle("Notifications") + SettingsCard { + val hasPermission = NotificationScheduler.hasNotificationPermission(context) + if (!hasPermission) { + RowItem(Icons.Rounded.Notifications, "Enable notifications", "Required for digests and quota alerts") { + OutlinedButton(onClick = askNotifications) { Text("Allow") } + } + HorizontalDivider() + } + SwitchRow("Daily digest", "Last-known usage at a chosen time", vm.notificationSettings.dailyEnabled) { + vm.updateNotificationSettings(vm.notificationSettings.copy(dailyEnabled = it)) + } + if (vm.notificationSettings.dailyEnabled) { + TimeSetting(vm.notificationSettings) { hour, minute -> + vm.updateNotificationSettings(vm.notificationSettings.copy(dailyHour = hour, dailyMinute = minute)) + } + } + HorizontalDivider() + SwitchRow("Low quota alert", "Warn when weekly quota runs low", vm.notificationSettings.thresholdEnabled) { + vm.updateNotificationSettings(vm.notificationSettings.copy(thresholdEnabled = it)) + } + if (vm.notificationSettings.thresholdEnabled) { + ThresholdSetting(vm.notificationSettings) { + vm.updateNotificationSettings(vm.notificationSettings.copy(thresholdPct = it)) + } + } + } + SectionTitle("App") + SettingsCard { + RowItem(Icons.Rounded.Info, "Version", "1.0.0") {} + HorizontalDivider() + RowItem(Icons.Rounded.RestartAlt, "Re-run setup wizard", "Clears credentials and onboarding", danger = true) { + TextButton(onClick = { showResetDialog = true }) { Text("Reset") } + } + } + } + if (showResetDialog) { + AlertDialog( + onDismissRequest = { showResetDialog = false }, + title = { Text("Reset setup?") }, + text = { Text("This clears stored credentials and restarts onboarding.") }, + confirmButton = { TextButton(onClick = { showResetDialog = false; vm.resetSetup() }) { Text("Reset") } }, + dismissButton = { TextButton(onClick = { showResetDialog = false }) { Text("Cancel") } }, + ) + } +} + +@Composable +private fun CodexUsageContent(usage: CodexUsage, lastFetchedAt: Long?, compact: Boolean) { + usage.planType?.let { AssistChip(onClick = {}, label = { Text(it.replaceFirstChar(Char::uppercase)) }) } + usage.primary?.let { UsageRow("${windowLabel(it.windowSeconds)} window", it, CodexGreen) } + usage.secondary?.let { UsageRow("${windowLabel(it.windowSeconds)} window", it, CodexGreen) } + CreditCard(usage) + if (!compact) ResetCreditsCard(usage.resetCoupons) + LastUpdated(lastFetchedAt) +} + +@Composable +private fun ClaudeUsageContent(usage: ClaudeUsage, lastFetchedAt: Long?) { + UsageRow("5-hour window", UsageWindow(usage.fiveHour.utilization, resetsAtIso = usage.fiveHour.resetsAt), ClaudeAmber) + UsageRow("7-day window", UsageWindow(usage.sevenDay.utilization, resetsAtIso = usage.sevenDay.resetsAt), ClaudeAmber) + if (usage.sevenDaySonnet != null || usage.sevenDayOpus != null) { + CardBlock { + Text("By model (7-day)", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant) + usage.sevenDaySonnet?.let { UsageRow("Sonnet", UsageWindow(it.utilization), ClaudeAmber) } + usage.sevenDayOpus?.let { UsageRow("Opus", UsageWindow(it.utilization), ClaudeAmber) } + } + } + LastUpdated(lastFetchedAt) +} + +@Composable +private fun UsageRow(label: String, window: UsageWindow, accent: Color) { + val percent = window.usedPercent.roundToInt().coerceIn(0, 100) + Column(Modifier.padding(vertical = 10.dp)) { + Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.Bottom) { + Text(label, style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text("$percent% used", style = MaterialTheme.typography.titleSmall, color = usageColor(percent, accent), fontWeight = FontWeight.Bold) + } + Spacer(Modifier.height(8.dp)) + LinearProgressIndicator( + progress = { percent / 100f }, + modifier = Modifier.fillMaxWidth().height(8.dp), + color = usageColor(percent, accent), + trackColor = MaterialTheme.colorScheme.surfaceVariant, + ) + resetText(window)?.let { Text(it, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 6.dp)) } + } +} + +@Composable +private fun CreditCard(usage: CodexUsage) { + CardBlock { + Text("Credits", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant) + val text = when { + usage.credits.unlimited -> "Unlimited credits" + usage.credits.hasCredits -> "\$${"%.2f".format(usage.credits.balance)} remaining" + else -> "No credits" + } + Text(text, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold) + usage.resetCoupons?.let { + Text("${it.availableCount ?: 0} reset credits available", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + it.nextExpiringCredit?.timeUntilExpiry?.let { expiry -> Text("Next expires in $expiry", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) } + } + } +} + +@Composable +private fun ResetCreditsCard(resetCoupons: ResetCoupons?) { + if (resetCoupons == null) return + CardBlock { + Text("Reset credits", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text("${resetCoupons.availableCount ?: 0} available", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold) + resetCoupons.totalEarnedCount?.let { Text("$it earned total", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) } + resetCoupons.credits.filter { it.status == "available" }.forEach { credit -> + Text("Credit ${credit.index}: expires ${credit.timeUntilExpiry ?: credit.expiresAt ?: "unknown"}", style = MaterialTheme.typography.bodySmall) + } + if (resetCoupons.source != "live_api") Text("Source: ${resetCoupons.sourceDescription}", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } +} + +@Composable +private fun ServiceCard(title: String, icon: ImageVector, color: Color, status: LoadStatus, error: String?, connected: Boolean, content: @Composable () -> Unit) { + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), shape = RoundedCornerShape(28.dp), modifier = Modifier.fillMaxWidth()) { + Column(Modifier.padding(18.dp)) { + Row(verticalAlignment = Alignment.CenterVertically) { + ServiceIcon(icon, color, 40) + Spacer(Modifier.width(12.dp)) + Text(title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f)) + StatusDot(status, connected) + } + Spacer(Modifier.height(12.dp)) + if (status == LoadStatus.Loading && !connected) CircularProgressIndicator(color = color) + if (status == LoadStatus.Error && error != null) ErrorCard(error) + content() + } + } +} + +@Composable +private fun UsageSurface(status: LoadStatus, content: @Composable () -> Unit) { + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), shape = RoundedCornerShape(28.dp), modifier = Modifier.fillMaxWidth()) { + Column(Modifier.padding(18.dp)) { + if (status == LoadStatus.Loading) { + Row(verticalAlignment = Alignment.CenterVertically) { + CircularProgressIndicator(Modifier.size(20.dp)) + Spacer(Modifier.width(10.dp)) + Text("Refreshing usage…", style = MaterialTheme.typography.bodyMedium) + } + Spacer(Modifier.height(12.dp)) + } + content() + } + } +} + +@Composable +private fun ConfigCard(connected: Boolean, label: String?, color: Color, connectLabel: String, onConnect: () -> Unit, onClear: () -> Unit) { + SettingsCard { + if (connected) { + RowItem(Icons.Rounded.CheckCircle, "Connected", label ?: "Credentials saved") { + TextButton(onClick = onClear) { Text("Clear", color = MaterialTheme.colorScheme.error) } + } + } else { + RowItem(Icons.Rounded.UploadFile, connectLabel, "Credentials stay encrypted on this device") { + Button(onClick = onConnect, colors = ButtonDefaults.buttonColors(containerColor = color)) { Text("Connect") } + } + } + } +} + +@Composable +private fun ClaudeCredentialCard(key: String, org: String, error: String?, onKey: (String) -> Unit, onOrg: (String) -> Unit, onSave: () -> Unit) { + SettingsCard { + Column(Modifier.padding(16.dp)) { + (error ?: if (key.isBlank()) null else validateClaudeSessionKey(key))?.let { ErrorCard(it) } + OutlinedTextField(key, onKey, Modifier.fillMaxWidth(), label = { Text("sessionKey") }, singleLine = true, visualTransformation = PasswordVisualTransformation()) + Spacer(Modifier.height(10.dp)) + OutlinedTextField(org, onOrg, Modifier.fillMaxWidth(), label = { Text("lastActiveOrg (optional)") }, singleLine = true) + Spacer(Modifier.height(12.dp)) + PrimaryButton("Save session key", if (isClaudeSessionKeyValid(key)) ClaudeAmber else MutedButton, onClick = onSave) + HelpCard("Chrome DevTools > Application > Cookies > claude.ai > sessionKey") + } + } +} + +@Composable +private fun ScreenColumn(content: @Composable ColumnScope.() -> Unit) { + Column( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(18.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + content = content, + ) +} + +@Composable +private fun OnboardingShell(horizontalAlignment: Alignment.Horizontal = Alignment.Start, content: @Composable ColumnScope.() -> Unit) { + Column( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(28.dp), + horizontalAlignment = horizontalAlignment, + content = content, + ) +} + +@Composable +private fun Header(title: String, subtitle: String, icon: ImageVector, color: Color, onRefresh: () -> Unit) { + Row(verticalAlignment = Alignment.CenterVertically) { + ServiceIcon(icon, color, 48) + Spacer(Modifier.width(14.dp)) + Column(Modifier.weight(1f)) { + Text(title, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Black) + Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + IconButton(onClick = onRefresh) { Icon(Icons.Rounded.Refresh, "Refresh") } + } +} + +@Composable +private fun PrimaryButton(text: String, color: Color, icon: ImageVector? = null, onClick: () -> Unit) { + Button(onClick = onClick, colors = ButtonDefaults.buttonColors(containerColor = color), shape = RoundedCornerShape(18.dp), modifier = Modifier.fillMaxWidth().height(54.dp)) { + if (icon != null) { Icon(icon, null); Spacer(Modifier.width(8.dp)) } + Text(text, fontWeight = FontWeight.Bold) + } +} + +@Composable +private fun ServiceIcon(icon: ImageVector, color: Color, size: Int = 56) { + Surface(shape = RoundedCornerShape((size / 3).dp), color = color.copy(alpha = 0.16f), modifier = Modifier.size(size.dp)) { + Box(contentAlignment = Alignment.Center) { Icon(icon, null, tint = color, modifier = Modifier.size((size / 2).dp)) } + } +} + +@Composable +private fun AppMark(size: Int) { + Row(horizontalArrangement = Arrangement.Center) { + ServiceIcon(Icons.Rounded.AutoAwesome, CodexGreen, size) + Spacer(Modifier.width(8.dp)) + ServiceIcon(Icons.Rounded.Psychology, ClaudeAmber, size) + } +} + +@Composable +private fun StepHeader(current: Int, total: Int) { + Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) { + (1..total).forEach { step -> + Surface( + shape = CircleShape, + color = if (step <= current) CodexGreen else MaterialTheme.colorScheme.surfaceVariant, + modifier = Modifier.size(28.dp), + ) { + Box(contentAlignment = Alignment.Center) { + Text( + step.toString(), + style = MaterialTheme.typography.labelMedium, + color = if (step <= current) Color.White else MaterialTheme.colorScheme.onSurfaceVariant, + fontWeight = FontWeight.Bold, + ) + } + } + if (step < total) { + Spacer(Modifier.width(8.dp)) + HorizontalDivider(Modifier.width(42.dp), color = if (step < current) CodexGreen else MaterialTheme.colorScheme.surfaceVariant) + Spacer(Modifier.width(8.dp)) + } + } + } +} + +@Composable +private fun FeaturePill(icon: ImageVector, title: String, subtitle: String, color: Color) { + SettingsCard { + Row(Modifier.padding(16.dp), verticalAlignment = Alignment.CenterVertically) { + ServiceIcon(icon, color, 42) + Spacer(Modifier.width(12.dp)) + Column { + Text(title, fontWeight = FontWeight.Bold) + Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + } + } +} + +@Composable +private fun ConnectedCard(title: String, label: String?, color: Color) { + SettingsCard { + Row(Modifier.padding(16.dp), verticalAlignment = Alignment.CenterVertically) { + Icon(Icons.Rounded.CheckCircle, null, tint = color) + Spacer(Modifier.width(12.dp)) + Column { + Text(title, fontWeight = FontWeight.Bold) + label?.let { Text("$it…", fontFamily = FontFamily.Monospace, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) } + } + } + } +} + +@Composable +private fun SummaryRow(title: String, subtitle: String, ok: Boolean, color: Color) { + SettingsCard { + Row(Modifier.padding(16.dp), verticalAlignment = Alignment.CenterVertically) { + Surface(shape = CircleShape, color = if (ok) color else MaterialTheme.colorScheme.surfaceVariant, modifier = Modifier.size(10.dp)) {} + Spacer(Modifier.width(12.dp)) + Column { Text(title, fontWeight = FontWeight.Bold); Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) } + } + } + Spacer(Modifier.height(10.dp)) +} + +@Composable +private fun ErrorCard(text: String) { + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.errorContainer), shape = RoundedCornerShape(18.dp), modifier = Modifier.fillMaxWidth()) { + Text(text, color = MaterialTheme.colorScheme.onErrorContainer, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.padding(14.dp)) + } +} + +@Composable +private fun HelpCard(text: String) { + Text(text, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 10.dp)) +} + +@Composable +private fun CardBlock(content: @Composable ColumnScope.() -> Unit) { + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.45f)), shape = RoundedCornerShape(20.dp), modifier = Modifier.fillMaxWidth().padding(top = 8.dp)) { + Column(Modifier.padding(14.dp), content = content) + } +} + +@Composable +private fun EmptyState(text: String, onAction: (() -> Unit)? = null) { + Column(Modifier.fillMaxWidth().padding(vertical = 18.dp), horizontalAlignment = Alignment.CenterHorizontally) { + Text(text, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + if (onAction != null) TextButton(onClick = onAction) { Text("Open Settings") } + } +} + +@Composable +private fun LastUpdated(timestamp: Long?) { + Text("Updated ${timestamp?.let(::formatTimestamp) ?: "never"}", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 8.dp)) +} + +@Composable +private fun SettingsCard(content: @Composable ColumnScope.() -> Unit) { + Card(colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), shape = RoundedCornerShape(24.dp), modifier = Modifier.fillMaxWidth()) { + Column(content = content) + } +} + +@Composable +private fun SectionTitle(title: String) { + Text(title.uppercase(), style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 8.dp)) +} + +@Composable +private fun RowItem(icon: ImageVector, title: String, subtitle: String, danger: Boolean = false, action: @Composable () -> Unit) { + Row(Modifier.fillMaxWidth().padding(16.dp), verticalAlignment = Alignment.CenterVertically) { + Icon(icon, null, tint = if (danger) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant) + Spacer(Modifier.width(14.dp)) + Column(Modifier.weight(1f)) { + Text(title, fontWeight = FontWeight.SemiBold, color = if (danger) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurface) + Text(subtitle, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, overflow = TextOverflow.Ellipsis) + } + action() + } +} + +@Composable +private fun SwitchRow(title: String, subtitle: String, checked: Boolean, onChecked: (Boolean) -> Unit) { + RowItem(Icons.Rounded.Alarm, title, subtitle) { Switch(checked = checked, onCheckedChange = onChecked) } +} + +@Composable +private fun TimeSetting(settings: NotificationSettings, onChange: (Int, Int) -> Unit) { + var value by remember(settings.dailyHour, settings.dailyMinute) { mutableStateOf("%02d:%02d".format(settings.dailyHour, settings.dailyMinute)) } + OutlinedTextField( + value = value, + onValueChange = { + value = it.take(5) + parseTime(value)?.let { parsed -> onChange(parsed.first, parsed.second) } + }, + label = { Text("Digest time") }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp), + supportingText = { Text("Use 24-hour HH:MM format.") }, + ) +} + +@Composable +private fun ThresholdSetting(settings: NotificationSettings, onChange: (Int) -> Unit) { + var value by remember(settings.thresholdPct) { mutableStateOf(settings.thresholdPct.toString()) } + OutlinedTextField( + value = value, + onValueChange = { next -> value = next.filter(Char::isDigit).take(2); value.toIntOrNull()?.takeIf { it in 1..99 }?.let(onChange) }, + label = { Text("Alert below % remaining") }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp), + ) +} + +@Composable +private fun StatusDot(status: LoadStatus, connected: Boolean) { + val color = when { + status == LoadStatus.Error -> MaterialTheme.colorScheme.error + connected -> CodexGreen + else -> MaterialTheme.colorScheme.outline + } + Surface(shape = CircleShape, color = color, modifier = Modifier.size(10.dp)) {} +} + +private fun connectedSummary(vm: AppViewModel): String = when (listOf(vm.codexAuth, vm.claudeAuth).count { it != null }) { + 0 -> "No services connected" + 1 -> "1 of 2 services connected" + else -> "2 services connected" +} + +private val MainTab.icon: ImageVector get() = when (this) { + MainTab.Dashboard -> Icons.Rounded.Home + MainTab.Codex -> Icons.Rounded.AutoAwesome + MainTab.Claude -> Icons.Rounded.Psychology + MainTab.Settings -> Icons.Rounded.Settings +} + +private fun usageColor(percent: Int, fallback: Color): Color = when { + percent >= 85 -> DangerRed + percent >= 60 -> WarningAmber + else -> fallback +} + +private fun resetText(window: UsageWindow): String? = when { + window.resetsAt != null -> "Resets ${formatTimestamp(window.resetsAt * 1000L)}" + window.resetsAtIso != null -> runCatching { "Resets ${formatTimestamp(Instant.parse(window.resetsAtIso).toEpochMilli())}" }.getOrNull() + else -> null +} + +private fun windowLabel(seconds: Long?): String = when { + seconds == null || seconds <= 0L -> "Usage" + seconds < 3_600L -> "${seconds / 60L}m" + seconds < 86_400L -> "${seconds / 3_600L}h" + else -> "${seconds / 86_400L}d" +} + +private fun formatTimestamp(value: Long): String = DateTimeFormatter.ofPattern("MMM d, HH:mm") + .withZone(ZoneId.systemDefault()) + .format(Instant.ofEpochMilli(value)) + +private fun parseTime(value: String): Pair? { + val parts = value.split(":") + if (parts.size != 2) return null + val hour = parts[0].toIntOrNull() ?: return null + val minute = parts[1].toIntOrNull() ?: return null + return if (hour in 0..23 && minute in 0..59) hour to minute else null +} + +private val CodexGreen = Color(0xFF10A37F) +private val ClaudeAmber = Color(0xFFD97706) +private val WarningAmber = Color(0xFFF59E0B) +private val DangerRed = Color(0xFFEF4444) +private val MutedButton = Color(0xFF52525B) + +@Composable +private fun CodexMobileTheme(content: @Composable () -> Unit) { + val dark = darkColorScheme( + primary = CodexGreen, + secondary = ClaudeAmber, + background = Color(0xFF090D11), + surface = Color(0xFF10161B), + surfaceVariant = Color(0xFF1A2229), + onPrimary = Color.White, + onSecondary = Color.White, + onBackground = Color(0xFFE7ECEF), + onSurface = Color(0xFFE7ECEF), + onSurfaceVariant = Color(0xFF9CA3AF), + ) + val light = lightColorScheme( + primary = CodexGreen, + secondary = ClaudeAmber, + background = Color(0xFFF6F8F7), + surface = Color.White, + surfaceVariant = Color(0xFFECEFED), + onPrimary = Color.White, + onSecondary = Color.White, + ) + MaterialTheme(colorScheme = if (isSystemInDarkTheme()) dark else light, content = { + Surface(Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background, content = content) + }) +} diff --git a/app/src/main/java/dev/reversed/codexbarmobile/Models.kt b/app/src/main/java/dev/reversed/codexbarmobile/Models.kt new file mode 100644 index 0000000..fa5425d --- /dev/null +++ b/app/src/main/java/dev/reversed/codexbarmobile/Models.kt @@ -0,0 +1,104 @@ +package dev.reversed.codexbarmobile + +data class CodexAuth( + val accessToken: String, + val accountId: String? = null, +) + +data class UsageWindow( + val usedPercent: Double, + val resetsAt: Long? = null, + val resetsAtIso: String? = null, + val windowSeconds: Long? = null, +) + +data class CodexCredits( + val hasCredits: Boolean, + val unlimited: Boolean, + val balance: Double, +) + +data class ResetCredit( + val index: Int, + val status: String?, + val grantedAt: String?, + val expiresAt: String?, + val timeUntilExpiry: String?, +) + +data class ResetCoupons( + val source: String, + val sourceDescription: String, + val availableCount: Int?, + val totalEarnedCount: Int?, + val credits: List, + val nextExpiringCredit: ResetCredit?, + val error: String? = null, +) + +data class CodexUsage( + val planType: String?, + val rateLimitReachedType: String?, + val primary: UsageWindow?, + val secondary: UsageWindow?, + val credits: CodexCredits, + val resetCoupons: ResetCoupons?, +) + +data class ClaudeAuth( + val sessionKey: String, + val lastActiveOrg: String? = null, +) + +data class ClaudeOrg( + val uuid: String, + val name: String, +) + +data class ClaudeWindowUsage( + val utilization: Double, + val resetsAt: String? = null, +) + +data class ClaudeUsage( + val fiveHour: ClaudeWindowUsage, + val sevenDay: ClaudeWindowUsage, + val sevenDaySonnet: ClaudeWindowUsage? = null, + val sevenDayOpus: ClaudeWindowUsage? = null, +) + +data class UsageCache( + val data: T, + val lastFetchedAt: Long, +) + +data class NotificationSettings( + val dailyEnabled: Boolean = false, + val dailyHour: Int = 9, + val dailyMinute: Int = 0, + val thresholdEnabled: Boolean = false, + val thresholdPct: Int = 20, +) + +enum class LoadStatus { + Idle, + Loading, + Success, + Error, +} + +enum class AppScreen { + Splash, + Welcome, + OnboardingCodex, + OnboardingClaude, + OnboardingDone, + Main, +} + +enum class MainTab(val label: String) { + Dashboard("Home"), + Codex("Codex"), + Claude("Claude"), + Settings("Settings"), +} diff --git a/app/src/main/java/dev/reversed/codexbarmobile/Notifications.kt b/app/src/main/java/dev/reversed/codexbarmobile/Notifications.kt new file mode 100644 index 0000000..d566693 --- /dev/null +++ b/app/src/main/java/dev/reversed/codexbarmobile/Notifications.kt @@ -0,0 +1,168 @@ +package dev.reversed.codexbarmobile + +import android.Manifest +import android.app.AlarmManager +import android.app.Application +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import androidx.core.content.ContextCompat +import java.time.LocalDate +import java.util.Calendar +import kotlin.math.roundToInt + +class CodexMobileApp : Application() { + override fun onCreate() { + super.onCreate() + NotificationScheduler.ensureChannel(this) + } +} + +object NotificationScheduler { + private const val CHANNEL_ID = "usage-alerts" + private const val CHANNEL_NAME = "Usage alerts" + private const val DAILY_REQUEST_CODE = 1001 + private const val EXTRA_BODY = "body" + + fun ensureChannel(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val manager = context.getSystemService(NotificationManager::class.java) + val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT).apply { + description = "CodexMobile usage digests and quota warnings" + } + manager.createNotificationChannel(channel) + } + } + + fun hasNotificationPermission(context: Context): Boolean = + Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || + ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED + + fun scheduleDailyDigest(context: Context, hour: Int, minute: Int, body: String) { + if (!hasNotificationPermission(context)) return + ensureChannel(context) + val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager + val intent = Intent(context, DailyDigestReceiver::class.java).putExtra(EXTRA_BODY, body) + val pending = PendingIntent.getBroadcast( + context, + DAILY_REQUEST_CODE, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val firstRun = Calendar.getInstance().apply { + set(Calendar.HOUR_OF_DAY, hour) + set(Calendar.MINUTE, minute) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + if (timeInMillis <= System.currentTimeMillis()) add(Calendar.DAY_OF_YEAR, 1) + } + alarmManager.setInexactRepeating( + AlarmManager.RTC_WAKEUP, + firstRun.timeInMillis, + AlarmManager.INTERVAL_DAY, + pending, + ) + } + + fun cancelDailyDigest(context: Context) { + val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager + val pending = PendingIntent.getBroadcast( + context, + DAILY_REQUEST_CODE, + Intent(context, DailyDigestReceiver::class.java), + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + alarmManager.cancel(pending) + pending.cancel() + } + + fun showQuotaAlert(context: Context, body: String) { + if (!hasNotificationPermission(context)) return + showNotification( + context = context, + id = 2001, + title = "Low quota warning", + body = body, + ) + } + + fun showDailyDigest(context: Context, body: String) { + showNotification( + context = context, + id = 1002, + title = "Usage digest", + body = body.ifBlank { "Open CodexMobile to check your usage limits." }, + ) + } + + private fun showNotification(context: Context, id: Int, title: String, body: String) { + if (!hasNotificationPermission(context)) return + ensureChannel(context) + val openIntent = PendingIntent.getActivity( + context, + id, + Intent(context, MainActivity::class.java), + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val notification = NotificationCompat.Builder(context, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_notification) + .setContentTitle(title) + .setContentText(body) + .setStyle(NotificationCompat.BigTextStyle().bigText(body)) + .setContentIntent(openIntent) + .setAutoCancel(true) + .setColor(0xFF10A37F.toInt()) + .build() + NotificationManagerCompat.from(context).notify(id, notification) + } +} + +class DailyDigestReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + NotificationScheduler.showDailyDigest(context, intent.getStringExtra("body").orEmpty()) + } +} + +fun maybeFireThresholdAlert( + context: Context, + storage: AppStorage, + settings: NotificationSettings, + claudeUsage: ClaudeUsage?, + codexUsage: CodexUsage?, +) { + if (!settings.thresholdEnabled) return + val today = LocalDate.now().toString() + if (storage.loadThresholdLastFired() == today) return + + val alerts = buildList { + claudeUsage?.let { + val remaining = 100.0 - it.sevenDay.utilization + if (remaining <= settings.thresholdPct) add("Claude 7-day: ${remaining.roundPercent()}% remaining") + } + codexUsage?.let { + val remaining = 100.0 - (it.secondary?.usedPercent ?: 0.0) + if (remaining <= settings.thresholdPct) add("Codex weekly: ${remaining.roundPercent()}% remaining") + } + } + if (alerts.isNotEmpty()) { + NotificationScheduler.showQuotaAlert(context, alerts.joinToString("\n")) + storage.saveThresholdLastFired(today) + } +} + +fun buildDailyDigestBody(claudeUsage: ClaudeUsage?, codexUsage: CodexUsage?): String { + val parts = buildList { + claudeUsage?.let { add("Claude 7d: ${it.sevenDay.utilization.roundPercent()}% used") } + codexUsage?.secondary?.let { add("Codex weekly: ${it.usedPercent.roundPercent()}% used") } + } + return if (parts.isEmpty()) "Open CodexMobile to check your usage limits." else parts.joinToString(" · ") +} + +fun Double.roundPercent(): Int = roundToInt().coerceIn(0, 100) diff --git a/app/src/main/java/dev/reversed/codexbarmobile/UsageApi.kt b/app/src/main/java/dev/reversed/codexbarmobile/UsageApi.kt new file mode 100644 index 0000000..3251e94 --- /dev/null +++ b/app/src/main/java/dev/reversed/codexbarmobile/UsageApi.kt @@ -0,0 +1,196 @@ +package dev.reversed.codexbarmobile + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.OkHttpClient +import okhttp3.Request +import org.json.JSONArray +import org.json.JSONObject +import java.time.Instant +import java.util.concurrent.TimeUnit + +class UsageApi { + private val client = OkHttpClient.Builder() + .connectTimeout(25, TimeUnit.SECONDS) + .readTimeout(25, TimeUnit.SECONDS) + .build() + + suspend fun fetchCodexUsage(auth: CodexAuth): CodexUsage = withContext(Dispatchers.IO) { + val request = Request.Builder() + .url(CODEX_USAGE_URL) + .applyCodexHeaders(auth) + .get() + .build() + + val payload = client.newCall(request).execute().use { response -> + if (response.code == 401 || response.code == 403) throw IllegalStateException("TOKEN_EXPIRED") + if (!response.isSuccessful) throw IllegalStateException("HTTP_ERROR_${response.code}") + JSONObject(response.body?.string().orEmpty()) + } + + val resetCoupons = fetchResetCoupons(auth, payload) + CodexUsage( + planType = payload.optStringOrNull("plan_type"), + rateLimitReachedType = payload.optStringOrNull("rate_limit_reached_type"), + primary = payload.optJSONObject("rate_limit")?.optJSONObject("primary_window")?.toCodexWindow(), + secondary = payload.optJSONObject("rate_limit")?.optJSONObject("secondary_window")?.toCodexWindow(), + credits = payload.optJSONObject("credits").let { credits -> + CodexCredits( + hasCredits = credits?.optBoolean("has_credits") ?: false, + unlimited = credits?.optBoolean("unlimited") ?: false, + balance = credits?.optDouble("balance", 0.0) ?: 0.0, + ) + }, + resetCoupons = resetCoupons, + ) + } + + private fun fetchResetCoupons(auth: CodexAuth, usagePayload: JSONObject): ResetCoupons { + val request = Request.Builder() + .url(CODEX_RESET_CREDITS_URL) + .applyCodexHeaders(auth) + .header("OpenAI-Beta", "codex-1") + .header("originator", "Codex Desktop") + .get() + .build() + + return runCatching { + client.newCall(request).execute().use { response -> + if (!response.isSuccessful) throw IllegalStateException("HTTP_ERROR_${response.code}") + val payload = JSONObject(response.body?.string().orEmpty()) + val rawCredits = payload.optJSONArray("credits") ?: JSONArray() + val credits = (0 until rawCredits.length()) + .mapNotNull { index -> rawCredits.optJSONObject(index)?.toResetCredit(index + 1) } + .sortedBy { credit -> credit.expiresAt?.let { runCatching { Instant.parse(it) }.getOrNull() } ?: Instant.MAX } + val available = credits.filter { it.status == "available" } + ResetCoupons( + source = "live_api", + sourceDescription = "Live Codex reset-credit endpoint", + availableCount = payload.optIntOrNull("available_count") + ?: usagePayload.optJSONObject("rate_limit_reset_credits")?.optIntOrNull("available_count"), + totalEarnedCount = payload.optIntOrNull("total_earned_count"), + credits = credits, + nextExpiringCredit = available.firstOrNull() ?: credits.firstOrNull(), + ) + } + }.getOrElse { error -> + ResetCoupons( + source = "unavailable", + sourceDescription = "Reset-credit endpoint unavailable", + availableCount = usagePayload.optJSONObject("rate_limit_reset_credits")?.optIntOrNull("available_count"), + totalEarnedCount = null, + credits = emptyList(), + nextExpiringCredit = null, + error = error.message ?: "UNKNOWN_ERROR", + ) + } + } + + suspend fun fetchClaudeUsage(auth: ClaudeAuth): ClaudeUsage = withContext(Dispatchers.IO) { + val orgId = auth.lastActiveOrg?.takeIf { it.isNotBlank() } ?: fetchClaudeOrgs(auth).firstOrNull()?.uuid + ?: throw IllegalStateException("NO_ORGS_FOUND") + + val request = Request.Builder() + .url("$CLAUDE_BASE_URL/organizations/$orgId/usage") + .applyClaudeHeaders(auth) + .get() + .build() + + client.newCall(request).execute().use { response -> + if (response.code == 401 || response.code == 403) throw IllegalStateException("TOKEN_EXPIRED") + if (!response.isSuccessful) throw IllegalStateException("HTTP_ERROR_${response.code}") + JSONObject(response.body?.string().orEmpty()).toClaudeUsageFromApi() + } + } + + private fun fetchClaudeOrgs(auth: ClaudeAuth): List { + val request = Request.Builder() + .url("$CLAUDE_BASE_URL/organizations") + .applyClaudeHeaders(auth) + .get() + .build() + + return client.newCall(request).execute().use { response -> + if (response.code == 401 || response.code == 403) throw IllegalStateException("TOKEN_EXPIRED") + if (!response.isSuccessful) throw IllegalStateException("HTTP_ERROR_${response.code}") + val arr = JSONArray(response.body?.string().orEmpty()) + (0 until arr.length()).mapNotNull { index -> + arr.optJSONObject(index)?.let { ClaudeOrg(it.getString("uuid"), it.optString("name")) } + } + } + } + + private fun Request.Builder.applyCodexHeaders(auth: CodexAuth): Request.Builder = apply { + header("Authorization", "Bearer ${auth.accessToken}") + header("Content-Type", "application/json") + auth.accountId?.takeIf { it.isNotBlank() }?.let { header("ChatGPT-Account-Id", it) } + } + + private fun Request.Builder.applyClaudeHeaders(auth: ClaudeAuth): Request.Builder = apply { + val cookies = buildList { + add("sessionKey=${auth.sessionKey}") + auth.lastActiveOrg?.takeIf { it.isNotBlank() }?.let { add("lastActiveOrg=$it") } + } + header("Cookie", cookies.joinToString("; ")) + header("Accept", "application/json, text/plain, */*") + header("Accept-Language", "en-US,en;q=0.9") + header("User-Agent", BROWSER_USER_AGENT) + header("Referer", "https://claude.ai/") + header("Origin", "https://claude.ai") + header("anthropic-client-platform", "web_claude_to_cc_migration") + } + + companion object { + private const val CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage" + private const val CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits" + private const val CLAUDE_BASE_URL = "https://claude.ai/api" + private const val BROWSER_USER_AGENT = "Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36" + } +} + +private fun JSONObject.toCodexWindow(): UsageWindow { + val seconds = optLong("limit_window_seconds", 0L) + return UsageWindow( + usedPercent = optDouble("used_percent", 0.0), + resetsAt = optLong("reset_at", 0L).takeIf { it > 0L }, + windowSeconds = seconds.takeIf { it > 0L }, + ) +} + +private fun JSONObject.toResetCredit(index: Int): ResetCredit = ResetCredit( + index = index, + status = optStringOrNull("status"), + grantedAt = optStringOrNull("granted_at"), + expiresAt = optStringOrNull("expires_at"), + timeUntilExpiry = formatDurationUntil(optStringOrNull("expires_at")), +) + +private fun JSONObject.toClaudeUsageFromApi(): ClaudeUsage = ClaudeUsage( + fiveHour = getJSONObject("five_hour").toClaudeWindowFromApi(), + sevenDay = getJSONObject("seven_day").toClaudeWindowFromApi(), + sevenDaySonnet = optJSONObject("seven_day_sonnet")?.toClaudeWindowFromApi(), + sevenDayOpus = optJSONObject("seven_day_opus")?.toClaudeWindowFromApi(), +) + +private fun JSONObject.toClaudeWindowFromApi(): ClaudeWindowUsage = ClaudeWindowUsage( + utilization = optDouble("utilization", 0.0), + resetsAt = optStringOrNull("resets_at"), +) + +fun formatDurationUntil(isoString: String?): String? { + if (isoString.isNullOrBlank()) return null + val target = runCatching { Instant.parse(isoString).toEpochMilli() }.getOrNull() ?: return null + var remaining = ((target - System.currentTimeMillis()).coerceAtLeast(0L) / 1000L) + val days = remaining / 86_400L + remaining -= days * 86_400L + val hours = remaining / 3_600L + remaining -= hours * 3_600L + val minutes = remaining / 60L + remaining -= minutes * 60L + return buildList { + if (days > 0) add("${days}d") + if (hours > 0) add("${hours}h") + if (minutes > 0) add("${minutes}m") + if (remaining > 0 || isEmpty()) add("${remaining}s") + }.joinToString(" ") +} diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..8e61c97 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_notification.xml b/app/src/main/res/drawable/ic_notification.xml new file mode 100644 index 0000000..2f64864 --- /dev/null +++ b/app/src/main/res/drawable/ic_notification.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..a8a8fa5 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..a8a8fa5 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..e7d5998 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #10A37F + #071311 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..9444666 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + CodexMobile + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..1517501 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..aebb820 --- /dev/null +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/android-icon-background.png b/assets/android-icon-background.png deleted file mode 100644 index 8f0d024..0000000 Binary files a/assets/android-icon-background.png and /dev/null differ diff --git a/assets/android-icon-foreground.png b/assets/android-icon-foreground.png deleted file mode 100644 index 4aa3c05..0000000 Binary files a/assets/android-icon-foreground.png and /dev/null differ diff --git a/assets/android-icon-monochrome.png b/assets/android-icon-monochrome.png deleted file mode 100644 index ef4a0dd..0000000 Binary files a/assets/android-icon-monochrome.png and /dev/null differ diff --git a/assets/favicon.png b/assets/favicon.png deleted file mode 100644 index 7bb5cd6..0000000 Binary files a/assets/favicon.png and /dev/null differ diff --git a/assets/icon.png b/assets/icon.png deleted file mode 100644 index 0fac318..0000000 Binary files a/assets/icon.png and /dev/null differ diff --git a/assets/notification-icon.png b/assets/notification-icon.png deleted file mode 100644 index a4a6585..0000000 Binary files a/assets/notification-icon.png and /dev/null differ diff --git a/assets/splash-icon.png b/assets/splash-icon.png deleted file mode 100644 index 0fac318..0000000 Binary files a/assets/splash-icon.png and /dev/null differ diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 1d96698..0000000 --- a/babel.config.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = function (api) { - api.cache(true); - return { - presets: [ - ["babel-preset-expo", { jsxImportSource: "nativewind" }], - "nativewind/babel", - ], - plugins: ["react-native-reanimated/plugin"], - }; -}; diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..6f48f61 --- /dev/null +++ b/build.gradle @@ -0,0 +1,4 @@ +plugins { + id 'com.android.application' version '8.5.2' apply false + id 'org.jetbrains.kotlin.android' version '1.9.24' apply false +} diff --git a/components/ErrorMessage.tsx b/components/ErrorMessage.tsx deleted file mode 100644 index 14e2639..0000000 --- a/components/ErrorMessage.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { View, Text } from "react-native"; - -const ERROR_MESSAGES: Record = { - TOKEN_EXPIRED: "Your session token has expired. Please reconfigure.", - MISSING_ACCESS_TOKEN: "auth.json is missing the accessToken field.", - INVALID_JSON: "The selected file is not valid JSON.", - DOCUMENT_NOT_READABLE: - "The selected file could not be read. Try copying auth.json into Files or Downloads and import it again.", - NO_ORGS_FOUND: "No Claude organizations found for this session key.", - INVALID_CODEX_RESPONSE: - "Codex returned an unexpected response. The app was kept safe from invalid data.", - INVALID_CLAUDE_RESPONSE: - "Claude returned an unexpected usage response. The app was kept safe from invalid data.", - INVALID_CLAUDE_ORGS_RESPONSE: - "Claude returned an unexpected organizations response.", - UNKNOWN_ERROR: "An unknown error occurred. Try refreshing.", -}; - -function humanize(code: string): string { - if (code.startsWith("HTTP_ERROR_")) { - const status = code.replace("HTTP_ERROR_", ""); - if (status === "429") return "Rate limited by the server. Try again shortly."; - if (status === "500" || status === "502" || status === "503") - return `Server error (${status}). The service may be down.`; - return `Unexpected server response (HTTP ${status}).`; - } - if ( - code === "Network request failed" || - code.includes("fetch") || - code.includes("network") - ) { - return "Network error. Check your internet connection and try again."; - } - return ERROR_MESSAGES[code] ?? `Unexpected error: ${code}`; -} - -interface ErrorMessageProps { - message: string | null; -} - -export function ErrorMessage({ message }: ErrorMessageProps) { - if (!message) return null; - - return ( - - {humanize(message)} - - ); -} diff --git a/components/LastUpdated.tsx b/components/LastUpdated.tsx deleted file mode 100644 index 2b3c553..0000000 --- a/components/LastUpdated.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect, useState } from "react"; -import { Text } from "react-native"; -import { COUNTDOWN_INTERVAL_MS } from "@/lib/constants"; -import { formatLastUpdated } from "@/lib/timeUtils"; - -export function LastUpdated({ timestamp }: { timestamp: number | null }) { - const [now, setNow] = useState(Date.now); - - useEffect(() => { - const interval = setInterval(() => setNow(Date.now()), COUNTDOWN_INTERVAL_MS); - return () => clearInterval(interval); - }, []); - - if (!timestamp) return null; - - return ( - - {formatLastUpdated(timestamp, now)} - - ); -} diff --git a/components/ProgressBar.tsx b/components/ProgressBar.tsx deleted file mode 100644 index ea5e709..0000000 --- a/components/ProgressBar.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { View } from "react-native"; -import { PROGRESS_THRESHOLDS } from "@/lib/constants"; - -interface ProgressBarProps { - percent: number; -} - -function getBarColor(percent: number): string { - if (percent >= PROGRESS_THRESHOLDS.danger) return "bg-red-500"; - if (percent >= PROGRESS_THRESHOLDS.warning) return "bg-yellow-400"; - return "bg-green-500"; -} - -export function ProgressBar({ percent }: ProgressBarProps) { - const clamped = Math.max(0, Math.min(100, percent)); - return ( - - - - ); -} diff --git a/components/ResetCountdown.tsx b/components/ResetCountdown.tsx deleted file mode 100644 index 1c2f04f..0000000 --- a/components/ResetCountdown.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import { Text } from "react-native"; -import { COUNTDOWN_INTERVAL_MS } from "@/lib/constants"; -import { formatResetCountdown, formatResetCountdownISO } from "@/lib/timeUtils"; - -interface ResetCountdownProps { - resetAtSeconds?: number; - resetAtISO?: string; -} - -export function ResetCountdown({ resetAtSeconds, resetAtISO }: ResetCountdownProps) { - const latest = useRef({ resetAtSeconds, resetAtISO }); - latest.current = { resetAtSeconds, resetAtISO }; - - const getLabel = () => { - if (latest.current.resetAtSeconds !== undefined) { - return formatResetCountdown(latest.current.resetAtSeconds); - } - if (latest.current.resetAtISO) return formatResetCountdownISO(latest.current.resetAtISO); - return ""; - }; - - const [label, setLabel] = useState(getLabel); - - useEffect(() => { - const update = () => setLabel(getLabel()); - update(); - const interval = setInterval(update, COUNTDOWN_INTERVAL_MS); - return () => clearInterval(interval); - }, []); - - useEffect(() => { - setLabel(getLabel()); - }, [resetAtSeconds, resetAtISO]); - - if (!label) return null; - - return ( - {label} - ); -} diff --git a/components/ScreenErrorBoundary.tsx b/components/ScreenErrorBoundary.tsx deleted file mode 100644 index d6be1c7..0000000 --- a/components/ScreenErrorBoundary.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from "react"; -import { Text, TouchableOpacity, View } from "react-native"; -import { COLORS } from "@/lib/constants"; - -interface Props { - children: React.ReactNode; - screenName: string; -} - -interface State { - error: Error | null; -} - -export class ScreenErrorBoundary extends React.Component { - state: State = { error: null }; - - static getDerivedStateFromError(error: Error): State { - return { error }; - } - - render() { - if (!this.state.error) return this.props.children; - - return ( - - - {this.props.screenName} hit a snag - - - This screen could not be rendered. The rest of Codexbar is still available. - - this.setState({ error: null })} - className="mt-5 rounded-xl px-4 py-3" - style={{ backgroundColor: COLORS.codex }} - > - Try again - - - ); - } -} diff --git a/components/SectionCard.tsx b/components/SectionCard.tsx deleted file mode 100644 index 8730674..0000000 --- a/components/SectionCard.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { View, Text } from "react-native"; - -interface SectionCardProps { - title: string; - children: React.ReactNode; - accentClass?: string; -} - -export function SectionCard({ title, children, accentClass }: SectionCardProps) { - return ( - - - {title} - - {children} - - ); -} diff --git a/components/ServiceStatusCard.tsx b/components/ServiceStatusCard.tsx deleted file mode 100644 index 323d4b9..0000000 --- a/components/ServiceStatusCard.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { View, Text, TouchableOpacity, ActivityIndicator } from "react-native"; -import { MaterialIcons } from "@expo/vector-icons"; -import { ProgressBar } from "./ProgressBar"; -import { ResetCountdown } from "./ResetCountdown"; - -interface UsageRow { - label: string; - percent: number; - resetAtSeconds?: number; - resetAtISO?: string; -} - -interface ServiceStatusCardProps { - title: string; - icon: React.ComponentProps["name"]; - accentColor: string; - status: "idle" | "loading" | "success" | "error"; - badge?: string; - rows?: UsageRow[]; - footer?: React.ReactNode; - unconfiguredLabel?: string; - onConfigurePress?: () => void; -} - -export function ServiceStatusCard({ - title, - icon, - accentColor, - status, - badge, - rows, - footer, - unconfiguredLabel, - onConfigurePress, -}: ServiceStatusCardProps) { - return ( - - {/* Header */} - - - - - - - {title} - - - {badge && ( - - - {badge} - - - )} - {status === "success" && !badge && ( - - )} - {status === "error" && ( - - )} - - - {/* Body */} - {status === "loading" && ( - - )} - - {status === "idle" && ( - - - {unconfiguredLabel ?? "Not configured"} - - {onConfigurePress && ( - - - Configure → - - - )} - - )} - - {status === "error" && ( - - Failed to load usage data - - )} - - {status === "success" && rows && ( - - {rows.map((row, i) => ( - - - - {row.label} - - - {Math.round(row.percent)}% - - - - - - ))} - - )} - - {footer && ( - - {footer} - - )} - - ); -} diff --git a/components/UsageStat.tsx b/components/UsageStat.tsx deleted file mode 100644 index b465f79..0000000 --- a/components/UsageStat.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { View, Text } from "react-native"; -import { ProgressBar } from "./ProgressBar"; -import { ResetCountdown } from "./ResetCountdown"; - -interface UsageStatProps { - label: string; - percent: number; - resetAtSeconds?: number; - resetAtISO?: string; -} - -export function UsageStat({ label, percent, resetAtSeconds, resetAtISO }: UsageStatProps) { - return ( - - - - {label} - - - {Math.round(percent)}% - - - - - - ); -} diff --git a/eas.json b/eas.json deleted file mode 100644 index 4f71066..0000000 --- a/eas.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "cli": { - "version": ">= 16.0.0", - "appVersionSource": "remote" - }, - "build": { - "preview": { - "channel": "preview", - "distribution": "internal", - "android": { - "buildType": "apk" - } - }, - "production": { - "channel": "production", - "distribution": "internal", - "android": { - "buildType": "apk" - } - } - }, - "submit": { - "production": {} - } -} diff --git a/global.css b/global.css deleted file mode 100644 index b5c61c9..0000000 --- a/global.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..8f2e28c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +android.useAndroidX=true +android.nonTransitiveRClass=true +kotlin.code.style=official diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e644113 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b82aa23 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..c0cf937 --- /dev/null +++ b/gradlew @@ -0,0 +1,23 @@ +#!/bin/sh + +# Copyright 2015-2021 the original authors. +# Licensed under the Apache License, Version 2.0. + +APP_HOME=${0%/*} +[ "$APP_HOME" = "$0" ] && APP_HOME=. +APP_HOME=$(cd "$APP_HOME" >/dev/null && pwd -P) || exit +APP_BASE_NAME=${0##*/} +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +if [ -n "$JAVA_HOME" ]; then + JAVACMD=$JAVA_HOME/bin/java +else + JAVACMD=java +fi + +if ! command -v "$JAVACMD" >/dev/null 2>&1 && [ ! -x "$JAVACMD" ]; then + echo "ERROR: Java is not available. Set JAVA_HOME to a JDK 17 installation." >&2 + exit 1 +fi + +exec "$JAVACMD" "-Xmx64m" "-Xms64m" "-Dorg.gradle.appname=$APP_BASE_NAME" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..46b0556 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,23 @@ +@if "%DEBUG%"=="" @echo off +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" +if defined JAVA_HOME goto findJavaFromJavaHome +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute +echo ERROR: JAVA_HOME is not set and no java command could be found. 1>&2 +exit /b 1 +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe +if exist "%JAVA_EXE%" goto execute +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +exit /b 1 +:execute +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +exit /b %ERRORLEVEL% diff --git a/hooks/useClaudeUsage.ts b/hooks/useClaudeUsage.ts deleted file mode 100644 index 02f905b..0000000 --- a/hooks/useClaudeUsage.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from "react"; -import { - fetchClaudeOrgs, - fetchClaudeUsage, - parseClaudeUsageResponse, -} from "@/lib/api/claudeApi"; -import { - isClaudeSessionKeyValid, - validateClaudeSessionKey, -} from "@/lib/claudeCredentials"; -import { RETRY_DELAY_MS } from "@/lib/constants"; -import { - clearClaudeLastActiveOrg, - clearClaudeSessionKey, - clearClaudeUsageCache, - loadClaudeLastActiveOrg, - loadClaudeSessionKey, - loadClaudeUsageCache, - saveClaudeLastActiveOrg, - saveClaudeSessionKey, - saveClaudeUsageCache, -} from "@/lib/storage"; -import type { ClaudeAuth, ClaudeUsageResponse } from "@/types/claude"; - -type Status = "idle" | "loading" | "success" | "error"; - -function shouldRetry(error: unknown): boolean { - const message = error instanceof Error ? error.message : ""; - return ![ - "TOKEN_EXPIRED", - "NO_ORGS_FOUND", - "INVALID_CLAUDE_RESPONSE", - "INVALID_CLAUDE_ORGS_RESPONSE", - ].includes(message); -} - -function wait(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -async function requestClaudeUsage(auth: ClaudeAuth): Promise { - let orgUuid = auth.lastActiveOrg?.trim(); - if (!orgUuid) { - const orgs = await fetchClaudeOrgs(auth); - if (!orgs.length) throw new Error("NO_ORGS_FOUND"); - orgUuid = orgs[0].uuid; - await saveClaudeLastActiveOrg(orgUuid); - } - return fetchClaudeUsage(auth, orgUuid); -} - -export function useClaudeUsage() { - const [auth, setAuth] = useState(null); - const [pendingKey, setPendingKey] = useState(""); - const [pendingOrg, setPendingOrg] = useState(""); - const [usage, setUsage] = useState(null); - const [lastFetchedAt, setLastFetchedAt] = useState(null); - const [status, setStatus] = useState("idle"); - const [error, setError] = useState(null); - const mounted = useRef(true); - const inFlight = useRef<{ - key: string; - promise: Promise; - } | null>(null); - const requestVersion = useRef(0); - - useEffect(() => { - mounted.current = true; - return () => { - mounted.current = false; - }; - }, []); - - const fetchUsage = useCallback((credentials: ClaudeAuth): Promise => { - const sanitized = { - sessionKey: credentials.sessionKey.trim(), - lastActiveOrg: credentials.lastActiveOrg?.trim() || undefined, - }; - const requestKey = `${sanitized.lastActiveOrg ?? ""}:${sanitized.sessionKey}`; - if (inFlight.current?.key === requestKey) return inFlight.current.promise; - const version = ++requestVersion.current; - - const promise = (async () => { - if (mounted.current) { - setStatus("loading"); - setError(null); - } - - try { - let data: ClaudeUsageResponse; - try { - data = await requestClaudeUsage(sanitized); - } catch (firstError) { - if (!shouldRetry(firstError)) throw firstError; - await wait(RETRY_DELAY_MS); - if (version !== requestVersion.current) return; - data = await requestClaudeUsage(sanitized); - } - - if (version !== requestVersion.current) return; - const fetchedAt = Date.now(); - await saveClaudeUsageCache({ data, lastFetchedAt: fetchedAt }); - if (mounted.current && version === requestVersion.current) { - setUsage(data); - setLastFetchedAt(fetchedAt); - setStatus("success"); - } - } catch (caught: unknown) { - if (version !== requestVersion.current) return; - const message = caught instanceof Error ? caught.message : "UNKNOWN_ERROR"; - if (message === "TOKEN_EXPIRED") { - await clearClaudeSessionKey(); - if (mounted.current) { - setAuth(null); - setUsage(null); - setLastFetchedAt(null); - } - } - if (mounted.current) { - setError(message); - setStatus("error"); - } - } - })().finally(() => { - if (inFlight.current?.promise === promise) inFlight.current = null; - }); - - inFlight.current = { key: requestKey, promise }; - return promise; - }, []); - - useEffect(() => { - let active = true; - - void Promise.all([ - loadClaudeSessionKey(), - loadClaudeLastActiveOrg(), - loadClaudeUsageCache(), - ]).then(async ([key, org, cache]) => { - if (!active) return; - - const storedAuth = key - ? { sessionKey: key.trim(), lastActiveOrg: org?.trim() || undefined } - : null; - - if (storedAuth && cache) { - try { - if (!Number.isFinite(cache.lastFetchedAt)) { - throw new Error("INVALID_CACHE_TIMESTAMP"); - } - const cachedUsage = parseClaudeUsageResponse(cache.data); - setUsage(cachedUsage); - setLastFetchedAt(cache.lastFetchedAt); - setStatus("success"); - } catch { - await clearClaudeUsageCache(); - } - } - - setAuth(storedAuth); - if (storedAuth) await fetchUsage(storedAuth); - }); - - return () => { - active = false; - }; - }, [fetchUsage]); - - const saveKey = useCallback(async () => { - const trimmedKey = pendingKey.trim(); - const validationError = validateClaudeSessionKey(trimmedKey); - if (validationError) { - setError(validationError); - return; - } - - const trimmedOrg = pendingOrg.trim() || undefined; - await saveClaudeSessionKey(trimmedKey); - if (trimmedOrg) await saveClaudeLastActiveOrg(trimmedOrg); - else await clearClaudeLastActiveOrg(); - - const nextAuth = { sessionKey: trimmedKey, lastActiveOrg: trimmedOrg }; - setAuth(nextAuth); - setPendingKey(""); - setPendingOrg(""); - setError(null); - await fetchUsage(nextAuth); - }, [fetchUsage, pendingKey, pendingOrg]); - - const refresh = useCallback(async () => { - if (auth) await fetchUsage(auth); - }, [auth, fetchUsage]); - - const reloadCredentials = useCallback(async () => { - const [key, org] = await Promise.all([ - loadClaudeSessionKey(), - loadClaudeLastActiveOrg(), - ]); - if (!key) { - requestVersion.current += 1; - setAuth(null); - setUsage(null); - setLastFetchedAt(null); - setStatus("idle"); - return; - } - - const stored = { - sessionKey: key.trim(), - lastActiveOrg: org?.trim() || undefined, - }; - setAuth(stored); - await fetchUsage(stored); - }, [fetchUsage]); - - const clearKey = useCallback(async () => { - requestVersion.current += 1; - await clearClaudeSessionKey(); - setAuth(null); - setUsage(null); - setLastFetchedAt(null); - setStatus("idle"); - setError(null); - }, []); - - return { - auth, - pendingKey, - setPendingKey, - pendingOrg, - setPendingOrg, - usage, - lastFetchedAt, - status, - error, - keyValidationError: pendingKey - ? validateClaudeSessionKey(pendingKey) - : null, - canSaveKey: isClaudeSessionKeyValid(pendingKey), - saveKey, - refresh, - reloadCredentials, - clearKey, - }; -} diff --git a/hooks/useCodexUsage.ts b/hooks/useCodexUsage.ts deleted file mode 100644 index d359162..0000000 --- a/hooks/useCodexUsage.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from "react"; -import { - fetchCodexUsage, - parseCodexUsageResponse, -} from "@/lib/api/codexApi"; -import { RETRY_DELAY_MS } from "@/lib/constants"; -import { pickAndReadCodexAuth } from "@/lib/fileReader"; -import { - clearCodexAuth, - clearCodexUsageCache, - loadCodexAuth, - loadCodexUsageCache, - saveCodexAuth, - saveCodexUsageCache, -} from "@/lib/storage"; -import type { CodexAuth, CodexUsageResponse } from "@/types/codex"; - -type Status = "idle" | "loading" | "success" | "error"; - -function shouldRetry(error: unknown): boolean { - const message = error instanceof Error ? error.message : ""; - return message !== "TOKEN_EXPIRED" && message !== "INVALID_CODEX_RESPONSE"; -} - -function wait(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export function useCodexUsage() { - const [auth, setAuth] = useState(null); - const [usage, setUsage] = useState(null); - const [lastFetchedAt, setLastFetchedAt] = useState(null); - const [status, setStatus] = useState("idle"); - const [error, setError] = useState(null); - const mounted = useRef(true); - const inFlight = useRef<{ - key: string; - promise: Promise; - } | null>(null); - const requestVersion = useRef(0); - - useEffect(() => { - mounted.current = true; - return () => { - mounted.current = false; - }; - }, []); - - const fetchUsage = useCallback((credentials: CodexAuth): Promise => { - const requestKey = `${credentials.accountId ?? ""}:${credentials.accessToken}`; - if (inFlight.current?.key === requestKey) return inFlight.current.promise; - const version = ++requestVersion.current; - - const promise = (async () => { - if (mounted.current) { - setStatus("loading"); - setError(null); - } - - try { - let data: CodexUsageResponse; - try { - data = await fetchCodexUsage(credentials); - } catch (firstError) { - if (!shouldRetry(firstError)) throw firstError; - await wait(RETRY_DELAY_MS); - if (version !== requestVersion.current) return; - data = await fetchCodexUsage(credentials); - } - - if (version !== requestVersion.current) return; - const fetchedAt = Date.now(); - await saveCodexUsageCache({ data, lastFetchedAt: fetchedAt }); - if (mounted.current && version === requestVersion.current) { - setUsage(data); - setLastFetchedAt(fetchedAt); - setStatus("success"); - } - } catch (caught: unknown) { - if (version !== requestVersion.current) return; - const message = caught instanceof Error ? caught.message : "UNKNOWN_ERROR"; - if (mounted.current) { - setError(message); - setStatus("error"); - } - } - })().finally(() => { - if (inFlight.current?.promise === promise) inFlight.current = null; - }); - - inFlight.current = { key: requestKey, promise }; - return promise; - }, []); - - useEffect(() => { - let active = true; - - void Promise.all([loadCodexAuth(), loadCodexUsageCache()]).then( - async ([storedAuth, cache]) => { - if (!active) return; - - if (storedAuth && cache) { - try { - if (!Number.isFinite(cache.lastFetchedAt)) { - throw new Error("INVALID_CACHE_TIMESTAMP"); - } - const cachedUsage = parseCodexUsageResponse(cache.data); - setUsage(cachedUsage); - setLastFetchedAt(cache.lastFetchedAt); - setStatus("success"); - } catch { - await clearCodexUsageCache(); - } - } - - setAuth(storedAuth); - if (storedAuth) await fetchUsage(storedAuth); - } - ); - - return () => { - active = false; - }; - }, [fetchUsage]); - - const importAuthFile = useCallback(async () => { - try { - const parsed = await pickAndReadCodexAuth(); - await saveCodexAuth(parsed); - setAuth(parsed); - setError(null); - await fetchUsage(parsed); - } catch (caught: unknown) { - const message = caught instanceof Error ? caught.message : "UNKNOWN_ERROR"; - if (message !== "PICKER_CANCELLED") setError(message); - } - }, [fetchUsage]); - - const refresh = useCallback(async () => { - if (auth) await fetchUsage(auth); - }, [auth, fetchUsage]); - - const reloadCredentials = useCallback(async () => { - const stored = await loadCodexAuth(); - if (!stored) { - requestVersion.current += 1; - setAuth(null); - setUsage(null); - setLastFetchedAt(null); - setStatus("idle"); - return; - } - setAuth(stored); - await fetchUsage(stored); - }, [fetchUsage]); - - const clearAuth = useCallback(async () => { - requestVersion.current += 1; - await clearCodexAuth(); - setAuth(null); - setUsage(null); - setLastFetchedAt(null); - setStatus("idle"); - setError(null); - }, []); - - return { - auth, - usage, - lastFetchedAt, - status, - error, - importAuthFile, - refresh, - reloadCredentials, - clearAuth, - }; -} diff --git a/hooks/useNotificationSettings.ts b/hooks/useNotificationSettings.ts deleted file mode 100644 index f044648..0000000 --- a/hooks/useNotificationSettings.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { - loadNotifSettings, - saveNotifSettings, - type NotifSettings, -} from "@/lib/storage"; -import { - requestPermissions, - getPermissionStatus, - scheduleDailyDigest, - cancelDailyDigest, -} from "@/lib/notifications"; - -export function useNotificationSettings() { - const [settings, setSettings] = useState({ - dailyEnabled: false, - dailyHour: 9, - dailyMinute: 0, - thresholdEnabled: false, - thresholdPct: 20, - }); - const [permissionStatus, setPermissionStatus] = useState("undetermined"); - const [loaded, setLoaded] = useState(false); - - useEffect(() => { - Promise.all([loadNotifSettings(), getPermissionStatus()]).then( - ([stored, status]) => { - setSettings(stored); - setPermissionStatus(status); - setLoaded(true); - } - ); - }, []); - - const askPermissions = useCallback(async (): Promise => { - const granted = await requestPermissions(); - setPermissionStatus(granted ? "granted" : "denied"); - return granted; - }, []); - - const update = useCallback( - async (patch: Partial) => { - const next = { ...settings, ...patch }; - setSettings(next); - await saveNotifSettings(next); - - // Keep scheduled notification in sync when toggling or changing time - const dailyChanged = - "dailyEnabled" in patch || - "dailyHour" in patch || - "dailyMinute" in patch; - if (dailyChanged) { - if (next.dailyEnabled) { - await scheduleDailyDigest(next.dailyHour, next.dailyMinute, null, null); - } else { - await cancelDailyDigest(); - } - } - }, - [settings] - ); - - return { settings, permissionStatus, loaded, askPermissions, update }; -} diff --git a/index.ts b/index.ts deleted file mode 100644 index 1d6e981..0000000 --- a/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -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/lib/api/claudeApi.ts b/lib/api/claudeApi.ts deleted file mode 100644 index a89bce6..0000000 --- a/lib/api/claudeApi.ts +++ /dev/null @@ -1,127 +0,0 @@ -import type { ClaudeAuth, ClaudeOrg, ClaudeUsageResponse } from "@/types/claude"; - -const BASE_URL = "https://claude.ai/api"; - -const BROWSER_UA = - "Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36"; - -function buildHeaders(auth: ClaudeAuth): Record { - const cookies = [`sessionKey=${auth.sessionKey}`]; - if (auth.lastActiveOrg) cookies.push(`lastActiveOrg=${auth.lastActiveOrg}`); - return { - Cookie: cookies.join("; "), - Accept: "application/json, text/plain, */*", - "Accept-Language": "en-US,en;q=0.9", - "User-Agent": BROWSER_UA, - Referer: "https://claude.ai/", - Origin: "https://claude.ai", - "anthropic-client-platform": "web_claude_to_cc_migration", - }; -} - -function isClaudeWindow(value: unknown): boolean { - if (!value || typeof value !== "object") return false; - const window = value as Record; - return ( - typeof window.utilization === "number" && - Number.isFinite(window.utilization) && - (window.resets_at === undefined || - window.resets_at === null || - typeof window.resets_at === "string") - ); -} - -export function parseClaudeOrgsResponse(data: unknown): ClaudeOrg[] { - if ( - !Array.isArray(data) || - data.some( - (org) => - !org || - typeof org !== "object" || - typeof (org as Record).uuid !== "string" || - typeof (org as Record).name !== "string" - ) - ) { - throw new Error("INVALID_CLAUDE_ORGS_RESPONSE"); - } - return data.map((org) => { - const value = org as Record; - return { uuid: value.uuid as string, name: value.name as string }; - }); -} - -export function parseClaudeUsageResponse(data: unknown): ClaudeUsageResponse { - if (!data || typeof data !== "object") { - throw new Error("INVALID_CLAUDE_RESPONSE"); - } - - const value = data as Record; - if ( - !isClaudeWindow(value.five_hour) || - !isClaudeWindow(value.seven_day) || - (value.seven_day_sonnet !== undefined && - value.seven_day_sonnet !== null && - !isClaudeWindow(value.seven_day_sonnet)) || - (value.seven_day_opus !== undefined && - value.seven_day_opus !== null && - !isClaudeWindow(value.seven_day_opus)) - ) { - throw new Error("INVALID_CLAUDE_RESPONSE"); - } - - const toWindow = (window: unknown) => { - const item = window as Record; - return { - utilization: item.utilization as number, - ...(typeof item.resets_at === "string" - ? { resets_at: item.resets_at } - : {}), - }; - }; - - return { - five_hour: toWindow(value.five_hour), - seven_day: toWindow(value.seven_day), - ...(value.seven_day_sonnet - ? { seven_day_sonnet: toWindow(value.seven_day_sonnet) } - : {}), - ...(value.seven_day_opus - ? { seven_day_opus: toWindow(value.seven_day_opus) } - : {}), - }; -} - -export async function fetchClaudeOrgs(auth: ClaudeAuth): Promise { - const response = await fetch(`${BASE_URL}/organizations`, { - headers: buildHeaders(auth), - credentials: "omit", - }); - - if (!response.ok) { - await response.text().catch(() => null); - if (response.status === 401 || response.status === 403) throw new Error("TOKEN_EXPIRED"); - throw new Error(`HTTP_ERROR_${response.status}`); - } - - const data: unknown = await response.json(); - return parseClaudeOrgsResponse(data); -} - -export async function fetchClaudeUsage( - auth: ClaudeAuth, - orgUuid: string -): Promise { - const response = await fetch(`${BASE_URL}/organizations/${orgUuid}/usage`, { - headers: buildHeaders(auth), - credentials: "omit", - }); - - if (!response.ok) { - await response.text().catch(() => null); - if (response.status === 401 || response.status === 403) throw new Error("TOKEN_EXPIRED"); - throw new Error(`HTTP_ERROR_${response.status}`); - } - - const data: unknown = await response.json(); - return parseClaudeUsageResponse(data); -} diff --git a/lib/api/codexApi.ts b/lib/api/codexApi.ts deleted file mode 100644 index 0ed5c01..0000000 --- a/lib/api/codexApi.ts +++ /dev/null @@ -1,215 +0,0 @@ -import type { CodexAuth, CodexUsageResponse } from "@/types/codex"; - -const USAGE_URL = "https://chatgpt.com/backend-api/wham/usage"; -const RESET_CREDITS_URL = - "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits"; - -interface RawUsageWindow { - used_percent?: number; - limit_window_seconds?: number; - reset_at?: number; -} - -interface RawUsageResponse { - plan_type?: string | null; - rate_limit?: { - primary_window?: RawUsageWindow | null; - secondary_window?: RawUsageWindow | null; - } | null; - credits?: { - has_credits?: boolean; - unlimited?: boolean; - balance?: string | number; - } | null; - rate_limit_reached_type?: string | null; - rate_limit_reset_credits?: { - available_count?: number | null; - } | null; -} - -interface RawResetCredit { - status?: string; - granted_at?: string | null; - expires_at?: string | null; -} - -interface RawResetCreditsResponse { - available_count?: number | null; - total_earned_count?: number | null; - credits?: RawResetCredit[] | null; -} - -function isNumber(value: unknown): value is number { - return typeof value === "number" && Number.isFinite(value); -} - -function formatDurationUntil(isoString: string | null | undefined): string | null { - if (!isoString) return null; - - const targetMs = new Date(isoString).getTime(); - if (Number.isNaN(targetMs)) return null; - - let remainingSeconds = Math.max(Math.round((targetMs - Date.now()) / 1000), 0); - const days = Math.floor(remainingSeconds / 86400); - remainingSeconds -= days * 86400; - const hours = Math.floor(remainingSeconds / 3600); - remainingSeconds -= hours * 3600; - const minutes = Math.floor(remainingSeconds / 60); - remainingSeconds -= minutes * 60; - - const parts: string[] = []; - if (days > 0) parts.push(`${days}d`); - if (hours > 0) parts.push(`${hours}h`); - if (minutes > 0) parts.push(`${minutes}m`); - if (remainingSeconds > 0 || parts.length === 0) parts.push(`${remainingSeconds}s`); - return parts.join(" "); -} - -function normalizeWindow(window: RawUsageWindow | null | undefined) { - if (!window) return null; - - const windowSeconds = - typeof window.limit_window_seconds === "number" ? window.limit_window_seconds : 0; - const resetsAt = typeof window.reset_at === "number" ? window.reset_at : 0; - - return { - usedPercent: typeof window.used_percent === "number" ? window.used_percent : 0, - resetsAt, - windowMinutes: Math.round(windowSeconds / 60), - windowSeconds, - }; -} - -function buildBaseHeaders(auth: CodexAuth): Record { - const headers: Record = { - Authorization: `Bearer ${auth.accessToken}`, - "Content-Type": "application/json", - }; - - if (auth.accountId) { - headers["ChatGPT-Account-Id"] = auth.accountId; - } - - return headers; -} - -async function fetchResetCoupons(auth: CodexAuth, usage: RawUsageResponse) { - const headers = { - ...buildBaseHeaders(auth), - "OpenAI-Beta": "codex-1", - originator: "Codex Desktop", - }; - - try { - const response = await fetch(RESET_CREDITS_URL, { headers }); - if (!response.ok) { - throw new Error(`HTTP_ERROR_${response.status}`); - } - - const payload = (await response.json()) as RawResetCreditsResponse; - const credits = Array.isArray(payload.credits) ? payload.credits : []; - const normalizedCredits = credits - .map((credit, index) => ({ - index: index + 1, - status: credit.status, - grantedAt: credit.granted_at ?? null, - grantedAtLocal: credit.granted_at - ? new Date(credit.granted_at).toLocaleString() - : null, - expiresAt: credit.expires_at ?? null, - expiresAtLocal: credit.expires_at - ? new Date(credit.expires_at).toLocaleString() - : null, - timeUntilExpiry: formatDurationUntil(credit.expires_at), - })) - .sort((a, b) => { - const left = a.expiresAt ? new Date(a.expiresAt).getTime() : Number.MAX_SAFE_INTEGER; - const right = b.expiresAt ? new Date(b.expiresAt).getTime() : Number.MAX_SAFE_INTEGER; - return left - right; - }); - - const availableCredits = normalizedCredits.filter( - (credit) => credit.status === "available" - ); - - return { - source: "live_api" as const, - sourceDescription: "Live Codex reset-credit endpoint", - availableCount: - payload.available_count ?? usage.rate_limit_reset_credits?.available_count ?? null, - totalEarnedCount: payload.total_earned_count ?? null, - credits: normalizedCredits, - nextExpiringCredit: availableCredits[0] ?? normalizedCredits[0] ?? null, - }; - } catch (error) { - const message = error instanceof Error ? error.message : "UNKNOWN_ERROR"; - return { - source: "unavailable" as const, - sourceDescription: "Reset-credit endpoint unavailable", - availableCount: usage.rate_limit_reset_credits?.available_count ?? null, - fallbackReason: message, - error: message, - }; - } -} - -export function parseCodexUsageResponse(data: unknown): CodexUsageResponse { - if (!data || typeof data !== "object") { - throw new Error("INVALID_CODEX_RESPONSE"); - } - - const value = data as Record; - const primary = value.primary as Record | null | undefined; - const secondary = value.secondary as Record | null | undefined; - const credits = value.credits as Record | undefined; - - const validWindow = (window: Record | null | undefined) => - window === null || - window === undefined || - (isNumber(window.usedPercent) && - isNumber(window.resetsAt) && - isNumber(window.windowMinutes) && - isNumber(window.windowSeconds)); - - if ( - !validWindow(primary) || - !validWindow(secondary) || - !credits || - typeof credits.hasCredits !== "boolean" || - typeof credits.unlimited !== "boolean" || - !isNumber(credits.balance) - ) { - throw new Error("INVALID_CODEX_RESPONSE"); - } - - return value as unknown as CodexUsageResponse; -} - -export async function fetchCodexUsage(auth: CodexAuth): Promise { - const headers = buildBaseHeaders(auth); - const response = await fetch(USAGE_URL, { headers }); - - if (response.status === 401 || response.status === 403) { - throw new Error("TOKEN_EXPIRED"); - } - if (!response.ok) { - await response.text().catch(() => null); - throw new Error(`HTTP_ERROR_${response.status}`); - } - - const payload = (await response.json()) as RawUsageResponse; - const resetCoupons = await fetchResetCoupons(auth, payload); - - return { - planType: payload.plan_type ?? null, - rateLimitReachedType: payload.rate_limit_reached_type ?? null, - primary: normalizeWindow(payload.rate_limit?.primary_window), - secondary: normalizeWindow(payload.rate_limit?.secondary_window), - credits: { - hasCredits: Boolean(payload.credits?.has_credits), - unlimited: Boolean(payload.credits?.unlimited), - balance: Number(payload.credits?.balance ?? 0), - }, - resetCoupons, - }; -} diff --git a/lib/claudeCredentials.ts b/lib/claudeCredentials.ts deleted file mode 100644 index 46da57f..0000000 --- a/lib/claudeCredentials.ts +++ /dev/null @@ -1,19 +0,0 @@ -const CLAUDE_SESSION_KEY_PATTERN = /^sk-ant-[A-Za-z0-9_-]+$/; - -export function validateClaudeSessionKey(value: string): string | null { - const key = value.trim(); - if (!key.startsWith("sk-ant-")) { - return "Session key must start with sk-ant-"; - } - if (key.length <= 40) { - return "Session key looks too short. Paste the complete cookie value."; - } - if (!CLAUDE_SESSION_KEY_PATTERN.test(key)) { - return "Session key contains unexpected characters. Check the pasted value."; - } - return null; -} - -export function isClaudeSessionKeyValid(value: string): boolean { - return validateClaudeSessionKey(value) === null; -} diff --git a/lib/constants.ts b/lib/constants.ts deleted file mode 100644 index 2ca2a64..0000000 --- a/lib/constants.ts +++ /dev/null @@ -1,23 +0,0 @@ -export const COLORS = { - codex: "#10a37f", - claude: "#d97706", - danger: "#ef4444", - warning: "#f59e0b", - disabled: "#e5e5e5", - muted: "#a3a3a3", - appBackground: "#090d11", -} as const; - -export const PROGRESS_THRESHOLDS = { - warning: 60, - danger: 85, -} as const; - -export const COUNTDOWN_INTERVAL_MS = 60_000; -export const RETRY_DELAY_MS = 5_000; - -export function getUsageColor(percent: number): string { - if (percent >= PROGRESS_THRESHOLDS.danger) return COLORS.danger; - if (percent >= PROGRESS_THRESHOLDS.warning) return COLORS.warning; - return COLORS.codex; -} diff --git a/lib/fileReader.ts b/lib/fileReader.ts deleted file mode 100644 index 3541d09..0000000 --- a/lib/fileReader.ts +++ /dev/null @@ -1,70 +0,0 @@ -import * as DocumentPicker from "expo-document-picker"; -import * as LegacyFileSystem from "expo-file-system/legacy"; -import type { CodexAuth } from "@/types/codex"; - -function sanitizeFileName(name: string): string { - return name.replace(/[^a-zA-Z0-9._-]/g, "_"); -} - -async function readPickedTextFile(uri: string, fileName?: string): Promise { - try { - const response = await fetch(uri); - if (!response.ok) { - throw new Error(`HTTP_ERROR_${response.status}`); - } - return await response.text(); - } catch { - try { - return await LegacyFileSystem.readAsStringAsync(uri); - } catch { - const cacheDirectory = LegacyFileSystem.cacheDirectory; - if (!cacheDirectory) { - throw new Error("DOCUMENT_NOT_READABLE"); - } - - const destination = `${cacheDirectory}${Date.now()}-${sanitizeFileName( - fileName ?? "import.json" - )}`; - - try { - await LegacyFileSystem.copyAsync({ from: uri, to: destination }); - return await LegacyFileSystem.readAsStringAsync(destination); - } catch { - throw new Error("DOCUMENT_NOT_READABLE"); - } - } - } -} - -export async function pickAndReadCodexAuth(): Promise { - const result = await DocumentPicker.getDocumentAsync({ - type: "application/json", - copyToCacheDirectory: true, - }); - - if (result.canceled) throw new Error("PICKER_CANCELLED"); - - const { uri, name } = result.assets[0]; - const text = await readPickedTextFile(uri, name); - - let parsed: Record; - try { - parsed = JSON.parse(text); - } catch { - throw new Error("INVALID_JSON"); - } - - const tokens = parsed["tokens"] as Record | undefined; - const accessToken = (tokens?.["access_token"] ?? parsed["accessToken"]) as string | undefined; - const accountId = ( - tokens?.["account_id"] ?? - parsed["accountId"] ?? - parsed["account_id"] - ) as string | undefined; - - if (!accessToken || typeof accessToken !== "string") { - throw new Error("MISSING_ACCESS_TOKEN"); - } - - return { accessToken, accountId }; -} diff --git a/lib/notifications.ts b/lib/notifications.ts deleted file mode 100644 index 29f6358..0000000 --- a/lib/notifications.ts +++ /dev/null @@ -1,160 +0,0 @@ -import type * as NotificationsType from "expo-notifications"; -import { - loadNotifSettings, - loadNotifThresholdLastFired, - saveNotifThresholdLastFired, -} from "@/lib/storage"; -import type { ClaudeUsageResponse } from "@/types/claude"; -import type { CodexUsageResponse } from "@/types/codex"; - -// expo-notifications push notifications were removed from Expo Go in SDK 53. -// Use require() so the initialization error is caught gracefully in Expo Go. -let Notifications: typeof NotificationsType | null = null; -try { - Notifications = require("expo-notifications") as typeof NotificationsType; - Notifications.setNotificationHandler({ - handleNotification: async () => ({ - shouldShowAlert: true, - shouldShowBanner: true, - shouldShowList: true, - shouldPlaySound: false, - shouldSetBadge: false, - }), - }); -} catch { - // Running in Expo Go or native module unavailable — notifications disabled. -} - -export async function requestPermissions(): Promise { - if (!Notifications) return false; - const { status } = await Notifications.requestPermissionsAsync(); - return status === "granted"; -} - -export async function getPermissionStatus(): Promise { - if (!Notifications) return "undetermined"; - const { status } = await Notifications.getPermissionsAsync(); - return status; -} - -const DAILY_ID = "codexbar-daily-digest"; - -export async function scheduleDailyDigest( - hour: number, - minute: number, - claudeUsage: ClaudeUsageResponse | null, - codexUsage: CodexUsageResponse | null -): Promise { - if (!Notifications) return; - try { - await Notifications.cancelScheduledNotificationAsync(DAILY_ID); - } catch {} - - const parts: string[] = []; - if (claudeUsage) { - parts.push(`Claude 7d: ${Math.round(claudeUsage.seven_day.utilization)}% used`); - } - if (codexUsage) { - parts.push( - `Codex: ${Math.round(codexUsage.secondary?.usedPercent ?? 0)}% used` - ); - } - - await Notifications.scheduleNotificationAsync({ - identifier: DAILY_ID, - content: { - title: "Usage Digest", - body: - parts.length > 0 - ? parts.join(" · ") - : "Open to check your usage limits", - }, - trigger: { - type: Notifications.SchedulableTriggerInputTypes.CALENDAR, - hour, - minute, - repeats: true, - }, - }); -} - -export async function cancelDailyDigest(): Promise { - if (!Notifications) return; - try { - await Notifications.cancelScheduledNotificationAsync(DAILY_ID); - } catch {} -} - -interface ThresholdAlert { - service: string; - window: string; - remaining: number; -} - -function buildThresholdAlerts( - thresholdPct: number, - claudeUsage: ClaudeUsageResponse | null, - codexUsage: CodexUsageResponse | null -): ThresholdAlert[] { - const alerts: ThresholdAlert[] = []; - - if (claudeUsage) { - const remaining = 100 - claudeUsage.seven_day.utilization; - if (remaining <= thresholdPct) { - alerts.push({ service: "Claude", window: "7-day", remaining }); - } - } - - if (codexUsage) { - const remaining = 100 - (codexUsage.secondary?.usedPercent ?? 0); - if (remaining <= thresholdPct) { - alerts.push({ service: "Codex", window: "weekly", remaining }); - } - } - - return alerts; -} - -/** Call this after every successful usage fetch. Reschedules daily digest and fires threshold alerts. */ -export async function onUsageDataLoaded( - claudeUsage: ClaudeUsageResponse | null, - codexUsage: CodexUsageResponse | null -): Promise { - const settings = await loadNotifSettings(); - - if (settings.dailyEnabled) { - await scheduleDailyDigest( - settings.dailyHour, - settings.dailyMinute, - claudeUsage, - codexUsage - ); - } - - if (settings.thresholdEnabled) { - const today = new Date().toISOString().slice(0, 10); - const lastFired = await loadNotifThresholdLastFired(); - if (lastFired !== today) { - const alerts = buildThresholdAlerts( - settings.thresholdPct, - claudeUsage, - codexUsage - ); - if (alerts.length > 0 && Notifications) { - await Notifications.scheduleNotificationAsync({ - content: { - title: "Low quota warning", - body: alerts - .map( - (a) => - `${a.service} ${a.window}: ${Math.round(a.remaining)}% remaining` - ) - .join("\n"), - }, - trigger: null, - }); - await saveNotifThresholdLastFired(today); - } - } - } -} diff --git a/lib/setupState.ts b/lib/setupState.ts deleted file mode 100644 index f1e05f4..0000000 --- a/lib/setupState.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as SecureStore from "expo-secure-store"; - -const KEY = "codexbar_onboarding_v1"; - -export async function hasCompletedOnboarding(): Promise { - const val = await SecureStore.getItemAsync(KEY); - return val === "done"; -} - -export async function markOnboardingComplete(): Promise { - await SecureStore.setItemAsync(KEY, "done"); -} - -export async function resetOnboarding(): Promise { - await SecureStore.deleteItemAsync(KEY); -} diff --git a/lib/storage.ts b/lib/storage.ts deleted file mode 100644 index 31f6f14..0000000 --- a/lib/storage.ts +++ /dev/null @@ -1,159 +0,0 @@ -import * as SecureStore from "expo-secure-store"; -import type { ClaudeUsageResponse } from "@/types/claude"; -import type { CodexUsageResponse } from "@/types/codex"; - -const KEYS = { - CODEX_AUTH: "codexbar_codex_auth", - CLAUDE_SESSION_KEY: "codexbar_claude_session_key", - CLAUDE_LAST_ACTIVE_ORG: "codexbar_claude_last_active_org", - CODEX_USAGE_CACHE: "codexbar_codex_usage_cache", - CLAUDE_USAGE_CACHE: "codexbar_claude_usage_cache", - NOTIF_DAILY_ENABLED: "notifDailyEnabled", - NOTIF_DAILY_HOUR: "notifDailyHour", - NOTIF_DAILY_MINUTE: "notifDailyMinute", - NOTIF_THRESHOLD_ENABLED: "notifThresholdEnabled", - NOTIF_THRESHOLD_PCT: "notifThresholdPct", - NOTIF_THRESHOLD_LAST_FIRED: "notifThresholdLastFired", -} as const; - -export interface UsageCache { - data: T; - lastFetchedAt: number; -} - -async function loadJson(key: string): Promise { - const raw = await SecureStore.getItemAsync(key); - if (!raw) return null; - - try { - return JSON.parse(raw) as T; - } catch { - await SecureStore.deleteItemAsync(key); - return null; - } -} - -async function saveJson(key: string, value: unknown): Promise { - await SecureStore.setItemAsync(key, JSON.stringify(value)); -} - -export interface NotifSettings { - dailyEnabled: boolean; - dailyHour: number; - dailyMinute: number; - thresholdEnabled: boolean; - /** Alert when remaining quota falls below this % (e.g. 20 = fire when < 20% left) */ - thresholdPct: number; -} - -export async function loadNotifSettings(): Promise { - const [de, dh, dm, te, tp] = await Promise.all([ - SecureStore.getItemAsync(KEYS.NOTIF_DAILY_ENABLED), - SecureStore.getItemAsync(KEYS.NOTIF_DAILY_HOUR), - SecureStore.getItemAsync(KEYS.NOTIF_DAILY_MINUTE), - SecureStore.getItemAsync(KEYS.NOTIF_THRESHOLD_ENABLED), - SecureStore.getItemAsync(KEYS.NOTIF_THRESHOLD_PCT), - ]); - return { - dailyEnabled: de === "true", - dailyHour: dh !== null ? parseInt(dh, 10) : 9, - dailyMinute: dm !== null ? parseInt(dm, 10) : 0, - thresholdEnabled: te === "true", - thresholdPct: tp !== null ? parseInt(tp, 10) : 20, - }; -} - -export async function saveNotifSettings(s: NotifSettings): Promise { - await Promise.all([ - SecureStore.setItemAsync(KEYS.NOTIF_DAILY_ENABLED, String(s.dailyEnabled)), - SecureStore.setItemAsync(KEYS.NOTIF_DAILY_HOUR, String(s.dailyHour)), - SecureStore.setItemAsync(KEYS.NOTIF_DAILY_MINUTE, String(s.dailyMinute)), - SecureStore.setItemAsync(KEYS.NOTIF_THRESHOLD_ENABLED, String(s.thresholdEnabled)), - SecureStore.setItemAsync(KEYS.NOTIF_THRESHOLD_PCT, String(s.thresholdPct)), - ]); -} - -export async function loadNotifThresholdLastFired(): Promise { - return SecureStore.getItemAsync(KEYS.NOTIF_THRESHOLD_LAST_FIRED); -} - -export async function saveNotifThresholdLastFired(date: string): Promise { - await SecureStore.setItemAsync(KEYS.NOTIF_THRESHOLD_LAST_FIRED, date); -} - -export async function saveCodexAuth(auth: { - accessToken: string; - accountId?: string; -}): Promise { - await saveJson(KEYS.CODEX_AUTH, auth); -} - -export async function loadCodexAuth(): Promise<{ - accessToken: string; - accountId?: string; -} | null> { - return loadJson(KEYS.CODEX_AUTH); -} - -export function loadCodexUsageCache(): Promise | null> { - return loadJson(KEYS.CODEX_USAGE_CACHE); -} - -export function saveCodexUsageCache( - cache: UsageCache -): Promise { - return saveJson(KEYS.CODEX_USAGE_CACHE, cache); -} - -export function clearCodexUsageCache(): Promise { - return SecureStore.deleteItemAsync(KEYS.CODEX_USAGE_CACHE); -} - -export function loadClaudeUsageCache(): Promise | null> { - return loadJson(KEYS.CLAUDE_USAGE_CACHE); -} - -export function saveClaudeUsageCache( - cache: UsageCache -): Promise { - return saveJson(KEYS.CLAUDE_USAGE_CACHE, cache); -} - -export function clearClaudeUsageCache(): Promise { - return SecureStore.deleteItemAsync(KEYS.CLAUDE_USAGE_CACHE); -} - -export async function saveClaudeSessionKey(key: string): Promise { - await SecureStore.setItemAsync(KEYS.CLAUDE_SESSION_KEY, key.trim()); -} - -export async function loadClaudeSessionKey(): Promise { - return SecureStore.getItemAsync(KEYS.CLAUDE_SESSION_KEY); -} - -export async function saveClaudeLastActiveOrg(orgId: string): Promise { - await SecureStore.setItemAsync(KEYS.CLAUDE_LAST_ACTIVE_ORG, orgId.trim()); -} - -export async function loadClaudeLastActiveOrg(): Promise { - return SecureStore.getItemAsync(KEYS.CLAUDE_LAST_ACTIVE_ORG); -} - -export async function clearClaudeLastActiveOrg(): Promise { - await SecureStore.deleteItemAsync(KEYS.CLAUDE_LAST_ACTIVE_ORG); -} - -export async function clearCodexAuth(): Promise { - await Promise.all([ - SecureStore.deleteItemAsync(KEYS.CODEX_AUTH), - clearCodexUsageCache(), - ]); -} - -export async function clearClaudeSessionKey(): Promise { - await Promise.all([ - SecureStore.deleteItemAsync(KEYS.CLAUDE_SESSION_KEY), - SecureStore.deleteItemAsync(KEYS.CLAUDE_LAST_ACTIVE_ORG), - clearClaudeUsageCache(), - ]); -} diff --git a/lib/timeUtils.ts b/lib/timeUtils.ts deleted file mode 100644 index b5bf488..0000000 --- a/lib/timeUtils.ts +++ /dev/null @@ -1,66 +0,0 @@ -export function formatResetCountdown(resetAtSeconds: number): string { - const nowSeconds = Math.floor(Date.now() / 1000); - const diffSeconds = resetAtSeconds - nowSeconds; - - if (diffSeconds <= 0) return "resetting now"; - if (diffSeconds < 60) return "resets in <1m"; - - const totalHours = Math.floor(diffSeconds / 3600); - const minutes = Math.floor((diffSeconds % 3600) / 60); - - if (totalHours >= 24) { - const days = Math.floor(totalHours / 24); - const hours = totalHours % 24; - if (hours > 0) return `resets in ${days}d ${hours}h`; - return `resets in ${days}d`; - } - if (totalHours > 0 && minutes > 0) return `resets in ${totalHours}h ${minutes}m`; - if (totalHours > 0) return `resets in ${totalHours}h`; - return `resets in ${minutes}m`; -} - -export function parseTimeInput( - value: string -): { hour: number; minute: number } | null { - const match = value.trim().match(/^(\d{1,2}):(\d{2})$/); - if (!match) return null; - - const hour = Number.parseInt(match[1], 10); - const minute = Number.parseInt(match[2], 10); - if (hour > 23 || minute > 59) return null; - - return { hour, minute }; -} - -export function formatTime(hour: number, minute: number): string { - return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`; -} - -export function formatLastUpdated(timestamp: number, now = Date.now()): string { - const elapsedSeconds = Math.max(0, Math.floor((now - timestamp) / 1000)); - if (elapsedSeconds < 60) return "Updated just now"; - - const minutes = Math.floor(elapsedSeconds / 60); - if (minutes < 60) return `Updated ${minutes} min ago`; - - const hours = Math.floor(minutes / 60); - if (hours < 24) return `Updated ${hours} hr${hours === 1 ? "" : "s"} ago`; - - const days = Math.floor(hours / 24); - return `Updated ${days} day${days === 1 ? "" : "s"} ago`; -} - -export function formatResetCountdownISO(isoString: string): string { - const resetAtSeconds = Math.floor(new Date(isoString).getTime() / 1000); - return formatResetCountdown(resetAtSeconds); -} - -export function windowLabel(limitWindowSeconds: number): string { - const hours = limitWindowSeconds / 3600; - if (hours < 24) return `${Math.round(hours)}h`; - const days = hours / 24; - const wholeDays = Math.floor(days); - const remainderHours = Math.round(hours - wholeDays * 24); - if (remainderHours === 0) return `${wholeDays}d`; - return `${wholeDays}d ${remainderHours}h`; -} diff --git a/metro.config.js b/metro.config.js deleted file mode 100644 index b0963fe..0000000 --- a/metro.config.js +++ /dev/null @@ -1,6 +0,0 @@ -const { getDefaultConfig } = require("expo/metro-config"); -const { withNativeWind } = require("nativewind/metro"); - -const config = getDefaultConfig(__dirname); - -module.exports = withNativeWind(config, { input: "./global.css" }); diff --git a/nativewind-env.d.ts b/nativewind-env.d.ts deleted file mode 100644 index 250fbd3..0000000 --- a/nativewind-env.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/// - -declare module "*.css" { - const content: unknown; - export default content; -} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 3d6d179..0000000 --- a/package-lock.json +++ /dev/null @@ -1,8792 +0,0 @@ -{ - "name": "codexbar.mobile", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "codexbar.mobile", - "version": "1.0.0", - "dependencies": { - "@expo/metro-runtime": "~56.0.15", - "@expo/vector-icons": "^15.1.1", - "babel-preset-expo": "~56.0.0", - "expo": "~56.0.14", - "expo-constants": "~56.0.20", - "expo-document-picker": "~56.0.4", - "expo-file-system": "~56.0.8", - "expo-font": "~56.0.7", - "expo-linking": "~56.0.15", - "expo-notifications": "~56.0.19", - "expo-router": "~56.2.13", - "expo-secure-store": "~56.0.4", - "expo-splash-screen": "~56.0.10", - "expo-status-bar": "~56.0.4", - "expo-system-ui": "~56.0.5", - "expo-updates": "~56.0.21", - "nativewind": "^4.2.6", - "react": "19.2.3", - "react-dom": "^19.2.3", - "react-native": "0.85.3", - "react-native-reanimated": "4.3.1", - "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "4.25.2", - "react-native-web": "^0.21.2", - "react-native-worklets": "^0.8.3" - }, - "devDependencies": { - "@types/react": "~19.2.2", - "tailwindcss": "^3.4.19", - "typescript": "~6.0.3" - } - }, - "node_modules/@adobe/css-tools": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", - "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", - "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==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", - "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", - "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/traverse": "^7.29.7", - "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.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", - "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "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.8", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", - "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", - "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.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", - "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", - "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", - "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-wrap-function": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", - "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", - "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", - "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz", - "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-syntax-decorators": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.29.7.tgz", - "integrity": "sha512-p+G5BNXDcy3bOXplhY4HybQ1GxH3i2Tppmdm/3epyRu2VgJJZuUlZ61MqRTg582Q7ZLBdP7fePYvsumSEkMxcQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz", - "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-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", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-default-from": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.29.7.tgz", - "integrity": "sha512-foag0BB37ROhdeIX9O8G0jX7hw0UekJc04cHMrYLOnrErsnBKqJGHJ8eDRpoCFZBvEPPygmmtw4qyU97qa4oOw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.29.7.tgz", - "integrity": "sha512-ajMX6QPcyomotqwpzhkYGxcK2i/us0rs1Qo9QvUpa+Fca0FTmqrzKrctoIYLMxcOhGZldGT/BAVkRGTWBiR8gQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", - "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-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/@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", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", - "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", - "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", - "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", - "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", - "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", - "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", - "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", - "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", - "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", - "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.29.7.tgz", - "integrity": "sha512-wRHeUjUjCZnMHmiO5bRgjFLcoEh7JyTdByOW11ahhwNa4V0bmeGEaIvt51yq0zQp2yWIpqfxXXPyUP6GFJZHOQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-syntax-flow": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", - "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", - "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", - "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", - "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", - "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", - "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7", - "@babel/plugin-transform-parameters": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", - "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", - "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", - "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", - "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", - "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz", - "integrity": "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz", - "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-syntax-jsx": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz", - "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==", - "license": "MIT", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", - "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", - "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz", - "integrity": "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", - "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.7.tgz", - "integrity": "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "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.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", - "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", - "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", - "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/plugin-syntax-typescript": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", - "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", - "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-syntax-jsx": "^7.29.7", - "@babel/plugin-transform-modules-commonjs": "^7.29.7", - "@babel/plugin-transform-typescript": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@expo-google-fonts/material-symbols": { - "version": "0.4.38", - "resolved": "https://registry.npmjs.org/@expo-google-fonts/material-symbols/-/material-symbols-0.4.38.tgz", - "integrity": "sha512-IJkBtN1o8u9BW5fvSii1MyHPQ7Q0HxbWcVBvOrOzgMLpVtZw7R2w94wBTVR7kZwv3w1JNTESMmLA5Sqn1+Z36A==", - "license": "MIT AND Apache-2.0" - }, - "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": "56.0.11", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-56.0.11.tgz", - "integrity": "sha512-Rt3U9Rqr6midz/sDeubFN5fefR0KzHpcEEgAUnV98XsLSSTnfzIxoC1blICb7pUUscKc8TtlVyn7/Gita2wnOQ==", - "license": "MIT", - "dependencies": { - "@expo/config-plugins": "~56.0.11", - "@expo/config-types": "^56.0.7", - "@expo/json-file": "^10.2.0", - "@expo/require-utils": "^56.1.4", - "deepmerge": "^4.3.1", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "resolve-workspace-root": "^2.0.0", - "semver": "^7.6.0", - "slugify": "^1.3.4" - } - }, - "node_modules/@expo/config-plugins": { - "version": "56.0.11", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-56.0.11.tgz", - "integrity": "sha512-be/FpnTUCY0Qt6OH9qFknj9/R7v0OW0Tsxkf/V0CkXuhHjZtL3J8N4kZhhDj5KiHnw7lkbtMvgxGnCHqieF/7g==", - "license": "MIT", - "dependencies": { - "@expo/config-types": "^56.0.7", - "@expo/json-file": "~10.2.0", - "@expo/plist": "^0.7.0", - "@expo/require-utils": "^56.1.4", - "@expo/sdk-runtime-versions": "^1.0.0", - "chalk": "^4.1.2", - "debug": "^4.3.5", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "semver": "^7.5.4", - "slugify": "^1.6.6", - "xcode": "^3.0.1", - "xml2js": "0.6.0" - } - }, - "node_modules/@expo/config-types": { - "version": "56.0.7", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-56.0.7.tgz", - "integrity": "sha512-V7bxawNsNned/yMppAHdisIOxniZXgPKRWpIUiQOQBs45/A5MBd2gfDM4Ecq5gnbilnQUTaI6Zxn6JcW7L3TAA==", - "license": "MIT" - }, - "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/devtools": { - "version": "56.0.2", - "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-56.0.2.tgz", - "integrity": "sha512-ANl4kPdbe0/HQYWkDEN79S6bQhI+i/ZCnPxuC853pPsB4svhINC7Ku9lmGOKPsUUWWnrHg1spkDGQBZ4sD6JxQ==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/@expo/dom-webview": { - "version": "56.0.6", - "resolved": "https://registry.npmjs.org/@expo/dom-webview/-/dom-webview-56.0.6.tgz", - "integrity": "sha512-DQY3Tj5nrPbpIfEQiD9xbyEFTu25yEORa02Eyzl5rXszDzxDT4VkZDHkyErNQOyE1qjublJHNFhE5bDm4tRfqA==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/@expo/env": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.3.1.tgz", - "integrity": "sha512-JvBdZa5OkTd+dGEtt3fLW9OF6RlIp9SNu9VyMSiWPV5szMDTSAYbX8Uj3cRvZcU1zzaRbqnTSsHk2AE8WXHfxQ==", - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "debug": "^4.3.4", - "getenv": "^2.0.0" - }, - "engines": { - "node": ">=20.12.0" - } - }, - "node_modules/@expo/expo-modules-macros-plugin": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@expo/expo-modules-macros-plugin/-/expo-modules-macros-plugin-0.2.2.tgz", - "integrity": "sha512-4IMzPDIo/VOXREQjsJtliSfqYVZvfzU2SLFS/9sKMWF848S8CHx+e/E+Vf0TcMvpWCCKX5umyqxb13KJJ+YUzg==", - "license": "MIT" - }, - "node_modules/@expo/fingerprint": { - "version": "0.19.6", - "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.19.6.tgz", - "integrity": "sha512-qNcb/8aDVi1QeQzS6bSkKU/7vld8WUSHYZnZbOtJx98BroztcN50yoj7PZ3ccuMB7PUHsWNAHJVM94VvDWnPPw==", - "license": "MIT", - "dependencies": { - "@expo/env": "^2.3.1", - "@expo/spawn-async": "^1.8.0", - "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": "^10.2.2", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - }, - "bin": { - "fingerprint": "bin/cli.js" - } - }, - "node_modules/@expo/image-utils": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.10.2.tgz", - "integrity": "sha512-qQUGaacqXduoFTCUQAMceIWYzlKU0xX4/BKTyh8TdVj0uHv9/W3MfHOy5yXoOqBVrSccXk++Gm4D/NfS5HnCNA==", - "license": "MIT", - "dependencies": { - "@expo/require-utils": "^56.1.4", - "@expo/spawn-async": "^1.8.0", - "chalk": "^4.0.0", - "getenv": "^2.0.0", - "jimp-compact": "0.16.1", - "parse-png": "^2.1.0", - "semver": "^7.6.0" - } - }, - "node_modules/@expo/inline-modules": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/@expo/inline-modules/-/inline-modules-0.0.13.tgz", - "integrity": "sha512-26RllWesRmYsAAo70cRcR9DaqXPKJct9MIGxZteS+Tkg25ljOkFeG7fYEsSazZOLpAslKBiilqtZykVYrxSzCw==", - "license": "MIT", - "dependencies": { - "@expo/config-plugins": "~56.0.11" - } - }, - "node_modules/@expo/json-file": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.2.0.tgz", - "integrity": "sha512-S6XzKe3R9GQeHiUPXc3xJjOv2VJhOEwFYf7xdC2z2cUqt3kZJ9mSO877sNQloVdnW/SUCtPY3bexlM7nwq+CAQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "json5": "^2.2.3" - } - }, - "node_modules/@expo/local-build-cache-provider": { - "version": "56.0.9", - "resolved": "https://registry.npmjs.org/@expo/local-build-cache-provider/-/local-build-cache-provider-56.0.9.tgz", - "integrity": "sha512-VMJC5ul7dXPfD2OO16ObPi6ym4H8vlnCBUuCM/KeKh0OvLRub35X8OB2uYrFQ+vbWkPemAEOWvk0oOptpPxbzA==", - "license": "MIT", - "dependencies": { - "@expo/config": "~56.0.11", - "chalk": "^4.1.2" - } - }, - "node_modules/@expo/log-box": { - "version": "56.0.14", - "resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-56.0.14.tgz", - "integrity": "sha512-3Eadcxz0J2NESG2iKe8DnAggsRCWqY0mBLhgQPNzClPVjS6o4NyD0F8kuOvWNngFwpJBC08HhY2o8P1mgSgeJg==", - "license": "MIT", - "dependencies": { - "@expo/dom-webview": "^56.0.6", - "anser": "^1.4.9", - "stacktrace-parser": "^0.1.10" - }, - "peerDependencies": { - "@expo/dom-webview": "^56.0.6", - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/@expo/metro": { - "version": "56.0.0", - "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-56.0.0.tgz", - "integrity": "sha512-5gIgQHtEpjjvsjKfVtIv23a98LLRV0/y07PDShEwYSytAMlE3FSF8RHXqtHc1sUJL6dn7hnuIBpIbrLXXuVi0A==", - "license": "MIT", - "dependencies": { - "metro": "0.84.4", - "metro-babel-transformer": "0.84.4", - "metro-cache": "0.84.4", - "metro-cache-key": "0.84.4", - "metro-config": "0.84.4", - "metro-core": "0.84.4", - "metro-file-map": "0.84.4", - "metro-minify-terser": "0.84.4", - "metro-resolver": "0.84.4", - "metro-runtime": "0.84.4", - "metro-source-map": "0.84.4", - "metro-symbolicate": "0.84.4", - "metro-transform-plugins": "0.84.4", - "metro-transform-worker": "0.84.4" - } - }, - "node_modules/@expo/metro-config": { - "version": "56.0.16", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-56.0.16.tgz", - "integrity": "sha512-mxPZ23exC6kkEpPYQOteamaiWYER3uDk2IqKys7EJwtIKc3F1207Xtsdko/DNNG04DLwpN/WM2UlNl+Ak8uPRg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "@babel/core": "^7.20.0", - "@babel/generator": "^7.20.5", - "@expo/config": "~56.0.11", - "@expo/env": "~2.3.1", - "@expo/json-file": "~10.2.0", - "@expo/metro": "~56.0.0", - "@expo/require-utils": "^56.1.4", - "@expo/spawn-async": "^1.8.0", - "@jridgewell/gen-mapping": "^0.3.13", - "@jridgewell/remapping": "^2.3.5", - "@jridgewell/sourcemap-codec": "^1.5.5", - "browserslist": "^4.25.0", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "hermes-parser": "^0.33.3", - "jsc-safe-url": "^0.2.4", - "lightningcss": "^1.30.1", - "picomatch": "^4.0.4", - "postcss": "^8.5.14", - "resolve-from": "^5.0.0" - }, - "peerDependencies": { - "expo": "*" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - } - } - }, - "node_modules/@expo/metro-config/node_modules/hermes-estree": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", - "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", - "license": "MIT" - }, - "node_modules/@expo/metro-config/node_modules/hermes-parser": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", - "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.33.3" - } - }, - "node_modules/@expo/metro-config/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@expo/metro-file-map": { - "version": "56.0.3", - "resolved": "https://registry.npmjs.org/@expo/metro-file-map/-/metro-file-map-56.0.3.tgz", - "integrity": "sha512-5OGW3z8LgEYgMJOR7F3pC8llFLkb1fVqwAewbCl6S4Vkha8AFQMwOjT+9Wbka+V4rmpljpGqOnMhF4xZbD961w==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "fb-watchman": "^2.0.2", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "node_modules/@expo/metro-runtime": { - "version": "56.0.16", - "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-56.0.16.tgz", - "integrity": "sha512-UsKrBLOCa+kAVHW1S0HdGkM0hkiQXeh3fZIpjcriOmoNg/CVRgdKQhUxUkNoXAoPfT85uW1x2fzNbiYhPQO1SA==", - "license": "MIT", - "dependencies": { - "@expo/log-box": "^56.0.14", - "anser": "^1.4.9", - "pretty-format": "^29.7.0", - "stacktrace-parser": "^0.1.10", - "whatwg-fetch": "^3.0.0" - }, - "peerDependencies": { - "@expo/log-box": "^56.0.14", - "expo": "*", - "react": "*", - "react-dom": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/@expo/osascript": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.7.0.tgz", - "integrity": "sha512-wKIXL8UtbuX4KwavPasIW3CUcgTbYfjzLcgUhjyKUAYDEqMaf6gmU1bqz3ffBPTokmX+G8/vFG1ZuI9etQWukA==", - "license": "MIT", - "dependencies": { - "@expo/spawn-async": "^1.8.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@expo/package-manager": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.13.0.tgz", - "integrity": "sha512-s3W3eZafJDEyVL7W/jxj2Nz3eONKxSCU604S5xj8ijrVaRz83x0DnZznLf/UXQEI1w+FyibH68nHeQyk767b1A==", - "license": "MIT", - "dependencies": { - "@expo/json-file": "^11.0.0", - "@expo/spawn-async": "^1.8.0", - "chalk": "^4.0.0", - "npm-package-arg": "^11.0.0", - "ora": "^3.4.0", - "resolve-workspace-root": "^2.0.0" - } - }, - "node_modules/@expo/package-manager/node_modules/@expo/json-file": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.0.tgz", - "integrity": "sha512-pHJCETqFL5x5BzNV6cEPwjwuECgGmnl0bNmfHIJ6LM1tlh2eVXi5HEdit3zby/JO/B8Otk5cgcqtJXgvvUat3A==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "json5": "^2.2.3" - } - }, - "node_modules/@expo/plist": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.7.0.tgz", - "integrity": "sha512-vrpryU1GoqSIRNqRB2D3IjXDmzNYfiQpEF6AH/xknlD7eiYmEDt3mb26V7cLcedcPG8PY/1xWHdBXVQJfEAh6Q==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - } - }, - "node_modules/@expo/prebuild-config": { - "version": "56.0.18", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-56.0.18.tgz", - "integrity": "sha512-OnzuPMVUWbj8x5XeYkzxW4X36AUGkp1Kif2h9FrcyXNT67NoWOgxeTB8udQBBA1uodR+wcf8Hxz8H5TgIpp4ig==", - "license": "MIT", - "dependencies": { - "@expo/config": "~56.0.11", - "@expo/config-plugins": "~56.0.11", - "@expo/config-types": "^56.0.7", - "@expo/image-utils": "^0.10.2", - "@expo/json-file": "^10.2.0", - "@react-native/normalize-colors": "0.85.3", - "debug": "^4.3.1", - "expo-modules-autolinking": "~56.0.18", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - } - }, - "node_modules/@expo/require-utils": { - "version": "56.1.4", - "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-56.1.4.tgz", - "integrity": "sha512-IX7XXg9obnrH3ni0TClBbVKgqk0nT0bjTEPTBtbD+WgIeZ0hpcgwxMJH3j5uBsUqEAq1jqUAkJWrPcg7ZRSV7g==", - "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 || ^6.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@expo/schema-utils": { - "version": "56.0.2", - "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-56.0.2.tgz", - "integrity": "sha512-WcOH1E6rwxRqNwBzPOVhd5GBbMlS04+5n+ZMdhdwKOg/Kt3suV+F8F6An+z8mUJ8eSuMM3HD9Sj09t7vc/Xjkw==", - "license": "MIT" - }, - "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.8.0", - "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", - "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6" - }, - "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/ui": { - "version": "56.0.20", - "resolved": "https://registry.npmjs.org/@expo/ui/-/ui-56.0.20.tgz", - "integrity": "sha512-GdQ0tE4YhI/Ij0Nl/NHoul0GC0N4riRN0d7gE+1mSOLykVtHsR19eD3MUWr6PwQZCC45uUxviSJ9c3hOztswPw==", - "license": "MIT", - "dependencies": { - "sf-symbols-typescript": "^2.1.0", - "vaul": "^1.1.2" - }, - "peerDependencies": { - "@babel/core": "*", - "expo": "*", - "react": "*", - "react-dom": "*", - "react-native": "*", - "react-native-worklets": "*" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native-worklets": { - "optional": true - } - } - }, - "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/xcpretty": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.4.tgz", - "integrity": "sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==", - "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/@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/@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": { - "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/@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/@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==", - "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==", - "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==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz", - "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.11.tgz", - "integrity": "sha512-djW9+zeg137KQdlPtmE8xnaD+K2rcXXMWFrSg0hsmYZ6HRbdTA7tDHFgpaW9+huWVEu0RCabL+985T4TA0BE7g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", - "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.4.tgz", - "integrity": "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.18.tgz", - "integrity": "sha512-apa28mldjMgORmE6g/w3sCcA0Y9UAVeeDVoozN4i7kOw12mLl9RBchfzK3Nn6qxOWjrZhK1Lfy7f07kyzxtnBw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.14", - "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.11", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-portal": "1.1.13", - "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-slot": "1.3.0", - "@radix-ui/react-use-controllable-state": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.7.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", - "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.14.tgz", - "integrity": "sha512-4lUhWTWAjbDIqFrAPWJ3WqBOpO5YchVZ88X3nh6H9Lu5AFi5nCUeTPj3D8FSDmabmFeRe9ME0BDA4MwKTha5GQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-effect-event": "0.0.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz", - "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.11.tgz", - "integrity": "sha512-Mn88Vg2whaRocGJNOH+DKFqYm6ySFPQaiwHNxZPyjn99B52KAEJWWY9NP83+nWdk2HM3rdov+STu9AG471Rt9w==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.2.tgz", - "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.13.tgz", - "integrity": "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.6.tgz", - "integrity": "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.7.tgz", - "integrity": "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.14.tgz", - "integrity": "sha512-8Qcnx9447tx/aCBgw6Jenfqg4Skq+vqab9mCBmuGNipIS5YXvL275wbKEu7+ICYHIlAPgCduUMJH1XOYewKF6Q==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-collection": "1.1.11", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-use-callback-ref": "1.1.2", - "@radix-ui/react-use-controllable-state": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", - "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.16.tgz", - "integrity": "sha512-v3Ab2l7z6U7tRB4xA0IyKdq0OsqaO1o9ZjsIEoKKnSZ/l96mZz8aCTX0NCXw+YVHJXr8Km4d+Mn6/Q8YjXa+gw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.7", - "@radix-ui/react-roving-focus": "1.1.14", - "@radix-ui/react-use-controllable-state": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz", - "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", - "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.3", - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", - "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", - "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@react-native-masked-view/masked-view": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@react-native-masked-view/masked-view/-/masked-view-0.3.2.tgz", - "integrity": "sha512-XwuQoW7/GEgWRMovOQtX3A4PrXhyaZm0lVUiY8qJDvdngjLms9Cpdck6SmGAUNqQwcj2EadHC1HwL0bEyoa/SQ==", - "license": "MIT", - "peerDependencies": { - "react": ">=16", - "react-native": ">=0.57" - } - }, - "node_modules/@react-native/assets-registry": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.85.3.tgz", - "integrity": "sha512-u9ZiYP23vA2IFtdFQFmetzSmk6SM0xgKIoiOsr1hXNHjHaLhOm+/Ph1ud57wX6+Dbwdzx8coJgnzSKL3W21PCg==", - "license": "MIT", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/babel-plugin-codegen": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.85.3.tgz", - "integrity": "sha512-Wc94zGfeFG8Njf9SHMPfYZP04kjigkOps6F1TYTvd7ZVXuGxqseCDgxc50LWcOhOCLypI9n3oVVqz81C3p44ZA==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.0", - "@react-native/codegen": "0.85.3" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/babel-preset": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.85.3.tgz", - "integrity": "sha512-fD7fxEhkJB/aF57tWoXjaAWpklfrExYZS3k6aXPP3BQ77DZY7gvf/b7dbirwjID6NVnP1JDRJyTuPBGr0K/vlw==", - "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-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-destructuring": "^7.24.8", - "@babel/plugin-transform-flow-strip-types": "^7.25.2", - "@babel/plugin-transform-for-of": "^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-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@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-typescript": "^7.25.2", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@react-native/babel-plugin-codegen": "0.85.3", - "babel-plugin-syntax-hermes-parser": "0.33.3", - "babel-plugin-transform-flow-enums": "^0.0.2", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/@react-native/codegen": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.85.3.tgz", - "integrity": "sha512-/JkS1lGLyzBWP1FbgDwaqEf7qShIC6pUC1M0a/YMAd/v4iqR24MRkQWe7jkYvcBQ2LpEhs5NGE9InhxSv21zCA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/parser": "^7.29.0", - "hermes-parser": "0.33.3", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "tinyglobby": "^0.2.15", - "yargs": "^17.6.2" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/@react-native/codegen/node_modules/hermes-estree": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", - "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", - "license": "MIT" - }, - "node_modules/@react-native/codegen/node_modules/hermes-parser": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", - "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.33.3" - } - }, - "node_modules/@react-native/community-cli-plugin": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.85.3.tgz", - "integrity": "sha512-fs85dmbIqNmtzEixDb0g+q6R3Vt4H9eAt8/inIZdDKfjN76+sUJA2r1nxODQ76bU23MrIbz8sI7KFBPaWk/zQw==", - "license": "MIT", - "dependencies": { - "@react-native/dev-middleware": "0.85.3", - "debug": "^4.4.0", - "invariant": "^2.2.4", - "metro": "^0.84.3", - "metro-config": "^0.84.3", - "metro-core": "^0.84.3", - "semver": "^7.1.3" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@react-native-community/cli": "*", - "@react-native/metro-config": "0.85.3" - }, - "peerDependenciesMeta": { - "@react-native-community/cli": { - "optional": true - }, - "@react-native/metro-config": { - "optional": true - } - } - }, - "node_modules/@react-native/debugger-frontend": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.85.3.tgz", - "integrity": "sha512-uAu7rM5o/Np1zgp6fi5zM1sP1aB8DcS7DdOLcj/TkSutOAjkMqqd2lWt1/+3S7qXexRHVK5XcP+o3VXo4L/V0A==", - "license": "BSD-3-Clause", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/debugger-shell": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.85.3.tgz", - "integrity": "sha512-/jRAaT9boiCttIcEwS02WPwYkUihqsjSaK/TMtHz05vT6uMgac9PaQt5kzBQLIABv5aEIa5gtrMmKVz49MjkjQ==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6", - "debug": "^4.4.0", - "fb-dotslash": "0.5.8" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/dev-middleware": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.85.3.tgz", - "integrity": "sha512-JYzBiT4A8w+KQt+dOD5v+ti+tDrGoPnsSTuApq3Ls4RB5sfWbDlYMyz3dbc8qBIHz9tv0sQ5+eOu6Xwqzr5AQA==", - "license": "MIT", - "dependencies": { - "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.85.3", - "@react-native/debugger-shell": "0.85.3", - "chrome-launcher": "^0.15.2", - "chromium-edge-launcher": "^0.3.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": "^7.5.10" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/gradle-plugin": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.85.3.tgz", - "integrity": "sha512-39dY2j50Q1pntejzwt3XL7vwXtrj8jcIfHq6E+gyu3jzYxZJVvMkMutQ39vSg6zinIQOX36oQDhidXUbCXzgoA==", - "license": "MIT", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/js-polyfills": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.85.3.tgz", - "integrity": "sha512-U2+aMshIXf1uFn77tpBb/xhHWB9vkVrMpt7kkucAugF8hJKYTDGB587X7WwelHduK2KBfhl4giSv0rzZGoef9A==", - "license": "MIT", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-babel-transformer": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.85.3.tgz", - "integrity": "sha512-omuKq+r7jM4XvCMIlNMPP7Up3SyB8o5EAdZtF7YXniKyq7UOMBqhYHFqgsdOXr0lT+3ADf7VCJG3sb82jlBrrQ==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@react-native/babel-preset": "0.85.3", - "hermes-parser": "0.33.3", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-estree": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", - "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", - "license": "MIT" - }, - "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-parser": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", - "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.33.3" - } - }, - "node_modules/@react-native/metro-config": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.85.3.tgz", - "integrity": "sha512-sVo6HepUmCcpdfozEf91lA0FjpLNNZYu/Zi9FiYiAQTK8pzATXDVTqhvdxpFrQn435p5eUTSbllvbH/KN+bnyA==", - "license": "MIT", - "dependencies": { - "@react-native/js-polyfills": "0.85.3", - "@react-native/metro-babel-transformer": "0.85.3", - "metro-config": "^0.84.3", - "metro-runtime": "^0.84.3" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/normalize-colors": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.85.3.tgz", - "integrity": "sha512-hj0PScZEhIbcOvQV5yMKX3ha4XEIOy/SVE1Rrpp0beW0dpNLOgSC7KDxGewmDnIHK9YdQUXGY9eMEfShUMIaZw==", - "license": "MIT" - }, - "node_modules/@react-native/virtualized-lists": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.85.3.tgz", - "integrity": "sha512-dsCjI//OIPEUJMyNHp4l7zNLVjCx7bcaRUceOCkU+IB17hkbtbGWvi7HjGFSzy7FJGmS/MOlcfpb72xXiy1Oig==", - "license": "MIT", - "dependencies": { - "invariant": "^2.2.4", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@types/react": "^19.2.0", - "react": "*", - "react-native": "0.85.3" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "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/@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==", - "license": "MIT", - "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" - }, - "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==", - "license": "MIT", - "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==", - "license": "MIT", - "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" - } - }, - "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==", - "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==", - "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" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", - "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, - "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==", - "license": "MIT" - }, - "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/node": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.0.tgz", - "integrity": "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==", - "license": "MIT", - "dependencies": { - "undici-types": "~8.3.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "license": "MIT", - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-test-renderer": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-19.1.0.tgz", - "integrity": "sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==", - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "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/@ungap/structured-clone": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.2.tgz", - "integrity": "sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA==", - "license": "ISC" - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", - "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", - "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": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.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/agent-cli-detector": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/agent-cli-detector/-/agent-cli-detector-0.1.2.tgz", - "integrity": "sha512-qdZ/9JFORtTKJNhT/IczMeEfEUbUU0K5umYeiIQHX+AjHs+Y9SXVzSgaYlpZeyNMrvuh2HpZiOTpvS57iPfBkQ==", - "license": "MIT", - "bin": { - "agent-cli-detector": "dist/cli.js" - }, - "engines": { - "node": ">=18.18" - } - }, - "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/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/aria-hidden": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", - "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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==", - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/array-timsort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", - "license": "MIT" - }, - "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/babel-plugin-polyfill-corejs2": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", - "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.8", - "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.8", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", - "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8" - }, - "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.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-plugin-syntax-hermes-parser": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.33.3.tgz", - "integrity": "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==", - "license": "MIT", - "dependencies": { - "hermes-parser": "0.33.3" - } - }, - "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", - "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", - "license": "MIT" - }, - "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", - "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.33.3" - } - }, - "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-expo": { - "version": "56.0.16", - "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-56.0.16.tgz", - "integrity": "sha512-HkTZP+nWVGTibw+JCiy2yCXPPXhFUbqG6xdZRSnnAv+tZUdsCdvGnfEl14shS1mZWIY0VSf/rWpkzIEsZKyqhQ==", - "license": "MIT", - "dependencies": { - "@babel/generator": "^7.20.5", - "@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-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-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-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-flow-strip-types": "^7.25.2", - "@babel/plugin-transform-for-of": "^7.24.7", - "@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-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.28.6", - "@babel/plugin-transform-react-jsx-development": "^7.27.1", - "@babel/plugin-transform-react-pure-annotations": "^7.27.1", - "@babel/plugin-transform-runtime": "^7.24.7", - "@babel/plugin-transform-typescript": "^7.25.2", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/preset-typescript": "^7.23.0", - "@react-native/babel-plugin-codegen": "0.85.3", - "babel-plugin-react-compiler": "^1.0.0", - "babel-plugin-react-native-web": "~0.21.0", - "babel-plugin-syntax-hermes-parser": "^0.33.3", - "babel-plugin-transform-flow-enums": "^0.0.2", - "debug": "^4.3.4" - }, - "peerDependencies": { - "@babel/runtime": "^7.20.0", - "expo": "*", - "expo-widgets": "^56.0.20", - "react-refresh": ">=0.14.0 <1.0.0" - }, - "peerDependenciesMeta": { - "@babel/runtime": { - "optional": true - }, - "expo": { - "optional": true - }, - "expo-widgets": { - "optional": true - } - } - }, - "node_modules/badgin": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz", - "integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.38", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", - "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "license": "Unlicense", - "engines": { - "node": ">=0.6" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.2", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz", - "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==", - "license": "MIT", - "dependencies": { - "big-integer": "1.6.x" - }, - "engines": { - "node": ">= 5.10.0" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", - "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "baseline-browser-mapping": "^2.10.38", - "caniuse-lite": "^1.0.30001799", - "electron-to-chromium": "^1.5.376", - "node-releases": "^2.0.48", - "update-browserslist-db": "^1.2.3" - }, - "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-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/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/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==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001799", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", - "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "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/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "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.3.0", - "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz", - "integrity": "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==", - "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" - } - }, - "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/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" - }, - "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/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/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/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": ">= 10" - } - }, - "node_modules/comment-json": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz", - "integrity": "sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==", - "license": "MIT", - "dependencies": { - "array-timsort": "^1.0.3", - "esprima": "^4.0.1" - }, - "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/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/core-js-compat": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", - "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "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/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/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==", - "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==", - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-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/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/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/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "license": "Apache-2.0" - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "license": "MIT" - }, - "node_modules/dnssd-advertise": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/dnssd-advertise/-/dnssd-advertise-1.1.6.tgz", - "integrity": "sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==", - "license": "MIT" - }, - "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==", - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "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.378", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.378.tgz", - "integrity": "sha512-VinvOAuuPmdD1guEgGv5f2Qp7/vlfqOrUOMYNnOD4wj3pit8kRsQHzfIf6teyUGWo15Tg5+bOJaRunvyltpVWQ==", - "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/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-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "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/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/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/expo": { - "version": "56.0.14", - "resolved": "https://registry.npmjs.org/expo/-/expo-56.0.14.tgz", - "integrity": "sha512-YfjXv/owsBhys0HS2K9kd5ONi+FYTNKzoMOCZB5sza0K7JjzjQ1dVC+KzUA27B3GN2RuAyeBoW8jItNr56EBGg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.20.0", - "@expo/cli": "^56.1.18", - "@expo/config": "~56.0.11", - "@expo/config-plugins": "~56.0.11", - "@expo/devtools": "~56.0.2", - "@expo/dom-webview": "~56.0.6", - "@expo/fingerprint": "^0.19.6", - "@expo/local-build-cache-provider": "^56.0.9", - "@expo/log-box": "^56.0.14", - "@expo/metro": "~56.0.0", - "@expo/metro-config": "~56.0.16", - "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~56.0.16", - "expo-asset": "~56.0.18", - "expo-constants": "~56.0.20", - "expo-file-system": "~56.0.8", - "expo-font": "~56.0.7", - "expo-keep-awake": "~56.0.3", - "expo-modules-autolinking": "~56.0.18", - "expo-modules-core": "~56.0.19", - "pretty-format": "^29.7.0", - "react-refresh": "^0.14.2", - "whatwg-url-minimum": "^0.1.2" - }, - "bin": { - "expo": "bin/cli", - "expo-modules-autolinking": "bin/autolinking", - "fingerprint": "bin/fingerprint" - }, - "peerDependencies": { - "@expo/dom-webview": "*", - "@expo/metro-runtime": "*", - "react": "*", - "react-dom": "*", - "react-native": "*", - "react-native-web": "*", - "react-native-webview": "*" - }, - "peerDependenciesMeta": { - "@expo/dom-webview": { - "optional": true - }, - "@expo/metro-runtime": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native-web": { - "optional": true - }, - "react-native-webview": { - "optional": true - } - } - }, - "node_modules/expo-application": { - "version": "56.0.3", - "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-56.0.3.tgz", - "integrity": "sha512-DdGGPlMuM6cSTeKhbvh6OeLr2O/+EI5BHKYrD+Do8sJPYgLwzGrgESELfyjJCpEhFzT+TgKIdmLmWXhNUQnHiw==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-asset": { - "version": "56.0.18", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-56.0.18.tgz", - "integrity": "sha512-koV8oOW/U4mPP+sWHhsSxk4GdYrO6s/vZU3/OMeDwiyjeqeNJWfjpVUS94HERzwvcthPiX419X3PNj0p9XKt+g==", - "license": "MIT", - "dependencies": { - "@expo/image-utils": "^0.10.1", - "expo-constants": "~56.0.19" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-constants": { - "version": "56.0.20", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-56.0.20.tgz", - "integrity": "sha512-4HgoVvUiMvcqujr/CUj7L1tumLWj8WX0PLM77OriDPoaJrMEwUHd841m4o4IoUyMPVT8XTiTiPFwJtGali8+9Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "@expo/env": "~2.3.1" - }, - "peerDependencies": { - "expo": "*", - "react-native": "*" - } - }, - "node_modules/expo-document-picker": { - "version": "56.0.4", - "resolved": "https://registry.npmjs.org/expo-document-picker/-/expo-document-picker-56.0.4.tgz", - "integrity": "sha512-75Apf74XNkYYohObIH19VZw42xpe0gmEnPccuzGXKVAzlvTYCfibSgW17F+6vt4paOfZEnAoZ1QFZM6dmaujRA==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-eas-client": { - "version": "56.0.1", - "resolved": "https://registry.npmjs.org/expo-eas-client/-/expo-eas-client-56.0.1.tgz", - "integrity": "sha512-r8h0ZIExacCrSRgY+ARfhMvFqosLHLJt1L7jyhvabfr1DN/ZDKDsYbovss2tzkpEUZGxZ3BPcB5epCwUsBBdOA==", - "license": "MIT" - }, - "node_modules/expo-file-system": { - "version": "56.0.8", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-56.0.8.tgz", - "integrity": "sha512-NrH41/8snGIBSbYicwVLB4txPdgCATd7ZYhMAGS3YJZ9GbnduhlAoV4/YCbGayjrbpE9bJb/6wegPL/zmvRMnQ==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react-native": "*" - } - }, - "node_modules/expo-font": { - "version": "56.0.7", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-56.0.7.tgz", - "integrity": "sha512-hpU/vRwPzsby9lPGkA4blDqLIIXYzoWnCZHr6PxvcWbY/uPObAiyhh6q+e0WYsB65SthK+PLH95jEnVag7fwEg==", - "license": "MIT", - "peer": true, - "dependencies": { - "fontfaceobserver": "^2.1.0" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-glass-effect": { - "version": "56.0.4", - "resolved": "https://registry.npmjs.org/expo-glass-effect/-/expo-glass-effect-56.0.4.tgz", - "integrity": "sha512-xI9rXtDwi7RW82uAlfyaXO6+k21ApWJ2tHAWYqPr/FjfmZbKsgNJ4Q0iZzGPCwboqjTGxaRZ61SZxBl8hDt5iA==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-json-utils": { - "version": "56.0.0", - "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-56.0.0.tgz", - "integrity": "sha512-lUqyv9aIGDbYTQ5Nux2FnH2/Dz0w5uJ8Pr080eS0StXi2jr5OmuMNErpzUnpfnYOU55xKotd4AHv68PfV/ludg==", - "license": "MIT" - }, - "node_modules/expo-keep-awake": { - "version": "56.0.3", - "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-56.0.3.tgz", - "integrity": "sha512-CLMJXtEiMKknD3Rpm8CRwE6ZJUzu2yCEmRk1sgfHAJ1zIbuEWY3dpPDubtsnuzWm+2k6Sru+yaFbYsvPWmTiBA==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*" - } - }, - "node_modules/expo-linking": { - "version": "56.0.15", - "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-56.0.15.tgz", - "integrity": "sha512-V3tkCxHIWO624ayw2L5Nfi0/bPgYy/0MgmoQR7g3FAKF4nyAayK8IhgAInz4MZ5Ao5Bb+5uZWDdUaS4yyEb+Gw==", - "license": "MIT", - "peer": true, - "dependencies": { - "expo-constants": "~56.0.20", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-manifests": { - "version": "56.0.4", - "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-56.0.4.tgz", - "integrity": "sha512-Fokawl2UkiExIF0bqGoblRFA8lYpROVD+EpvDwSW4LgqQyPwNua1gLSgHZjdl5GsVugfRMMWE3LHaibDyX93hw==", - "license": "MIT", - "dependencies": { - "expo-json-utils": "~56.0.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-modules-autolinking": { - "version": "56.0.18", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-56.0.18.tgz", - "integrity": "sha512-8+NyEpTKjrUpHRFw+WihXXnLa/nqPlUpFz4SdtzPovW24rJikyw160gVSCbuILp+AgC8yasjHT+C6xuqRSdiew==", - "license": "MIT", - "dependencies": { - "@expo/require-utils": "^56.1.4", - "@expo/spawn-async": "^1.8.0", - "chalk": "^4.1.0", - "commander": "^7.2.0" - }, - "bin": { - "expo-modules-autolinking": "bin/expo-modules-autolinking.js" - } - }, - "node_modules/expo-modules-core": { - "version": "56.0.19", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-56.0.19.tgz", - "integrity": "sha512-nJCXHNK4y7X8/Z40zssp8hRpxzwEEpWGtA4b9b3gf67aaj4Z7l5PDstfv+8d5QnsAcOM+Vxum9E+itqNB27qXQ==", - "license": "MIT", - "dependencies": { - "@expo/expo-modules-macros-plugin": "0.2.2", - "expo-modules-jsi": "~56.0.11", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "react": "*", - "react-native": "*", - "react-native-worklets": "^0.7.4 || ^0.8.0" - }, - "peerDependenciesMeta": { - "react-native-worklets": { - "optional": true - } - } - }, - "node_modules/expo-modules-jsi": { - "version": "56.0.11", - "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-56.0.11.tgz", - "integrity": "sha512-vhjaTb63ekITnSz8ah+k+GOUDRB9TB8NmY8Iq7cj5O8iKXcqJi/3ZyHyhiFSu0Pjb+UXEeFX+42KZ/a3XZDd4Q==", - "license": "MIT", - "peerDependencies": { - "react-native": "*" - } - }, - "node_modules/expo-notifications": { - "version": "56.0.19", - "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-56.0.19.tgz", - "integrity": "sha512-3sTegn8Wwu84TLIAxAqC725kqQ412U2NG9qUH4k3gQzBU49vROhvsslj7gARgvOJY8KohuJz82csuZfZnHDDHw==", - "license": "MIT", - "dependencies": { - "@expo/image-utils": "^0.10.1", - "abort-controller": "^3.0.0", - "badgin": "^1.1.5", - "expo-application": "~56.0.3", - "expo-constants": "~56.0.19" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-router": { - "version": "56.2.13", - "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-56.2.13.tgz", - "integrity": "sha512-Iln0473krRnI8m1EnZ29Sg1kWRgQ2W9a8bsDkslPPnpdAHQee28HajkQHXZsNPxD1t4hii1lajRRHKNmJs37rA==", - "license": "MIT", - "dependencies": { - "@expo/log-box": "^56.0.14", - "@expo/metro-runtime": "^56.0.16", - "@expo/schema-utils": "^56.0.2", - "@expo/ui": "^56.0.20", - "@radix-ui/react-slot": "^1.2.0", - "@radix-ui/react-tabs": "^1.1.12", - "@react-native-masked-view/masked-view": "^0.3.2", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/user-event": "^14.6.1", - "client-only": "^0.0.1", - "color": "^4.2.3", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "expo-glass-effect": "^56.0.4", - "expo-server": "^56.0.5", - "expo-symbols": "^56.0.6", - "fast-deep-equal": "^3.1.3", - "invariant": "^2.2.4", - "nanoid": "^3.3.8", - "query-string": "^7.1.3", - "react-fast-compare": "^3.2.2", - "react-is": "^19.1.0", - "react-native-drawer-layout": "^4.2.2", - "react-native-screens": "^4.25.2", - "server-only": "^0.0.1", - "sf-symbols-typescript": "^2.1.0", - "shallowequal": "^1.1.0", - "standard-navigation": "^0.0.5", - "vaul": "^1.1.2" - }, - "peerDependencies": { - "@expo/log-box": "^56.0.14", - "@expo/metro-runtime": "^56.0.16", - "@testing-library/react-native": ">= 13.2.0", - "expo": "*", - "expo-constants": "^56.0.20", - "expo-linking": "^56.0.15", - "react": "*", - "react-dom": "*", - "react-native": "*", - "react-native-gesture-handler": "*", - "react-native-reanimated": "*", - "react-native-safe-area-context": ">= 5.4.0", - "react-native-screens": "^4.25.2", - "react-native-web": "*", - "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" - }, - "peerDependenciesMeta": { - "@testing-library/react-native": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native-gesture-handler": { - "optional": true - }, - "react-native-reanimated": { - "optional": true - }, - "react-native-web": { - "optional": true - }, - "react-server-dom-webpack": { - "optional": true - } - } - }, - "node_modules/expo-router/node_modules/react-is": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", - "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", - "license": "MIT" - }, - "node_modules/expo-secure-store": { - "version": "56.0.4", - "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-56.0.4.tgz", - "integrity": "sha512-hjEi/gmpdFFJ9lYbdp3k3p/WchV7Gi0Qt8jt/m/0WJadqQrskafHAlDxbZkII1cN3Yd7zp9Lvkeq3UfGhSwirQ==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-server": { - "version": "56.0.5", - "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-56.0.5.tgz", - "integrity": "sha512-SmM2p2g3Jrktpiazcst+OxhjSzOHXKAY4BPURHYHXvApzzoybMmrNF4IEZ8DKZ145BhSe4ydAmlEFCRTsdtgUQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=20.16.0" - } - }, - "node_modules/expo-splash-screen": { - "version": "56.0.12", - "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-56.0.12.tgz", - "integrity": "sha512-RvEtJ78aNpuxdVD8TCe9viKtlYGzS9hW20fbvqvkeXDN6WAaYo1CRitPdjWNkaNNSPKOolp3zfha4EGdhXOtxg==", - "license": "MIT", - "dependencies": { - "@expo/config-plugins": "~56.0.11", - "@expo/image-utils": "^0.10.2", - "xml2js": "0.6.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-status-bar": { - "version": "56.0.4", - "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-56.0.4.tgz", - "integrity": "sha512-IGs/fDfkHXofy2ZQrGiXayhFK04HB85FZXorhcEhDZEcqASKgSqpak+HwUtAaR0MeTJwWyHNF7I6VmVbbp8EcA==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-structured-headers": { - "version": "56.0.0", - "resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-56.0.0.tgz", - "integrity": "sha512-Yv4x+SQxNnMQm4nu8NFfzx197YaDhdYH2N0u7tGErwWTmH9Tm1SAhqo7bLbBWLC9kf7W+kdzTshLU9rTiCXWGw==", - "license": "MIT" - }, - "node_modules/expo-symbols": { - "version": "56.0.6", - "resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-56.0.6.tgz", - "integrity": "sha512-BrA81DjcNafdj7gXVhdrExb9LtUiSVyOf/NavyMmDAHgHMY1GqeR5cnn1PSAZeYKnSgQhee/H89XUpAxtog5hg==", - "license": "MIT", - "dependencies": { - "@expo-google-fonts/material-symbols": "^0.4.1", - "sf-symbols-typescript": "^2.0.0" - }, - "peerDependencies": { - "expo": "*", - "expo-font": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-system-ui": { - "version": "56.0.5", - "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-56.0.5.tgz", - "integrity": "sha512-n1MmnUArV4cc3gVed9fGtluPme00PE9axKVx+NHbKxHFMam5l4GcOI7PxbYKFNx8o7WA1LRD7eLW33agmZrxGg==", - "license": "MIT", - "dependencies": { - "@react-native/normalize-colors": "0.85.3", - "debug": "^4.3.2" - }, - "peerDependencies": { - "expo": "*", - "react-native": "*", - "react-native-web": "*" - }, - "peerDependenciesMeta": { - "react-native-web": { - "optional": true - } - } - }, - "node_modules/expo-updates": { - "version": "56.0.21", - "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-56.0.21.tgz", - "integrity": "sha512-7kYS2/ra9Lg4xBG6Fadcq/YR8DngdCeBVc0lQeHvqH/dZHL2N0bJRu0y4utJd9tpIzQtNCmceGu1SmGZVT57/Q==", - "license": "MIT", - "dependencies": { - "@expo/code-signing-certificates": "^0.0.6", - "@expo/plist": "^0.7.0", - "@expo/spawn-async": "^1.8.0", - "arg": "^4.1.0", - "chalk": "^4.1.2", - "debug": "^4.3.4", - "expo-eas-client": "~56.0.0", - "expo-manifests": "~56.0.4", - "expo-structured-headers": "~56.0.0", - "expo-updates-interface": "~56.0.1", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "ignore": "^5.3.1", - "nullthrows": "^1.1.1", - "resolve-from": "^5.0.0" - }, - "bin": { - "expo-updates": "bin/cli.js" - }, - "peerDependencies": { - "expo": "*", - "expo-dev-client": "*", - "react": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "expo-dev-client": { - "optional": true - } - } - }, - "node_modules/expo-updates-interface": { - "version": "56.0.2", - "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-56.0.2.tgz", - "integrity": "sha512-eWTwSZ9y8vrULG2oBn2TQSSIwBGSq/TxGJ3jY6tuVS2FWH/ASRIiKs3zkUZTRoC3ZuV2alz0mUClYV7nNrFx8g==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-updates/node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "license": "MIT" - }, - "node_modules/expo/node_modules/@expo/cli": { - "version": "56.1.18", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-56.1.18.tgz", - "integrity": "sha512-ACzbK2mLPevgjdJ7EeDyjPem+WU9oDcCLD2Ajwrl6dVvN9xP5wchGrwRQvVx55TU3bdTCEXpiHC2AGRXfXVc6g==", - "license": "MIT", - "dependencies": { - "@expo/code-signing-certificates": "^0.0.6", - "@expo/config": "~56.0.11", - "@expo/config-plugins": "~56.0.11", - "@expo/devcert": "^1.2.1", - "@expo/env": "~2.3.1", - "@expo/image-utils": "^0.10.2", - "@expo/inline-modules": "^0.0.13", - "@expo/json-file": "^10.2.0", - "@expo/log-box": "^56.0.14", - "@expo/metro": "~56.0.0", - "@expo/metro-config": "~56.0.16", - "@expo/metro-file-map": "^56.0.3", - "@expo/osascript": "^2.6.0", - "@expo/package-manager": "^1.12.1", - "@expo/plist": "^0.7.0", - "@expo/prebuild-config": "^56.0.18", - "@expo/require-utils": "^56.1.4", - "@expo/router-server": "^56.0.15", - "@expo/schema-utils": "^56.0.2", - "@expo/spawn-async": "^1.8.0", - "@expo/ws-tunnel": "^2.0.0", - "@expo/xcpretty": "^4.4.4", - "@react-native/dev-middleware": "0.85.3", - "accepts": "^1.3.8", - "agent-cli-detector": "^0.1.2", - "arg": "^5.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", - "dnssd-advertise": "^1.1.6", - "expo-server": "^56.0.5", - "fetch-nodeshim": "^0.4.10", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "lan-network": "^0.2.1", - "multitars": "^1.0.0", - "node-forge": "^1.3.3", - "npm-package-arg": "^11.0.0", - "ora": "^3.4.0", - "picomatch": "^4.0.4", - "pretty-format": "^29.7.0", - "progress": "^2.0.3", - "prompts": "^2.3.2", - "resolve-from": "^5.0.0", - "semver": "^7.6.0", - "send": "^0.19.0", - "slugify": "^1.3.4", - "stacktrace-parser": "^0.1.10", - "structured-headers": "^0.4.1", - "terminal-link": "^2.1.1", - "toqr": "^0.1.1", - "wrap-ansi": "^7.0.0", - "ws": "^8.12.1", - "zod": "^3.25.76" - }, - "bin": { - "expo-internal": "main.js" - }, - "peerDependencies": { - "expo": "*", - "expo-router": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "expo-router": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { - "version": "56.0.15", - "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-56.0.15.tgz", - "integrity": "sha512-eXTwUEKR6MPeoJVwyGOX5eIvUUKCGL0mItTXBMTb2TIr9M6IH7ORVo8yHB70RVSLVXo8AuwsCtDfKFKZ3rUZ5w==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "@expo/metro-runtime": "^56.0.16", - "expo": "*", - "expo-constants": "^56.0.19", - "expo-font": "^56.0.7", - "expo-router": "*", - "expo-server": "^56.0.5", - "react": "*", - "react-dom": "*", - "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" - }, - "peerDependenciesMeta": { - "@expo/metro-runtime": { - "optional": true - }, - "expo-router": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-server-dom-webpack": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/ws-tunnel": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-2.0.0.tgz", - "integrity": "sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw==", - "license": "MIT", - "peerDependencies": { - "ws": "^8.0.0" - } - }, - "node_modules/expo/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/expo/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/expo/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/expo/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-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expo/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": ">= 0.6" - } - }, - "node_modules/expo/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/expo/node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "license": "MIT", - "peer": true, - "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/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-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==", - "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==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-dotslash": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", - "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", - "license": "(MIT OR Apache-2.0)", - "bin": { - "dotslash": "bin/dotslash" - }, - "engines": { - "node": ">=20" - } - }, - "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/fbjs/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": { - "asap": "~2.0.3" - } - }, - "node_modules/fetch-nodeshim": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/fetch-nodeshim/-/fetch-nodeshim-0.4.10.tgz", - "integrity": "sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w==", - "license": "MIT" - }, - "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/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/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/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-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 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==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hermes-compiler": { - "version": "250829098.0.10", - "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.10.tgz", - "integrity": "sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==", - "license": "MIT" - }, - "node_modules/hermes-estree": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", - "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", - "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.35.0" - } - }, - "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/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/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/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/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==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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/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-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/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==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "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==", - "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==", - "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-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": { - "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/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-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-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-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/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/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==", - "license": "MIT", - "peer": true, - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "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/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "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", - "engines": { - "node": ">=6" - } - }, - "node_modules/lan-network": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.2.1.tgz", - "integrity": "sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==", - "license": "MIT", - "bin": { - "lan-network": "dist/lan-network-cli.js" - } - }, - "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", - "engines": { - "node": ">=6" - } - }, - "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/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", - "dependencies": { - "ms": "2.0.0" - } - }, - "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/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" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "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": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.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": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.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": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.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": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.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" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.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" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.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" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, - "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/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/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": { - "chalk": "^2.0.1" - }, - "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": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "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": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "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": { - "color-name": "1.1.3" - } - }, - "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/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/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": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "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==", - "license": "MIT", - "bin": { - "lz-string": "bin/bin.js" - } - }, - "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": { - "tmpl": "1.0.5" - } - }, - "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/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/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==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/metro": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.4.tgz", - "integrity": "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "accepts": "^2.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.35.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.84.4", - "metro-cache": "0.84.4", - "metro-cache-key": "0.84.4", - "metro-config": "0.84.4", - "metro-core": "0.84.4", - "metro-file-map": "0.84.4", - "metro-resolver": "0.84.4", - "metro-runtime": "0.84.4", - "metro-source-map": "0.84.4", - "metro-symbolicate": "0.84.4", - "metro-transform-plugins": "0.84.4", - "metro-transform-worker": "0.84.4", - "mime-types": "^3.0.1", - "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" - }, - "bin": { - "metro": "src/cli.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-babel-transformer": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.4.tgz", - "integrity": "sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.35.0", - "metro-cache-key": "0.84.4", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-cache": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.4.tgz", - "integrity": "sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==", - "license": "MIT", - "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "https-proxy-agent": "^7.0.5", - "metro-core": "0.84.4" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-cache-key": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.4.tgz", - "integrity": "sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-config": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.4.tgz", - "integrity": "sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==", - "license": "MIT", - "dependencies": { - "connect": "^3.6.5", - "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.7.0", - "metro": "0.84.4", - "metro-cache": "0.84.4", - "metro-core": "0.84.4", - "metro-runtime": "0.84.4", - "yaml": "^2.6.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-core": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.4.tgz", - "integrity": "sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "lodash.throttle": "^4.1.1", - "metro-resolver": "0.84.4" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-file-map": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.4.tgz", - "integrity": "sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==", - "license": "MIT", - "dependencies": { - "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" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-minify-terser": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.4.tgz", - "integrity": "sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "terser": "^5.15.0" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-resolver": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.4.tgz", - "integrity": "sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-runtime": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.4.tgz", - "integrity": "sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.25.0", - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-source-map": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.4.tgz", - "integrity": "sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.84.4", - "nullthrows": "^1.1.1", - "ob1": "0.84.4", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-symbolicate": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.4.tgz", - "integrity": "sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.84.4", - "nullthrows": "^1.1.1", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "bin": { - "metro-symbolicate": "src/index.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-transform-plugins": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.4.tgz", - "integrity": "sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-transform-worker": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.4.tgz", - "integrity": "sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "metro": "0.84.4", - "metro-babel-transformer": "0.84.4", - "metro-cache": "0.84.4", - "metro-cache-key": "0.84.4", - "metro-minify-terser": "0.84.4", - "metro-source-map": "0.84.4", - "metro-transform-plugins": "0.84.4", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "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": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "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": ">=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/multitars": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/multitars/-/multitars-1.0.0.tgz", - "integrity": "sha512-H/J4fMLedtudftaYMOg7ajzLYgT3/rwbWVJbqr/iUgB8DQztn38ys5HOqI1CzSxx8QhXXwOOnnBvd4v3jG5+Mg==", - "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": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nativewind": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/nativewind/-/nativewind-4.2.6.tgz", - "integrity": "sha512-kLPRH3Yh/hhIFufXzUZDe39fuK471GwaPBCqYNgcRygILr+obV+wFfDmG+zaJnniVUFFQzYOTCEldem6XktZ+A==", - "license": "MIT", - "dependencies": { - "comment-json": "^4.2.5", - "debug": "^4.3.7", - "react-native-css-interop": "0.2.6" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "tailwindcss": ">3.3.0" - } - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "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": ">= 6.13.0" - } - }, - "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/node-releases": { - "version": "2.0.49", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.49.tgz", - "integrity": "sha512-f06bl1D+8ZDkn2oOQQKAh5/otFWqVnM1Q5oerA8Pex7UfT66Tx4IPHIqVVFKqFT3FUtaDstdgkM7yT7JWhqxfw==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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": "^16.14.0 || >=18.0.0" - } - }, - "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/ob1": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.4.tgz", - "integrity": "sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "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": ">= 0.8" - } - }, - "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/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": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": { - "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": ">=6" - } - }, - "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", - "engines": { - "node": ">=6" - } - }, - "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": ">=4" - } - }, - "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": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "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", - "dependencies": { - "color-name": "1.1.3" - } - }, - "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": ">=0.8.0" - } - }, - "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", - "engines": { - "node": ">=4" - } - }, - "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-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "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": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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": { - "pngjs": "^3.3.0" - }, - "engines": { - "node": ">=10" - } - }, - "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.8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "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.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/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/plist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz", - "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.9.10", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/plist/node_modules/@xmldom/xmldom": { - "version": "0.9.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz", - "integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==", - "license": "MIT", - "engines": { - "node": ">=14.6" - } - }, - "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/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "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", - "peer": true, - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "license": "MIT" - }, - "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/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==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "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/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise": { - "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": { - "asap": "~2.0.6" - } - }, - "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": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "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": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": { - "inherits": "~2.0.3" - } - }, - "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==", - "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/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.6" - } - }, - "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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", - "dependencies": { - "shell-quote": "^1.6.1", - "ws": "^7" - } - }, - "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", - "license": "MIT", - "peer": true, - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.3" - } - }, - "node_modules/react-fast-compare": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", - "license": "MIT" - }, - "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": ">=10" - }, - "peerDependencies": { - "react": ">=17.0.0" - } - }, - "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/react-native": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.85.3.tgz", - "integrity": "sha512-HN/fGC+3nZVcDNcw7gfbM/DuqZAvI9Mz+/SxuhODaua4JY0BPzhfTzWXRyTR4mRgMHmShTPpH2PYMTxvZrsdZA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@react-native/assets-registry": "0.85.3", - "@react-native/codegen": "0.85.3", - "@react-native/community-cli-plugin": "0.85.3", - "@react-native/gradle-plugin": "0.85.3", - "@react-native/js-polyfills": "0.85.3", - "@react-native/normalize-colors": "0.85.3", - "@react-native/virtualized-lists": "0.85.3", - "abort-controller": "^3.0.0", - "anser": "^1.4.9", - "ansi-regex": "^5.0.0", - "babel-plugin-syntax-hermes-parser": "0.33.3", - "base64-js": "^1.5.1", - "commander": "^12.0.0", - "flow-enums-runtime": "^0.0.6", - "hermes-compiler": "250829098.0.10", - "invariant": "^2.2.4", - "memoize-one": "^5.0.0", - "metro-runtime": "^0.84.3", - "metro-source-map": "^0.84.3", - "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.27.0", - "semver": "^7.1.3", - "stacktrace-parser": "^0.1.10", - "tinyglobby": "^0.2.15", - "whatwg-fetch": "^3.0.0", - "ws": "^7.5.10", - "yargs": "^17.6.2" - }, - "bin": { - "react-native": "cli.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@react-native/jest-preset": "0.85.3", - "@types/react": "^19.1.1", - "react": "^19.2.3" - }, - "peerDependenciesMeta": { - "@react-native/jest-preset": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-native-css-interop": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/react-native-css-interop/-/react-native-css-interop-0.2.6.tgz", - "integrity": "sha512-uXad6EWqufupnRjrba2De30tiAx26kLEcwSV3eSLVBwpfYeOnrpDc9k6kHk6SBNbmHHlE5sc9vsfKdVRS9msYg==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.22.15", - "@babel/traverse": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.3.7", - "lightningcss": "~1.27.0", - "semver": "^7.6.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "react": ">=18", - "react-native": "*", - "react-native-reanimated": ">=3.6.2", - "tailwindcss": "~3" - }, - "peerDependenciesMeta": { - "react-native-safe-area-context": { - "optional": true - }, - "react-native-svg": { - "optional": true - } - } - }, - "node_modules/react-native-css-interop/node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz", - "integrity": "sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^1.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.27.0", - "lightningcss-darwin-x64": "1.27.0", - "lightningcss-freebsd-x64": "1.27.0", - "lightningcss-linux-arm-gnueabihf": "1.27.0", - "lightningcss-linux-arm64-gnu": "1.27.0", - "lightningcss-linux-arm64-musl": "1.27.0", - "lightningcss-linux-x64-gnu": "1.27.0", - "lightningcss-linux-x64-musl": "1.27.0", - "lightningcss-win32-arm64-msvc": "1.27.0", - "lightningcss-win32-x64-msvc": "1.27.0" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-darwin-arm64": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz", - "integrity": "sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-darwin-x64": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz", - "integrity": "sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-freebsd-x64": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz", - "integrity": "sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz", - "integrity": "sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz", - "integrity": "sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm64-musl": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz", - "integrity": "sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-linux-x64-gnu": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz", - "integrity": "sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-linux-x64-musl": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz", - "integrity": "sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz", - "integrity": "sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-css-interop/node_modules/lightningcss-win32-x64-msvc": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz", - "integrity": "sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/react-native-drawer-layout": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/react-native-drawer-layout/-/react-native-drawer-layout-4.2.5.tgz", - "integrity": "sha512-Yl82uLkXjXuq7222hWGIDsq5A6R/bsCeCEgdIxQUxAEHf00oRdDnRByLx3Fsij3qwtmYNPGrHV1NH8G8hbCbLQ==", - "license": "MIT", - "dependencies": { - "color": "^4.2.3", - "use-latest-callback": "^0.2.4" - }, - "peerDependencies": { - "react": ">= 18.2.0", - "react-native": "*", - "react-native-gesture-handler": ">= 2.0.0", - "react-native-reanimated": ">= 2.0.0" - } - }, - "node_modules/react-native-gesture-handler": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-3.0.2.tgz", - "integrity": "sha512-XBTgmvr2jh/xrMwlHTV2Z1x6IFUl3zfLxyaCAnvj3GSXK5YlY3ZmiIs57hniPmh3I7RtjPFxtGdRr0i+PzyBrg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/react-test-renderer": "^19.1.0", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native-is-edge-to-edge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.3.1.tgz", - "integrity": "sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA==", - "license": "MIT", - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native-reanimated": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.3.1.tgz", - "integrity": "sha512-KhGsS0YkCA+gusgyzlf9hnqzVPIR398KTpqXyqq/+yYJJPAvyEEPKcxlB0xtOOXSMrR2A9uRKVARVQhZwrOh+Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "react-native-is-edge-to-edge": "^1.3.1", - "semver": "^7.7.3" - }, - "peerDependencies": { - "react": "*", - "react-native": "0.81 - 0.85", - "react-native-worklets": "0.8.x" - } - }, - "node_modules/react-native-safe-area-context": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.7.0.tgz", - "integrity": "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native-screens": { - "version": "4.25.2", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.25.2.tgz", - "integrity": "sha512-1Nj1fusFd+rIMKU/qC9yGKVG+3ofh11d3OdBQKL1iVvQfKvcB8vhvTGQf2TkfxW3bamxN+hCZIXmNuU0mRkyDg==", - "license": "MIT", - "dependencies": { - "react-freeze": "^1.0.0", - "warn-once": "^0.1.0" - }, - "peerDependencies": { - "react": "*", - "react-native": ">=0.82.0" - } - }, - "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", - "peer": true, - "dependencies": { - "@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" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - } - }, - "node_modules/react-native-web/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-web/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/react-native-worklets": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.8.3.tgz", - "integrity": "sha512-oCBJROyLU7yG/1R8s0INMflygTH71bx+5XcYkH0CM938TlhSoVbiunE1WVW5FZa51vwYqfLie/IXMX2s1Kh3eg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/preset-typescript": "^7.27.1", - "convert-source-map": "^2.0.0", - "semver": "^7.7.3" - }, - "peerDependencies": { - "@babel/core": "*", - "@react-native/metro-config": "*", - "react": "*", - "react-native": "0.81 - 0.85" - } - }, - "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": ">=18" - } - }, - "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", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-remove-scroll": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", - "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", - "license": "MIT", - "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", - "license": "MIT", - "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "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==", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/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": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "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": { - "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": ">=4" - } - }, - "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/regjsparser": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", - "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", - "license": "BSD-2-Clause", - "dependencies": { - "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": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-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": ">=8" - } - }, - "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/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": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-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/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "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": { - "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": ">= 0.8.0" - } - }, - "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": { - "ms": "2.0.0" - } - }, - "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/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": ">= 0.8" - } - }, - "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": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "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": ">= 0.8" - } - }, - "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", - "engines": { - "node": ">=0.10.0" - } - }, - "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.0" - } - }, - "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": ">= 0.8" - } - }, - "node_modules/server-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", - "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", - "license": "MIT" - }, - "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/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "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/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "license": "MIT" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", - "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "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": { - "bplist-creator": "0.1.0", - "bplist-parser": "0.3.1", - "plist": "^3.0.5" - } - }, - "node_modules/simple-plist/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/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", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "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/slugify": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz", - "integrity": "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "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/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": { - "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.10.0" - } - }, - "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": ">=6" - } - }, - "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": { - "type-fest": "^0.7.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/standard-navigation": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/standard-navigation/-/standard-navigation-0.0.5.tgz", - "integrity": "sha512-YAmzwAiiQVocZxO/VGPFiQHcu5pKiz09QIGC0MK6aRMoa3E0QkoTQgcqJr7ZZ3OMiNhu4DkaGElFI5htjOIDbw==", - "license": "MIT" - }, - "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", - "engines": { - "node": ">= 0.6" - } - }, - "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/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", - "engines": { - "node": ">=4" - } - }, - "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": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/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/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": ">=8" - } - }, - "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": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/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": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", - "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "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/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "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/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "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": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/toqr": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/toqr/-/toqr-0.1.1.tgz", - "integrity": "sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==", - "license": "MIT" - }, - "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/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/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "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/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "devOptional": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "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/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], - "license": "MIT", - "bin": { - "ua-parser-js": "script/cli.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "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": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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", - "engines": { - "node": ">=4" - } - }, - "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/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/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "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/use-sidecar": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", - "license": "MIT", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "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==", - "license": "MIT" - }, - "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.4.0" - } - }, - "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==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "license": "MIT", - "bin": { - "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.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "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", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vaul": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", - "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-dialog": "^1.1.1" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" - } - }, - "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/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": { - "makeerror": "1.0.12" - } - }, - "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": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "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-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": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/whatwg-url-minimum": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/whatwg-url-minimum/-/whatwg-url-minimum-0.1.2.tgz", - "integrity": "sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==", - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "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": ">= 8" - } - }, - "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": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/ws": { - "version": "7.5.11", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", - "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "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": { - "simple-plist": "^1.1.0", - "uuid": "^7.0.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "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": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "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", - "engines": { - "node": ">=4.0" - } - }, - "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/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "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/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 7d92963..0000000 --- a/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "codexbar.mobile", - "version": "1.0.0", - "main": "expo-router/entry", - "dependencies": { - "@expo/metro-runtime": "~56.0.15", - "@expo/vector-icons": "^15.1.1", - "babel-preset-expo": "~56.0.0", - "expo": "~56.0.14", - "expo-constants": "~56.0.20", - "expo-document-picker": "~56.0.4", - "expo-file-system": "~56.0.8", - "expo-font": "~56.0.7", - "expo-linking": "~56.0.15", - "expo-notifications": "~56.0.19", - "expo-router": "~56.2.13", - "expo-secure-store": "~56.0.4", - "expo-splash-screen": "~56.0.10", - "expo-status-bar": "~56.0.4", - "expo-system-ui": "~56.0.5", - "expo-updates": "~56.0.21", - "nativewind": "^4.2.6", - "react": "19.2.3", - "react-dom": "^19.2.3", - "react-native": "0.85.3", - "react-native-reanimated": "4.3.1", - "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "4.25.2", - "react-native-web": "^0.21.2", - "react-native-worklets": "^0.8.3" - }, - "devDependencies": { - "@types/react": "~19.2.2", - "tailwindcss": "^3.4.19", - "typescript": "~6.0.3" - }, - "scripts": { - "start": "expo start", - "android": "expo start --android", - "ios": "expo start --ios", - "web": "expo start --web", - "update:preview": "eas update --channel preview --environment preview", - "update:production": "eas update --channel production --environment production", - "build:android:preview": "eas build --platform android --profile preview --non-interactive", - "build:android:production": "eas build --platform android --profile production --non-interactive" - }, - "private": true -} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..c954e70 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = 'CodexMobile' +include ':app' diff --git a/tailwind.config.js b/tailwind.config.js deleted file mode 100644 index 6d797b5..0000000 --- a/tailwind.config.js +++ /dev/null @@ -1,20 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: [ - "./app/**/*.{js,jsx,ts,tsx}", - "./components/**/*.{js,jsx,ts,tsx}", - "./hooks/**/*.{js,jsx,ts,tsx}", - ], - presets: [require("nativewind/preset")], - theme: { - extend: { - colors: { - brand: { - codex: "#10a37f", - claude: "#d97706", - }, - }, - }, - }, - plugins: [], -}; diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index a7bbebe..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "expo/tsconfig.base", - "compilerOptions": { - "strict": true, - "paths": { - "@/*": ["./*"] - } - }, - "include": [ - "**/*.ts", - "**/*.tsx", - ".expo/types/**/*.d.ts", - "nativewind-env.d.ts" - ] -} diff --git a/types/claude.ts b/types/claude.ts deleted file mode 100644 index 2019d15..0000000 --- a/types/claude.ts +++ /dev/null @@ -1,21 +0,0 @@ -export interface ClaudeAuth { - sessionKey: string; - lastActiveOrg?: string; -} - -export interface ClaudeOrg { - uuid: string; - name: string; -} - -export interface ClaudeWindowUsage { - utilization: number; - resets_at?: string; -} - -export interface ClaudeUsageResponse { - five_hour: ClaudeWindowUsage; - seven_day: ClaudeWindowUsage; - seven_day_sonnet?: ClaudeWindowUsage; - seven_day_opus?: ClaudeWindowUsage; -} diff --git a/types/codex.ts b/types/codex.ts deleted file mode 100644 index 86a3c40..0000000 --- a/types/codex.ts +++ /dev/null @@ -1,57 +0,0 @@ -export interface CodexAuth { - accessToken: string; - accountId?: string; -} - -export interface CodexUsageWindow { - usedPercent: number; - resetsAt: number; - windowMinutes: number; - windowSeconds: number; -} - -export interface CodexCreditsSummary { - hasCredits: boolean; - unlimited: boolean; - balance: number; -} - -export interface CodexResetCredit { - index: number; - status?: string; - grantedAt?: string | null; - grantedAtLocal?: string | null; - expiresAt?: string | null; - expiresAtLocal?: string | null; - timeUntilExpiry?: string | null; -} - -export interface CodexResetCoupons { - source: "live_api" | "local_state_fallback" | "unavailable"; - sourceDescription: string; - availableCount?: number | null; - totalEarnedCount?: number | null; - credits?: CodexResetCredit[]; - nextExpiringCredit?: CodexResetCredit | null; - dismissedAtLocal?: string | null; - latestPossibleExpiryLocal?: string | null; - latestPossibleExpiryNote?: string | null; - fallbackReason?: string; - error?: string; -} - -export interface CodexDesktopSnapshot { - sessionFile?: string; - threadId?: string | null; - snapshotTimestamp?: string | null; - limitId?: string | null; - planType?: string | null; - rateLimitReachedType?: string | null; - primary: CodexUsageWindow | null; - secondary: CodexUsageWindow | null; -} - -export interface CodexUsageResponse extends CodexDesktopSnapshot { - credits: CodexCreditsSummary; - resetCoupons?: CodexResetCoupons | null; -}