diff --git a/.eas/workflows/development-builds.yml b/.eas/workflows/development-builds.yml
new file mode 100644
index 00000000..541e5ff2
--- /dev/null
+++ b/.eas/workflows/development-builds.yml
@@ -0,0 +1,22 @@
+name: Create development builds
+
+on:
+ pull_request:
+ branches:
+ - main
+ - release/*
+
+jobs:
+ build_android:
+ name: Build Android (dev)
+ type: build
+ params:
+ platform: android
+ profile: development
+
+ build_ios_simulator:
+ name: Build iOS Simulator (dev)
+ type: build
+ params:
+ platform: ios
+ profile: preview
diff --git a/.eas/workflows/preview-update.yml b/.eas/workflows/preview-update.yml
new file mode 100644
index 00000000..cb317dd6
--- /dev/null
+++ b/.eas/workflows/preview-update.yml
@@ -0,0 +1,14 @@
+name: Publish preview update
+
+on:
+ push:
+ branches:
+ - '*'
+ - '!main'
+
+jobs:
+ publish_preview:
+ name: Publish preview update
+ type: update
+ params:
+ branch: ${{ github.ref_name || 'preview' }}
diff --git a/.eas/workflows/production-deploy.yml b/.eas/workflows/production-deploy.yml
new file mode 100644
index 00000000..501d8d92
--- /dev/null
+++ b/.eas/workflows/production-deploy.yml
@@ -0,0 +1,67 @@
+name: Deploy to production
+
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ fingerprint:
+ name: Fingerprint
+ type: fingerprint
+
+ # NOTE: get-build intentionally uses default behavior (completed builds only).
+ # If a build is in-progress, we skip and let it complete on its own.
+ # This prevents duplicate builds and OTA updates that would race with ongoing builds.
+ # Set wait_for_in_progress: true if you want to wait for in-progress builds instead.
+ get_android_build:
+ name: Check existing Android build
+ needs: [fingerprint]
+ type: get-build
+ params:
+ fingerprint_hash: ${{ needs.fingerprint.outputs.android_fingerprint_hash }}
+ profile: production
+
+ get_ios_build:
+ name: Check existing iOS build
+ needs: [fingerprint]
+ type: get-build
+ params:
+ fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}
+ profile: production
+
+ build_android:
+ name: Build Android
+ needs: [get_android_build]
+ if: ${{ !needs.get_android_build.outputs.build_id }}
+ type: build
+ params:
+ platform: android
+ profile: production
+
+ build_ios:
+ name: Build iOS
+ needs: [get_ios_build]
+ if: ${{ !needs.get_ios_build.outputs.build_id }}
+ type: build
+ params:
+ platform: ios
+ profile: production
+
+ publish_android_update:
+ name: Publish Android OTA update
+ needs: [get_android_build]
+ if: ${{ needs.get_android_build.outputs.build_id }}
+ type: update
+ params:
+ branch: production
+ platform: android
+
+ publish_ios_update:
+ name: Publish iOS OTA update
+ needs: [get_ios_build]
+ if: ${{ needs.get_ios_build.outputs.build_id }}
+ type: update
+ params:
+ branch: production
+ platform: ios
diff --git a/.github/actions/setup-thumbcode/action.yml b/.github/actions/setup-thumbcode/action.yml
index a5d51458..3260df07 100644
--- a/.github/actions/setup-thumbcode/action.yml
+++ b/.github/actions/setup-thumbcode/action.yml
@@ -2,14 +2,10 @@ name: 'Setup ThumbCode Environment'
description: 'Reusable setup action for ThumbCode workflows - installs Node, pnpm, dependencies, and generates tokens'
inputs:
- node-version:
- description: 'Node.js version to use'
+ node-version-file:
+ description: 'File containing Node.js version (defaults to .nvmrc)'
required: false
- default: '20'
- pnpm-version:
- description: 'pnpm version to use'
- required: false
- default: '10'
+ default: '.nvmrc'
generate-tokens:
description: 'Whether to generate design tokens'
required: false
@@ -24,13 +20,12 @@ runs:
steps:
- name: Install pnpm
uses: pnpm/action-setup@c5ba7f7862a0f64c1b1a05fbac13e0b8e86ba08c # v4
- with:
- version: ${{ inputs.pnpm-version }}
+ # Reads version from packageManager field in package.json
- name: Setup Node.js
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
+ uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
- node-version: ${{ inputs.node-version }}
+ node-version-file: ${{ inputs.node-version-file }}
cache: 'pnpm'
- name: Install dependencies
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
new file mode 100644
index 00000000..f77b06bc
--- /dev/null
+++ b/.github/workflows/cd.yml
@@ -0,0 +1,185 @@
+name: CD
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - 'src/**'
+ - 'app.json'
+ - 'eas.json'
+ - 'package.json'
+ pull_request:
+ branches: [main]
+ paths:
+ - 'src/**'
+ - 'app.json'
+ - 'eas.json'
+ - 'package.json'
+ workflow_dispatch:
+ inputs:
+ platform:
+ description: 'Platform to build'
+ required: true
+ default: 'all'
+ type: choice
+ options:
+ - all
+ - android
+ - ios
+ - web
+ profile:
+ description: 'Build profile'
+ required: true
+ default: 'preview'
+ type: choice
+ options:
+ - development
+ - preview
+ - production
+
+# Prevent concurrent deployments
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: false
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ # ============================================
+ # EAS Update for PRs (OTA Updates)
+ # ============================================
+ eas-update:
+ name: EAS Update (PR Preview)
+ if: github.event_name == 'pull_request'
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ contents: read
+ pull-requests: write
+
+ steps:
+ - name: Check for EXPO_TOKEN
+ id: check-token
+ env:
+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
+ run: |
+ if [ -z "$EXPO_TOKEN" ]; then
+ echo "::warning::EXPO_TOKEN secret is not configured. Skipping EAS update."
+ echo "Learn more: https://docs.expo.dev/eas-update/github-actions"
+ echo "has_token=false" >> $GITHUB_OUTPUT
+ else
+ echo "has_token=true" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Checkout code
+ if: steps.check-token.outputs.has_token == 'true'
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: Setup ThumbCode environment
+ if: steps.check-token.outputs.has_token == 'true'
+ uses: ./.github/actions/setup-thumbcode
+
+ - name: Setup Expo and EAS
+ if: steps.check-token.outputs.has_token == 'true'
+ uses: expo/expo-github-action@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # v8
+ with:
+ eas-version: latest
+ token: ${{ secrets.EXPO_TOKEN }}
+
+ - name: Create preview update
+ if: steps.check-token.outputs.has_token == 'true'
+ uses: expo/expo-github-action/preview@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # v8
+ with:
+ command: eas update --auto
+ env:
+ # Use production slug to match EAS project configuration
+ EXPO_PUBLIC_APP_ENV: production
+
+ # ============================================
+ # EAS Build - Android
+ # ============================================
+ build-android:
+ name: Build Android
+ if: |
+ (github.event_name == 'push' && github.ref == 'refs/heads/main') ||
+ (github.event_name == 'workflow_dispatch' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'android'))
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+
+ steps:
+ - name: Check for EXPO_TOKEN
+ env:
+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
+ run: |
+ if [ -z "$EXPO_TOKEN" ]; then
+ echo "::error::EXPO_TOKEN secret is required for EAS builds"
+ exit 1
+ fi
+
+ - name: Checkout code
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: Setup ThumbCode environment
+ uses: ./.github/actions/setup-thumbcode
+
+ - name: Setup Expo and EAS
+ uses: expo/expo-github-action@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # v8
+ with:
+ eas-version: latest
+ token: ${{ secrets.EXPO_TOKEN }}
+
+ - name: Build Android
+ run: |
+ PROFILE="${{ github.event.inputs.profile || 'preview' }}"
+ eas build --platform android --profile $PROFILE --non-interactive --no-wait
+
+ # ============================================
+ # EAS Build - iOS
+ # ============================================
+ build-ios:
+ name: Build iOS
+ if: |
+ (github.event_name == 'push' && github.ref == 'refs/heads/main') ||
+ (github.event_name == 'workflow_dispatch' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios'))
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+
+ steps:
+ - name: Check for EXPO_TOKEN
+ env:
+ EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
+ run: |
+ if [ -z "$EXPO_TOKEN" ]; then
+ echo "::error::EXPO_TOKEN secret is required for EAS builds"
+ exit 1
+ fi
+
+ - name: Checkout code
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: Setup ThumbCode environment
+ uses: ./.github/actions/setup-thumbcode
+
+ - name: Setup Expo and EAS
+ uses: expo/expo-github-action@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # v8
+ with:
+ eas-version: latest
+ token: ${{ secrets.EXPO_TOKEN }}
+
+ - name: Build iOS
+ run: |
+ PROFILE="${{ github.event.inputs.profile || 'preview' }}"
+ eas build --platform ios --profile $PROFILE --non-interactive --no-wait
+
+ # ============================================
+ # NOTE: App Store Submissions
+ # ============================================
+ # Production submission jobs are not yet configured.
+ # See issue #66 for required credentials and setup.
+ #
+ # Current release strategy:
+ # - Web staging: Automatic via Render.com (render.yaml)
+ # - Mobile builds: Download from expo.dev after EAS build completes
+ # - Debug APK: Can be downloaded from expo.dev build artifacts
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6d8e2d26..fbfa5438 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -60,7 +60,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
- fetch-depth: 0 # Shallow clones disabled for SonarCloud
+ fetch-depth: 0 # Shallow clones disabled for SonarCloud
- name: Setup ThumbCode environment
uses: ./.github/actions/setup-thumbcode
@@ -69,7 +69,7 @@ jobs:
run: pnpm run test:coverage
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
+ uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
@@ -78,7 +78,7 @@ jobs:
name: codecov-umbrella
- name: Upload coverage to Coveralls
- uses: coverallsapp/github-action@643bc377ffa44ace6394b2b5d0d3950076de9f63 # v2.3.0
+ uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -87,7 +87,7 @@ jobs:
flag-name: unit-tests
- name: SonarCloud Scan
- uses: SonarSource/sonarcloud-github-action@e44258b109568baa0df60ed515909fc6c72cba92 # v2.3.0
+ uses: SonarSource/sonarcloud-github-action@ffc3010689be73b8e5ae0c57ce35968afd7909e8 # v5
if: always()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -98,8 +98,8 @@ jobs:
-Dsonar.pullrequest.branch=${{ github.head_ref }}
-Dsonar.pullrequest.base=${{ github.base_ref }}
- build:
- name: Build
+ build-web:
+ name: Build Web
runs-on: ubuntu-latest
timeout-minutes: 15
@@ -116,13 +116,48 @@ jobs:
CI: true
- name: Upload build artifacts
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
if: success()
with:
name: web-build
path: dist/
retention-days: 7
+ e2e-web:
+ name: E2E Tests (Web)
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ needs: build-web
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: Setup ThumbCode environment
+ uses: ./.github/actions/setup-thumbcode
+
+ - name: Install Playwright browsers
+ run: npx playwright install --with-deps chromium
+
+ - name: Download web build
+ uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
+ with:
+ name: web-build
+ path: dist/
+
+ - name: Run E2E tests
+ run: pnpm run test:e2e:web
+ env:
+ CI: true
+
+ - name: Upload Playwright report
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ if: failure()
+ with:
+ name: playwright-report
+ path: playwright-report/
+ retention-days: 7
+
# Finalize Coveralls parallel build
coveralls-finish:
name: Finish Coveralls
@@ -132,7 +167,7 @@ jobs:
steps:
- name: Coveralls Finished
- uses: coverallsapp/github-action@643bc377ffa44ace6394b2b5d0d3950076de9f63 # v2.3.0
+ uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true
diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml
index 63eb70e2..163dd64b 100644
--- a/.github/workflows/deploy-gh-pages.yml
+++ b/.github/workflows/deploy-gh-pages.yml
@@ -1,8 +1,13 @@
-name: Deploy to GitHub Pages
+name: Deploy Documentation to GitHub Pages
on:
push:
branches: [main]
+ paths:
+ - 'docs/**'
+ - 'src/**/*.ts'
+ - 'src/**/*.tsx'
+ - '.github/workflows/deploy-gh-pages.yml'
workflow_dispatch:
permissions:
@@ -17,7 +22,7 @@ concurrency:
jobs:
build:
- name: Build Staging Web App
+ name: Build Documentation
runs-on: ubuntu-latest
timeout-minutes: 10
@@ -25,35 +30,108 @@ jobs:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - name: Use Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '20.x'
-
- name: Setup pnpm
- uses: pnpm/action-setup@v2
+ uses: pnpm/action-setup@c5ba7f7862a0f64c1b1a05fbac13e0b8e86ba08c # v4
+ # Reads version from packageManager field in package.json
+
+ - name: Use Node.js
+ uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
- version: 8
+ node-version-file: '.nvmrc'
+ cache: 'pnpm'
- name: Install dependencies
- run: pnpm install
+ run: pnpm install --frozen-lockfile
- - name: Build web app
- run: npx expo export --platform web
+ - name: Generate API documentation with TypeDoc
+ run: npx typedoc --out docs-dist/api src/index.ts --plugin typedoc-plugin-markdown
- - name: Inject no-cache headers for staging
+ - name: Build documentation site
run: |
- # Add no-cache meta tags to all HTML files for staging environment
- find dist -name "*.html" -exec sed -i 's/
/\n \n \n /' {} \;
- echo "Injected no-cache headers into $(find dist -name '*.html' | wc -l) HTML files"
+ # Create a simple docs site from markdown
+ mkdir -p docs-dist
+
+ # Copy documentation files
+ cp -r docs/* docs-dist/ 2>/dev/null || true
+ cp README.md docs-dist/ 2>/dev/null || true
+ cp CLAUDE.md docs-dist/ 2>/dev/null || true
+ cp DECISIONS.md docs-dist/ 2>/dev/null || true
+
+ # Create index.html
+ cat > docs-dist/index.html << 'HTMLEOF'
+
+
+
+
+
+ ThumbCode Documentation
+
+
+
+
+ ThumbCode Documentation
+ Code with your thumbs. A decentralized multi-agent mobile development platform.
+
+
+
+
+
+
+
+
+ HTMLEOF
- name: Setup Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
- name: Upload artifact
- uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
+ uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
with:
- path: 'dist'
+ path: 'docs-dist'
deploy:
name: Deploy to GitHub Pages
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 00000000..1d9b7831
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+22.12.0
diff --git a/app.config.ts b/app.config.ts
index b9536512..706f2dc1 100644
--- a/app.config.ts
+++ b/app.config.ts
@@ -136,7 +136,7 @@ export default ({ config }: ConfigContext): ExpoConfig => {
// EAS configuration
eas: {
- projectId: process.env.EXPO_PROJECT_ID || '',
+ projectId: process.env.EXPO_PROJECT_ID || '36e52acc-b39a-4bfa-a9dc-4a1053e87032',
},
// Public environment variables (accessible at runtime)
@@ -144,6 +144,6 @@ export default ({ config }: ConfigContext): ExpoConfig => {
githubClientId: process.env.EXPO_PUBLIC_GITHUB_CLIENT_ID || '',
},
- owner: process.env.EXPO_OWNER || 'thumbcode',
+ owner: process.env.EXPO_OWNER || 'jbcom',
};
};
diff --git a/app.json b/app.json
index 4cc111e2..9f16d81b 100644
--- a/app.json
+++ b/app.json
@@ -48,17 +48,16 @@
]
],
"experiments": {
- "typedRoutes": true,
- "baseUrl": "/thumbcode"
+ "typedRoutes": true
},
"extra": {
"router": {
"origin": false
},
"eas": {
- "projectId": "${EXPO_PROJECT_ID:-your-project-id}"
+ "projectId": "36e52acc-b39a-4bfa-a9dc-4a1053e87032"
}
},
- "owner": "${EXPO_OWNER:-thumbcode}"
+ "owner": "jbcom"
}
}
diff --git a/docs/memory-bank/DEVELOPMENT-LOG.md b/docs/memory-bank/DEVELOPMENT-LOG.md
index 61f35858..eb1acc4f 100644
--- a/docs/memory-bank/DEVELOPMENT-LOG.md
+++ b/docs/memory-bank/DEVELOPMENT-LOG.md
@@ -275,6 +275,82 @@ All compiled into NativeWind-compatible Tailwind config.
---
+## Market Research & Competitive Analysis (Jan 18, 2026)
+
+### AI Coding Assistant Market 2026
+
+**Market Size**: $4.91B (2024) → $30.1B projected (2032) at 27.1% CAGR
+
+**Key Competitors**:
+- GitHub Copilot (68% developer adoption)
+- ChatGPT (82% usage for coding)
+- Claude (41% developer usage)
+- Cursor (leading "agentic IDE" with multi-platform integration)
+- Windsurf (Codeium's "world's first agentic IDE")
+- Various CLI tools: Claude Code, Gemini CLI
+
+**2026 Trends**:
+1. **Quality > Speed** — 2025 was "year of AI speed"; 2026 focuses on quality/governance
+2. **Multi-Platform Integration** — Winning pattern: terminal + IDE + web + desktop
+3. **Agent Mode** — Autonomous multi-step workflows (refactoring, bug fixing, modules)
+4. **Security Concerns** — 48% of AI-generated code has potential vulnerabilities
+5. **Mobile "Vibe Coding"** — Emerging category with natural language prompts
+
+### ThumbCode's Competitive Advantage
+
+**CRITICAL INSIGHT**: NO major competitor is mobile-first.
+
+| Differentiator | ThumbCode | Competition |
+|----------------|-----------|-------------|
+| **Platform** | Mobile-first | Desktop/web-first |
+| **Architecture** | Decentralized BYOK | Cloud-hosted |
+| **Privacy** | User owns keys | Vendor manages keys |
+| **Cost Model** | $0 infrastructure | Per-seat subscriptions |
+| **Agent Model** | Multi-agent orchestration | Single assistant |
+
+ThumbCode addresses the **top market concerns**:
+- Privacy/Security → BYOK model with SecureStore
+- Cost → Zero per-user cost
+- Mobile accessibility → Only mobile-first solution
+- Agent capabilities → Full multi-agent orchestration
+
+---
+
+## 1.0 Roadmap Execution Plan
+
+### Phase 1: Foundation (Current Sprint)
+- [x] EAS Workflows (development, production, preview)
+- [x] CI/CD pipeline with GitHub Actions
+- [ ] Fix GitHub Pages loading issue (#63)
+- [ ] Configure staging deployment (Render.com)
+- [ ] Environment configuration (.env validation)
+
+### Phase 2: Core Services (Next Sprint)
+- [ ] Credential management (expo-secure-store)
+- [ ] Git service (isomorphic-git integration)
+- [ ] Zustand state management stores
+- [ ] Error handling and logging infrastructure
+
+### Phase 3: Agent System (Major Milestone)
+- [ ] Agent orchestration engine
+- [ ] Specialized agents (Architect, Implementer, Reviewer, Tester)
+- [ ] Chat system with streaming
+- [ ] MCP integration
+
+### Phase 4: UI/UX Polish
+- [ ] Expand component library (40+ components)
+- [ ] Implement all screens from Canva designs
+- [ ] Guided onboarding flow
+- [ ] Accessibility compliance (WCAG AA)
+
+### Phase 5: Production Hardening
+- [ ] Security audit
+- [ ] Performance optimization
+- [ ] Analytics and monitoring (privacy-focused)
+- [ ] App store submission
+
+---
+
## Open Questions / Future Decisions
1. **Domain registration** — thumbcode.app, thumbcode.dev not yet purchased
diff --git a/package.json b/package.json
index 8488030e..ce1c447b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,7 @@
{
"name": "thumbcode",
"version": "0.1.0",
+ "packageManager": "pnpm@10.11.0",
"description": "Code with your thumbs. A decentralized multi-agent mobile development platform.",
"main": "expo-router/entry",
"scripts": {
@@ -37,7 +38,6 @@
"@anthropic-ai/sdk": "^0.32.0",
"@react-native-async-storage/async-storage": "^2.0.0",
"@react-native-community/netinfo": "^11.4.1",
- "react-native-ssl-public-key-pinning": "^1.2.6",
"@react-navigation/native": "^7.0.0",
"@thumbcode/config": "workspace:*",
"@thumbcode/core": "workspace:*",
@@ -63,6 +63,7 @@
"expo-secure-store": "~14.0.0",
"expo-splash-screen": "~0.29.0",
"expo-status-bar": "~2.0.0",
+ "expo-updates": "^29.0.16",
"expo-web-browser": "~14.0.0",
"immer": "^10.2.0",
"isomorphic-git": "^1.27.0",
@@ -76,6 +77,7 @@
"react-native-reanimated": "~3.16.0",
"react-native-safe-area-context": "~4.12.0",
"react-native-screens": "~4.0.0",
+ "react-native-ssl-public-key-pinning": "^1.2.6",
"react-native-svg": "~15.8.0",
"react-native-web": "~0.19.13",
"tailwindcss": "^3.4.0",
@@ -104,6 +106,8 @@
"jest-expo": "~52.0.6",
"react-test-renderer": "18.3.1",
"serve": "^14.2.5",
+ "typedoc": "^0.28.0",
+ "typedoc-plugin-markdown": "^4.9.0",
"typescript": "~5.6.0"
},
"pnpm": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8c2f0836..742c9ce1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -95,6 +95,9 @@ importers:
expo-status-bar:
specifier: ~2.0.0
version: 2.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
+ expo-updates:
+ specifier: ^29.0.16
+ version: 29.0.16(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
expo-web-browser:
specifier: ~14.0.0
version: 14.0.2(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))
@@ -109,7 +112,7 @@ importers:
version: 4.17.22
nativewind:
specifier: ^4.1.0
- version: 4.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0))
+ version: 4.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2))
openai:
specifier: ^4.70.0
version: 4.104.0(ws@8.19.0)(zod@3.25.76)
@@ -145,7 +148,7 @@ importers:
version: 0.19.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
tailwindcss:
specifier: ^3.4.0
- version: 3.4.19(tsx@4.21.0)
+ version: 3.4.19(tsx@4.21.0)(yaml@2.8.2)
zod:
specifier: ^3.23.0
version: 3.25.76
@@ -216,6 +219,12 @@ importers:
serve:
specifier: ^14.2.5
version: 14.2.5
+ typedoc:
+ specifier: ^0.28.0
+ version: 0.28.16(typescript@5.6.3)
+ typedoc-plugin-markdown:
+ specifier: ^4.9.0
+ version: 4.9.0(typedoc@0.28.16(typescript@5.6.3))
typescript:
specifier: ~5.6.0
version: 5.6.3
@@ -350,7 +359,7 @@ importers:
version: 4.0.22(ca3003e1f7f8d1ffc6d1fe044df18e11)
nativewind:
specifier: ^4.1.0
- version: 4.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0))
+ version: 4.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2))
react:
specifier: '>=18.0.0'
version: 18.3.1
@@ -1439,15 +1448,27 @@ packages:
'@expo/code-signing-certificates@0.0.5':
resolution: {integrity: sha512-BNhXkY1bblxKZpltzAx98G2Egj9g1Q+JRcvR7E99DOj862FTCX+ZPsAUtPTr7aHxwtrL7+fL3r0JSmM9kBm+Bw==}
+ '@expo/code-signing-certificates@0.0.6':
+ resolution: {integrity: sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==}
+
+ '@expo/config-plugins@54.0.4':
+ resolution: {integrity: sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==}
+
'@expo/config-plugins@9.0.17':
resolution: {integrity: sha512-m24F1COquwOm7PBl5wRbkT9P9DviCXe0D7S7nQsolfbhdCWuvMkfXeoWmgjtdhy7sDlOyIgBrAdnB6MfsWKqIg==}
'@expo/config-types@52.0.5':
resolution: {integrity: sha512-AMDeuDLHXXqd8W+0zSjIt7f37vUd/BP8p43k68NHpyAvQO+z8mbQZm3cNQVAMySeayK2XoPigAFB1JF2NFajaA==}
+ '@expo/config-types@54.0.10':
+ resolution: {integrity: sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==}
+
'@expo/config@10.0.11':
resolution: {integrity: sha512-nociJ4zr/NmbVfMNe9j/+zRlt7wz/siISu7PjdWE4WE+elEGxWWxsGzltdJG0llzrM+khx8qUiFK5aiVcdMBww==}
+ '@expo/config@12.0.13':
+ resolution: {integrity: sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==}
+
'@expo/devcert@1.2.1':
resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==}
@@ -1488,6 +1509,9 @@ packages:
'@expo/plist@0.2.2':
resolution: {integrity: sha512-ZZGvTO6vEWq02UAPs3LIdja+HRO18+LRI5QuDl6Hs3Ps7KX7xU6Y6kjahWKY37Rx2YjNpX07dGpBFzzC+vKa2g==}
+ '@expo/plist@0.4.8':
+ resolution: {integrity: sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==}
+
'@expo/prebuild-config@8.2.0':
resolution: {integrity: sha512-CxiPpd980s0jyxi7eyN3i/7YKu3XL+8qPjBZUCYtc0+axpGweqIkq2CslyLSKHyqVyH/zlPkbVgWdyiYavFS5Q==}
@@ -1518,6 +1542,9 @@ packages:
resolution: {integrity: sha512-ReZxZ8pdnoI3tP/dNnJdnmAk7uLT4FjsKDGW7YeDdvdOMz2XCQSmSCM9IWlrXuWtMF9zeSB6WJtEhCQ41gQOfw==}
hasBin: true
+ '@gerrit0/mini-shiki@3.21.0':
+ resolution: {integrity: sha512-9PrsT5DjZA+w3lur/aOIx3FlDeHdyCEFlv9U+fmsVyjPZh61G5SYURQ/1ebe2U63KbDmI2V8IhIUegWb8hjOyg==}
+
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -1674,6 +1701,14 @@ packages:
cpu: [x64]
os: [win32]
+ '@isaacs/balanced-match@4.0.1':
+ resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
+ engines: {node: 20 || >=22}
+
+ '@isaacs/brace-expansion@5.0.0':
+ resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
+ engines: {node: 20 || >=22}
+
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@@ -2002,6 +2037,21 @@ packages:
'@segment/loosely-validate-event@2.0.0':
resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==}
+ '@shikijs/engine-oniguruma@3.21.0':
+ resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==}
+
+ '@shikijs/langs@3.21.0':
+ resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==}
+
+ '@shikijs/themes@3.21.0':
+ resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==}
+
+ '@shikijs/types@3.21.0':
+ resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==}
+
+ '@shikijs/vscode-textmate@10.0.2':
+ resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
+
'@sinclair/typebox@0.27.8':
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
@@ -2062,6 +2112,9 @@ packages:
'@types/hammerjs@2.0.46':
resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==}
+ '@types/hast@3.0.4':
+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+
'@types/istanbul-lib-coverage@2.0.6':
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
@@ -2118,6 +2171,9 @@ packages:
'@types/tough-cookie@4.0.5':
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
+ '@types/unist@3.0.3':
+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+
'@types/yargs-parser@21.0.3':
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
@@ -2478,6 +2534,9 @@ packages:
arch@2.2.0:
resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==}
+ arg@4.1.0:
+ resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==}
+
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
@@ -3586,6 +3645,9 @@ packages:
peerDependencies:
expo: '*'
+ expo-eas-client@1.0.8:
+ resolution: {integrity: sha512-5or11NJhSeDoHHI6zyvQDW2cz/yFyE+1Cz8NTs5NK8JzC7J0JrkUgptWtxyfB6Xs/21YRNifd3qgbBN3hfKVgA==}
+
expo-file-system@18.0.12:
resolution: {integrity: sha512-HAkrd/mb8r+G3lJ9MzmGeuW2B+BxQR1joKfeCyY4deLl1zoZ48FrAWjgZjHK9aHUVhJ0ehzInu/NQtikKytaeg==}
peerDependencies:
@@ -3614,6 +3676,9 @@ packages:
react-native-web:
optional: true
+ expo-json-utils@0.15.0:
+ resolution: {integrity: sha512-duRT6oGl80IDzH2LD2yEFWNwGIC2WkozsB6HF3cDYNoNNdUvFk6uN3YiwsTsqVM/D0z6LEAQ01/SlYvN+Fw0JQ==}
+
expo-keep-awake@14.0.3:
resolution: {integrity: sha512-6Jh94G6NvTZfuLnm2vwIpKe3GdOiVBuISl7FI8GqN0/9UOg9E0WXXp5cDcfAG8bn80RfgLJS8P7EPUGTZyOvhg==}
peerDependencies:
@@ -3631,6 +3696,11 @@ packages:
peerDependencies:
expo: '*'
+ expo-manifests@1.0.10:
+ resolution: {integrity: sha512-oxDUnURPcL4ZsOBY6X1DGWGuoZgVAFzp6PISWV7lPP2J0r8u1/ucuChBgpK7u1eLGFp6sDIPwXyEUCkI386XSQ==}
+ peerDependencies:
+ expo: '*'
+
expo-modules-autolinking@2.0.8:
resolution: {integrity: sha512-DezgnEYFQYic8hKGhkbztBA3QUmSftjaNDIKNAtS2iGJmzCcNIkatjN2slFDSWjSTNo8gOvPQyMKfyHWFvLpOQ==}
hasBin: true
@@ -3680,6 +3750,22 @@ packages:
react: '*'
react-native: '*'
+ expo-structured-headers@5.0.0:
+ resolution: {integrity: sha512-RmrBtnSphk5REmZGV+lcdgdpxyzio5rJw8CXviHE6qH5pKQQ83fhMEcigvrkBdsn2Efw2EODp4Yxl1/fqMvOZw==}
+
+ expo-updates-interface@2.0.0:
+ resolution: {integrity: sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg==}
+ peerDependencies:
+ expo: '*'
+
+ expo-updates@29.0.16:
+ resolution: {integrity: sha512-E9/fxRz/Eurtc7hxeI/6ZPyHH3To9Xoccm1kXoICZTRojmuTo+dx0Xv53UHyHn4G5zGMezyaKF2Qtj3AKcT93w==}
+ hasBin: true
+ peerDependencies:
+ expo: '*'
+ react: '*'
+ react-native: '*'
+
expo-web-browser@14.0.2:
resolution: {integrity: sha512-Hncv2yojhTpHbP6SGWARBFdl7P6wBHc1O8IKaNsH0a/IEakq887o1eRhLxZ5IwztPQyRDhpqHdgJ+BjWolOnwA==}
peerDependencies:
@@ -3918,6 +4004,10 @@ packages:
resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==}
engines: {node: '>=6'}
+ getenv@2.0.0:
+ resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==}
+ engines: {node: '>=6'}
+
git-raw-commits@4.0.0:
resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==}
engines: {node: '>=16'}
@@ -3938,6 +4028,10 @@ packages:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
hasBin: true
+ glob@13.0.0:
+ resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==}
+ engines: {node: 20 || >=22}
+
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
@@ -4711,6 +4805,9 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ linkify-it@5.0.0:
+ resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
+
loader-runner@4.3.1:
resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==}
engines: {node: '>=6.11.5'}
@@ -4784,9 +4881,16 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+ lru-cache@11.2.4:
+ resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==}
+ engines: {node: 20 || >=22}
+
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lunr@2.3.9:
+ resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==}
+
make-dir@2.1.0:
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
engines: {node: '>=6'}
@@ -4801,6 +4905,10 @@ packages:
makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+ markdown-it@14.1.0:
+ resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
+ hasBin: true
+
marky@1.3.0:
resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==}
@@ -4819,6 +4927,9 @@ packages:
mdn-data@2.0.14:
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
+ mdurl@2.0.0:
+ resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
+
memoize-one@5.2.1:
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
@@ -4943,6 +5054,10 @@ packages:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
+ minimatch@10.1.1:
+ resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==}
+ engines: {node: 20 || >=22}
+
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -5289,6 +5404,10 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
+ path-scurry@2.0.1:
+ resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
+ engines: {node: 20 || >=22}
+
path-to-regexp@3.3.0:
resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==}
@@ -5447,6 +5566,10 @@ packages:
pump@3.0.3:
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
+ punycode.js@2.3.1:
+ resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
+ engines: {node: '>=6'}
+
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -6345,6 +6468,19 @@ packages:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'}
+ typedoc-plugin-markdown@4.9.0:
+ resolution: {integrity: sha512-9Uu4WR9L7ZBgAl60N/h+jqmPxxvnC9nQAlnnO/OujtG2ubjnKTVUFY1XDhcMY+pCqlX3N2HsQM2QTYZIU9tJuw==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ typedoc: 0.28.x
+
+ typedoc@0.28.16:
+ resolution: {integrity: sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==}
+ engines: {node: '>= 18', pnpm: '>= 10'}
+ hasBin: true
+ peerDependencies:
+ typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x
+
typescript@5.6.3:
resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
engines: {node: '>=14.17'}
@@ -6358,6 +6494,9 @@ packages:
resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==}
hasBin: true
+ uc.micro@2.1.0:
+ resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
+
uglify-js@3.19.3:
resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
engines: {node: '>=0.8.0'}
@@ -6696,6 +6835,11 @@ packages:
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
engines: {node: '>=18'}
+ yaml@2.8.2:
+ resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
+ engines: {node: '>= 14.6'}
+ hasBin: true
+
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
@@ -8041,6 +8185,29 @@ snapshots:
node-forge: 1.3.3
nullthrows: 1.1.1
+ '@expo/code-signing-certificates@0.0.6':
+ dependencies:
+ node-forge: 1.3.3
+
+ '@expo/config-plugins@54.0.4':
+ dependencies:
+ '@expo/config-types': 54.0.10
+ '@expo/json-file': 10.0.8
+ '@expo/plist': 0.4.8
+ '@expo/sdk-runtime-versions': 1.0.0
+ chalk: 4.1.2
+ debug: 4.4.3
+ getenv: 2.0.0
+ glob: 13.0.0
+ resolve-from: 5.0.0
+ semver: 7.7.3
+ slash: 3.0.0
+ slugify: 1.6.6
+ xcode: 3.0.1
+ xml2js: 0.6.0
+ transitivePeerDependencies:
+ - supports-color
+
'@expo/config-plugins@9.0.17':
dependencies:
'@expo/config-types': 52.0.5
@@ -8062,6 +8229,8 @@ snapshots:
'@expo/config-types@52.0.5': {}
+ '@expo/config-types@54.0.10': {}
+
'@expo/config@10.0.11':
dependencies:
'@babel/code-frame': 7.10.4
@@ -8080,6 +8249,24 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@expo/config@12.0.13':
+ dependencies:
+ '@babel/code-frame': 7.10.4
+ '@expo/config-plugins': 54.0.4
+ '@expo/config-types': 54.0.10
+ '@expo/json-file': 10.0.8
+ deepmerge: 4.3.1
+ getenv: 2.0.0
+ glob: 13.0.0
+ require-from-string: 2.0.2
+ resolve-from: 5.0.0
+ resolve-workspace-root: 2.0.1
+ semver: 7.7.3
+ slugify: 1.6.6
+ sucrase: 3.35.1
+ transitivePeerDependencies:
+ - supports-color
+
'@expo/devcert@1.2.1':
dependencies:
'@expo/sudo-prompt': 9.3.2
@@ -8188,6 +8375,12 @@ snapshots:
base64-js: 1.5.1
xmlbuilder: 14.0.0
+ '@expo/plist@0.4.8':
+ dependencies:
+ '@xmldom/xmldom': 0.8.11
+ base64-js: 1.5.1
+ xmlbuilder: 15.1.1
+
'@expo/prebuild-config@8.2.0':
dependencies:
'@expo/config': 10.0.11
@@ -8246,6 +8439,14 @@ snapshots:
find-up: 5.0.0
js-yaml: 4.1.1
+ '@gerrit0/mini-shiki@3.21.0':
+ dependencies:
+ '@shikijs/engine-oniguruma': 3.21.0
+ '@shikijs/langs': 3.21.0
+ '@shikijs/themes': 3.21.0
+ '@shikijs/types': 3.21.0
+ '@shikijs/vscode-textmate': 10.0.2
+
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
@@ -8355,6 +8556,12 @@ snapshots:
'@img/sharp-win32-x64@0.34.5':
optional: true
+ '@isaacs/balanced-match@4.0.1': {}
+
+ '@isaacs/brace-expansion@5.0.0':
+ dependencies:
+ '@isaacs/balanced-match': 4.0.1
+
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
@@ -9002,6 +9209,26 @@ snapshots:
component-type: 1.2.2
join-component: 1.1.0
+ '@shikijs/engine-oniguruma@3.21.0':
+ dependencies:
+ '@shikijs/types': 3.21.0
+ '@shikijs/vscode-textmate': 10.0.2
+
+ '@shikijs/langs@3.21.0':
+ dependencies:
+ '@shikijs/types': 3.21.0
+
+ '@shikijs/themes@3.21.0':
+ dependencies:
+ '@shikijs/types': 3.21.0
+
+ '@shikijs/types@3.21.0':
+ dependencies:
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
+ '@shikijs/vscode-textmate@10.0.2': {}
+
'@sinclair/typebox@0.27.8': {}
'@sinonjs/commons@3.0.1':
@@ -9075,6 +9302,10 @@ snapshots:
'@types/hammerjs@2.0.46': {}
+ '@types/hast@3.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
'@types/istanbul-lib-coverage@2.0.6': {}
'@types/istanbul-lib-report@3.0.3':
@@ -9138,6 +9369,8 @@ snapshots:
'@types/tough-cookie@4.0.5': {}
+ '@types/unist@3.0.3': {}
+
'@types/yargs-parser@21.0.3': {}
'@types/yargs@17.0.35':
@@ -9515,6 +9748,8 @@ snapshots:
arch@2.2.0: {}
+ arg@4.1.0: {}
+
arg@5.0.2: {}
argparse@1.0.10:
@@ -10879,6 +11114,8 @@ snapshots:
expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
ua-parser-js: 0.7.41
+ expo-eas-client@1.0.8: {}
+
expo-file-system@18.0.12(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)):
dependencies:
expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
@@ -10903,6 +11140,8 @@ snapshots:
optionalDependencies:
react-native-web: 0.19.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ expo-json-utils@0.15.0: {}
+
expo-keep-awake@14.0.3(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react@18.3.1):
dependencies:
expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
@@ -10923,6 +11162,14 @@ snapshots:
expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
invariant: 2.2.4
+ expo-manifests@1.0.10(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)):
+ dependencies:
+ '@expo/config': 12.0.13
+ expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
+ expo-json-utils: 0.15.0
+ transitivePeerDependencies:
+ - supports-color
+
expo-modules-autolinking@2.0.8:
dependencies:
'@expo/spawn-async': 1.7.2
@@ -10998,6 +11245,34 @@ snapshots:
react: 18.3.1
react-native: 0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)
+ expo-structured-headers@5.0.0: {}
+
+ expo-updates-interface@2.0.0(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)):
+ dependencies:
+ expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
+
+ expo-updates@29.0.16(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1):
+ dependencies:
+ '@expo/code-signing-certificates': 0.0.6
+ '@expo/plist': 0.4.8
+ '@expo/spawn-async': 1.7.2
+ arg: 4.1.0
+ chalk: 4.1.2
+ debug: 4.4.3
+ expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
+ expo-eas-client: 1.0.8
+ expo-manifests: 1.0.10(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))
+ expo-structured-headers: 5.0.0
+ expo-updates-interface: 2.0.0(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))
+ getenv: 2.0.0
+ glob: 13.0.0
+ ignore: 5.3.2
+ react: 18.3.1
+ react-native: 0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)
+ resolve-from: 5.0.0
+ transitivePeerDependencies:
+ - supports-color
+
expo-web-browser@14.0.2(expo@52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)):
dependencies:
expo: 52.0.48(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@expo/metro-runtime@4.0.1(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
@@ -11278,6 +11553,8 @@ snapshots:
getenv@1.0.0: {}
+ getenv@2.0.0: {}
+
git-raw-commits@4.0.0:
dependencies:
dargs: 8.1.0
@@ -11303,6 +11580,12 @@ snapshots:
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
+ glob@13.0.0:
+ dependencies:
+ minimatch: 10.1.1
+ minipass: 7.1.2
+ path-scurry: 2.0.1
+
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
@@ -12318,6 +12601,10 @@ snapshots:
lines-and-columns@1.2.4: {}
+ linkify-it@5.0.0:
+ dependencies:
+ uc.micro: 2.1.0
+
loader-runner@4.3.1: {}
locate-path@3.0.0:
@@ -12375,10 +12662,14 @@ snapshots:
lru-cache@10.4.3: {}
+ lru-cache@11.2.4: {}
+
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
+ lunr@2.3.9: {}
+
make-dir@2.1.0:
dependencies:
pify: 4.0.1
@@ -12394,6 +12685,15 @@ snapshots:
dependencies:
tmpl: 1.0.5
+ markdown-it@14.1.0:
+ dependencies:
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.0
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
+
marky@1.3.0: {}
math-intrinsics@1.1.0: {}
@@ -12410,6 +12710,8 @@ snapshots:
mdn-data@2.0.14: {}
+ mdurl@2.0.0: {}
+
memoize-one@5.2.1: {}
memoize-one@6.0.0: {}
@@ -12625,6 +12927,10 @@ snapshots:
min-indent@1.0.1: {}
+ minimatch@10.1.1:
+ dependencies:
+ '@isaacs/brace-expansion': 5.0.0
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.12
@@ -12681,12 +12987,12 @@ snapshots:
napi-postinstall@0.3.4: {}
- nativewind@4.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0)):
+ nativewind@4.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)):
dependencies:
comment-json: 4.5.1
debug: 4.4.3
- react-native-css-interop: 0.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0))
- tailwindcss: 3.4.19(tsx@4.21.0)
+ react-native-css-interop: 0.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2))
+ tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2)
transitivePeerDependencies:
- react
- react-native
@@ -12960,6 +13266,11 @@ snapshots:
lru-cache: 10.4.3
minipass: 7.1.2
+ path-scurry@2.0.1:
+ dependencies:
+ lru-cache: 11.2.4
+ minipass: 7.1.2
+
path-to-regexp@3.3.0: {}
path-type@4.0.0: {}
@@ -13016,13 +13327,14 @@ snapshots:
camelcase-css: 2.0.1
postcss: 8.5.6
- postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0):
+ postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2):
dependencies:
lilconfig: 3.1.3
optionalDependencies:
jiti: 1.21.7
postcss: 8.5.6
tsx: 4.21.0
+ yaml: 2.8.2
postcss-nested@6.2.0(postcss@8.5.6):
dependencies:
@@ -13092,6 +13404,8 @@ snapshots:
end-of-stream: 1.4.5
once: 1.4.0
+ punycode.js@2.3.1: {}
+
punycode@2.3.1: {}
pure-rand@6.1.0: {}
@@ -13164,7 +13478,7 @@ snapshots:
react-is@19.2.3: {}
- react-native-css-interop@0.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0)):
+ react-native-css-interop@0.2.1(react-native-reanimated@3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-safe-area-context@4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native-svg@15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1))(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)):
dependencies:
'@babel/helper-module-imports': 7.28.6
'@babel/traverse': 7.28.6
@@ -13175,7 +13489,7 @@ snapshots:
react-native: 0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1)
react-native-reanimated: 3.16.7(@babel/core@7.28.6)(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
semver: 7.7.3
- tailwindcss: 3.4.19(tsx@4.21.0)
+ tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2)
optionalDependencies:
react-native-safe-area-context: 4.12.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
react-native-svg: 15.8.0(react-native@0.76.0(@babel/core@7.28.6)(@babel/preset-env@7.28.6(@babel/core@7.28.6))(@types/react@18.3.27)(react@18.3.1))(react@18.3.1)
@@ -13960,7 +14274,7 @@ snapshots:
symbol-tree@3.2.4: {}
- tailwindcss@3.4.19(tsx@4.21.0):
+ tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -13979,7 +14293,7 @@ snapshots:
postcss: 8.5.6
postcss-import: 15.1.0(postcss@8.5.6)
postcss-js: 4.1.0(postcss@8.5.6)
- postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)
+ postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2)
postcss-nested: 6.2.0(postcss@8.5.6)
postcss-selector-parser: 6.1.2
resolve: 1.22.11
@@ -14178,12 +14492,27 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
+ typedoc-plugin-markdown@4.9.0(typedoc@0.28.16(typescript@5.6.3)):
+ dependencies:
+ typedoc: 0.28.16(typescript@5.6.3)
+
+ typedoc@0.28.16(typescript@5.6.3):
+ dependencies:
+ '@gerrit0/mini-shiki': 3.21.0
+ lunr: 2.3.9
+ markdown-it: 14.1.0
+ minimatch: 9.0.5
+ typescript: 5.6.3
+ yaml: 2.8.2
+
typescript@5.6.3: {}
ua-parser-js@0.7.41: {}
ua-parser-js@1.0.41: {}
+ uc.micro@2.1.0: {}
+
uglify-js@3.19.3:
optional: true
@@ -14522,6 +14851,8 @@ snapshots:
yallist@5.0.0: {}
+ yaml@2.8.2: {}
+
yargs-parser@21.1.1: {}
yargs@17.7.2:
diff --git a/render.yaml b/render.yaml
new file mode 100644
index 00000000..0af11634
--- /dev/null
+++ b/render.yaml
@@ -0,0 +1,49 @@
+# Render Blueprint for ThumbCode Staging
+# https://render.com/docs/blueprint-spec
+
+services:
+ - type: web
+ name: thumbcode-staging
+ runtime: static
+ buildCommand: corepack enable && pnpm install --frozen-lockfile && npx expo export --platform web
+ staticPublishPath: ./dist
+ pullRequestPreviewsEnabled: true
+ headers:
+ # Security headers
+ - path: /*
+ name: X-Frame-Options
+ value: DENY
+ - path: /*
+ name: X-Content-Type-Options
+ value: nosniff
+ - path: /*
+ name: Referrer-Policy
+ value: strict-origin-when-cross-origin
+ - path: /*
+ name: Strict-Transport-Security
+ value: max-age=31536000; includeSubDomains
+ - path: /*
+ name: Permissions-Policy
+ value: camera=(), microphone=(), geolocation=()
+ # Cache static assets aggressively (hashed filenames)
+ # NOTE: Specific paths must come BEFORE /* to avoid nondeterministic matching
+ - path: /assets/*
+ name: Cache-Control
+ value: public, max-age=31536000, immutable
+ - path: /_expo/*
+ name: Cache-Control
+ value: public, max-age=31536000, immutable
+ # Staging: no-cache for HTML to always get fresh builds
+ - path: /*
+ name: Cache-Control
+ value: no-cache, no-store, must-revalidate
+ routes:
+ # SPA fallback - all routes serve index.html
+ - type: rewrite
+ source: /*
+ destination: /index.html
+ envVars:
+ - key: NODE_VERSION
+ value: 22
+ - key: PNPM_VERSION
+ value: 10