diff --git a/.eas/workflows/preview.yml b/.eas/workflows/preview.yml new file mode 100644 index 0000000..045d5f7 --- /dev/null +++ b/.eas/workflows/preview.yml @@ -0,0 +1,22 @@ +name: Preview build (internal, TEST distribution) + +# TEST distribution is EAS internal distribution, not a store — see docs/deploy.md. Triggers on +# `main` only; the repo's default branch should be `main` (see checklist in the deploy plan). +on: + push: + branches: ['main'] + +jobs: + build_android_preview: + name: Build Android (preview) + type: build + params: + platform: android + profile: preview + + build_ios_preview: + name: Build iOS (preview) + type: build + params: + platform: ios + profile: preview diff --git a/.eas/workflows/release.yml b/.eas/workflows/release.yml new file mode 100644 index 0000000..caad9ba --- /dev/null +++ b/.eas/workflows/release.yml @@ -0,0 +1,76 @@ +name: Release (production build + store submit) + +# Triggered by pushing a `vX.Y.Z` tag (ChatbotX's own release) or manually for a white-label +# customer build via `eas workflow:run .eas/workflows/release.yml -F brand=`. A +# non-default `brand` is expected to live in the private `chatbotx-mobile-brands` repo — see +# docs/white-label.md — cloned into `brands/` before the build so the customer's brand.json/assets +# are never committed to this (public) repo. +on: + push: + tags: ['v*'] + workflow_dispatch: + inputs: + brand: + type: string + description: 'Brand id (brands//) to build and submit' + default: chatbotx + +jobs: + fetch_brand: + name: Fetch customer brand overlay + type: custom + if: ${{ inputs.brand != '' && inputs.brand != 'chatbotx' }} + steps: + - uses: eas/checkout + - name: Clone private brand overlay repo + run: | + set -euo pipefail + : "${BRANDS_REPO_TOKEN:?BRANDS_REPO_TOKEN secret is not set}" + rm -rf "brands/${{ inputs.brand }}" /tmp/chatbotx-mobile-brands + git clone --depth 1 \ + "https://x-access-token:${BRANDS_REPO_TOKEN}@github.com/ChatbotXIO/chatbotx-mobile-brands.git" \ + /tmp/chatbotx-mobile-brands + test -f "/tmp/chatbotx-mobile-brands/${{ inputs.brand }}/brand.json" \ + || { echo "No brand.json for brand '${{ inputs.brand }}' in chatbotx-mobile-brands"; exit 1; } + cp -R "/tmp/chatbotx-mobile-brands/${{ inputs.brand }}" "brands/${{ inputs.brand }}" + + build_android_production: + name: Build Android (production) + type: build + # `after` (not `needs`) — `needs` requires the dependency to *succeed*, which would block this + # job whenever `fetch_brand` is skipped (the default chatbotx brand, nothing to clone). `after` + # only waits for it to complete, success or skip, so the `if` below is the only real gate. + after: [fetch_brand] + if: ${{ always() && (after.fetch_brand.status == 'success' || after.fetch_brand.status == 'skipped') }} + env: + BRAND: ${{ inputs.brand || 'chatbotx' }} + params: + platform: android + profile: production + + build_ios_production: + name: Build iOS (production) + type: build + after: [fetch_brand] + if: ${{ always() && (after.fetch_brand.status == 'success' || after.fetch_brand.status == 'skipped') }} + env: + BRAND: ${{ inputs.brand || 'chatbotx' }} + params: + platform: ios + profile: production + + submit_android_production: + name: Submit to Play Store + type: submit + needs: [build_android_production] + params: + build_id: ${{ needs.build_android_production.outputs.build_id }} + profile: production + + submit_ios_production: + name: Submit to App Store + type: submit + needs: [build_ios_production] + params: + build_id: ${{ needs.build_ios_production.outputs.build_id }} + profile: production diff --git a/.eas/workflows/update.yml b/.eas/workflows/update.yml new file mode 100644 index 0000000..5ea4bbc --- /dev/null +++ b/.eas/workflows/update.yml @@ -0,0 +1,27 @@ +name: OTA update + +# Automatic: every push to main publishes a JS-only OTA update to the `preview` (TEST) channel — +# the common case when no native config changed. Manual: publish to either channel on demand via +# `eas workflow:run .eas/workflows/update.yml -F channel=production`. See docs/deploy.md for the +# `runtimeVersion: appVersion` implication (a native change requires a new build, not just an OTA +# update, or the update won't be receivable by builds on a different `version`). +on: + push: + branches: ['main'] + workflow_dispatch: + inputs: + channel: + type: choice + description: 'Which channel to publish the OTA update to' + options: + - preview + - production + default: preview + +jobs: + publish_update: + name: Publish OTA update + type: update + environment: ${{ inputs.channel || 'preview' }} + params: + channel: ${{ inputs.channel || 'preview' }} diff --git a/.easignore b/.easignore new file mode 100644 index 0000000..a4c8280 --- /dev/null +++ b/.easignore @@ -0,0 +1,2 @@ +# CodeGraph local index (contains a live daemon socket file that cannot be archived) +.codegraph diff --git a/.env.example b/.env.example index ff699c0..27bb1bf 100644 --- a/.env.example +++ b/.env.example @@ -4,3 +4,11 @@ API_BASE_URL=http://localhost:3123 # PartyKit realtime server URL. Defaults to the local `partykit dev` port when unset. WS_URL=http://localhost:1999 + +# Selects brands//brand.json — app id, name, colors, icons, EAS project. `chatbotx` is the +# default brand tracked in this repo; see docs/white-label.md to add your own. +BRAND=chatbotx + +# development | preview | production — suffixes the bundle id/app name and picks the EAS Update +# channel so dev/test/prod builds can coexist on one device. See docs/deploy.md. +APP_ENV=development diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3a8157..24e799a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,11 +9,11 @@ jobs: ci: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7 with: node-version: 22 cache: pnpm @@ -35,3 +35,9 @@ jobs: - name: Expo config/dependency doctor run: npx expo-doctor + + - name: Verify brand mechanism (chatbotx) + run: BRAND=chatbotx pnpm prebuild:check + + - name: Verify brand mechanism (_template) + run: BRAND=_template pnpm prebuild:check diff --git a/.gitignore b/.gitignore index 641dc92..11480f5 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,13 @@ yarn-error.* # local env files .env -.env*.local +.env.* +!.env.example + +# brand overlays (white-label customer brands live outside this repo — see docs/white-label.md) +brands/* +!brands/chatbotx/ +!brands/_template/ # typescript *.tsbuildinfo diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1d5fd0c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Thanks for considering a contribution to ChatbotX's mobile app. + +## Getting set up + +```bash +pnpm install +cp .env.example .env +pnpm start +``` + +See the [README](README.md) for the full quick start and available scripts. + +## Before opening a PR + +```bash +pnpm typecheck +pnpm lint +pnpm format:check +pnpm test +npx expo-doctor +``` + +CI runs all of these on every push/PR — please run them locally first so review cycles aren't +spent on failures these would have caught. + +## Code style + +- TypeScript, strict mode. Avoid `any`; narrow `unknown` instead. +- Match existing patterns in the file/feature you're touching before introducing a new one. +- Keep PRs focused — unrelated refactors make review harder and should be a separate PR. + +## Commit messages + +Conventional commits: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`, `perf:`, `ci:`. + +## Reporting bugs / requesting features + +Open a GitHub issue with: + +- What you expected vs. what happened +- Steps to reproduce (for bugs) +- Your environment (OS, Expo Go vs. dev build, physical device vs. simulator) + +## Security issues + +Please do not open a public issue for a security vulnerability. See the repository's security +policy (or contact the maintainers directly) instead. + +## Scope note + +Contributions to the core app (chat, contacts, auth, etc.) are welcome. White-label/brand-specific +work (see [docs/white-label.md](docs/white-label.md)) is maintained by the ChatbotX team for +customer builds and isn't something this repo's contribution flow covers. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6b42612 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 ChatbotX + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 5192119..2cd8134 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,8 @@ pnpm start ``` Then follow the Expo CLI prompts to open the app in a development build, Android emulator, iOS -simulator, or Expo Go. +simulator, or Expo Go. `.env`'s `BRAND=chatbotx` and `APP_ENV=development` defaults are enough to +run the app with zero EAS setup — see [Deploying](#deploying) once you need a real build. ## Development Commands @@ -48,8 +49,19 @@ pnpm test # jest pnpm format # prettier --write . pnpm format:check # prettier --check . pnpm generate:api # regenerate the typed API client from a running backend instance +pnpm brand:new # scaffold a new brand from brands/_template ``` +## Deploying + +TEST builds are EAS internal distribution; production builds go through EAS Build/Submit to the +App Store and Play Store. See [docs/deploy.md](docs/deploy.md) for the full flow. + +## White-label + +This app can be built for a different brand (app name, icons, colors, bundle id, EAS project) from +the same codebase — see [docs/white-label.md](docs/white-label.md). + ## Docs - [Project structure](docs/project-structure.md) @@ -57,3 +69,5 @@ pnpm generate:api # regenerate the typed API client from a running backend i - [Realtime event types](docs/realtime-events.md) - [Android push notifications](docs/push-notifications.md) - [EAS Update](docs/eas-updates.md) +- [Deploying (TEST and production)](docs/deploy.md) +- [White-label](docs/white-label.md) diff --git a/app.config.test.ts b/app.config.test.ts new file mode 100644 index 0000000..3516d4c --- /dev/null +++ b/app.config.test.ts @@ -0,0 +1,132 @@ +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { loadBrand, readAppEnv, validateBrand } from './app.config'; + +const VALID_BRAND = { + id: 'acme', + displayName: 'Acme', + slug: 'acme-app', + scheme: 'acmeapp', + ios: { bundleIdentifier: 'com.acme.app' }, + android: { package: 'com.acme.app', adaptiveIconBackgroundColor: '#ffffff' }, + colors: { brand: '#3c6df0', splashBackground: '#ffffff' }, + eas: { projectId: 'abc-123' }, +}; + +describe('validateBrand', () => { + test('returns a normalized BrandConfig for a fully valid brand.json', () => { + const result = validateBrand(VALID_BRAND, 'acme'); + + expect(result).toEqual({ + id: 'acme', + displayName: 'Acme', + slug: 'acme-app', + scheme: 'acmeapp', + ios: { bundleIdentifier: 'com.acme.app' }, + android: { package: 'com.acme.app', adaptiveIconBackgroundColor: '#ffffff' }, + colors: { brand: '#3c6df0', splashBackground: '#ffffff' }, + eas: { projectId: 'abc-123', owner: undefined }, + }); + }); + + test('keeps a non-empty eas.owner', () => { + const result = validateBrand( + { ...VALID_BRAND, eas: { projectId: 'abc-123', owner: 'my-org' } }, + 'acme', + ); + expect(result.eas.owner).toBe('my-org'); + }); + + test('treats an empty eas.owner as absent', () => { + const result = validateBrand( + { ...VALID_BRAND, eas: { projectId: 'abc-123', owner: '' } }, + 'acme', + ); + expect(result.eas.owner).toBeUndefined(); + }); + + test('accepts uppercase hex colors', () => { + const result = validateBrand( + { ...VALID_BRAND, colors: { brand: '#136EF1', splashBackground: '#FFFFFF' } }, + 'acme', + ); + expect(result.colors.brand).toBe('#136EF1'); + }); + + test('allows an empty eas.projectId (no EAS project configured yet)', () => { + const result = validateBrand({ ...VALID_BRAND, eas: { projectId: '' } }, 'acme'); + expect(result.eas.projectId).toBe(''); + }); + + test.each([ + ['id', { ...VALID_BRAND, id: '' }], + ['displayName', { ...VALID_BRAND, displayName: undefined }], + ['slug', { ...VALID_BRAND, slug: 123 }], + ['scheme', { ...VALID_BRAND, scheme: '' }], + ['ios.bundleIdentifier', { ...VALID_BRAND, ios: {} }], + ['android.package', { ...VALID_BRAND, android: { adaptiveIconBackgroundColor: '#ffffff' } }], + [ + 'android.adaptiveIconBackgroundColor', + { ...VALID_BRAND, android: { package: 'com.acme.app' } }, + ], + ['colors.brand', { ...VALID_BRAND, colors: { splashBackground: '#ffffff' } }], + ['colors.brand', { ...VALID_BRAND, colors: { ...VALID_BRAND.colors, brand: '#fff' } }], + [ + 'android.adaptiveIconBackgroundColor', + { ...VALID_BRAND, android: { ...VALID_BRAND.android, adaptiveIconBackgroundColor: 'blue' } }, + ], + ['colors.splashBackground', { ...VALID_BRAND, colors: { brand: '#ffffff' } }], + ['eas.projectId', { ...VALID_BRAND, eas: {} }], + ])('throws a message naming the missing field "%s"', (field, invalidBrand) => { + expect(() => validateBrand(invalidBrand, 'acme')).toThrow( + new RegExp(field.replace('.', '\\.')), + ); + }); + + test('throws for a non-object root', () => { + expect(() => validateBrand(null, 'acme')).toThrow(/brands\/acme\/brand\.json/); + }); +}); + +describe('loadBrand', () => { + let repoRoot: string; + + beforeEach(() => { + repoRoot = mkdtempSync(join(tmpdir(), 'load-brand-test-')); + }); + + afterEach(() => { + rmSync(repoRoot, { recursive: true, force: true }); + }); + + test('reads and validates brands//brand.json', () => { + const brandDir = join(repoRoot, 'brands', 'acme'); + mkdirSync(brandDir, { recursive: true }); + writeFileSync(join(brandDir, 'brand.json'), JSON.stringify(VALID_BRAND)); + + const result = loadBrand('acme', repoRoot); + expect(result.id).toBe('acme'); + }); + + test('throws a clear error when the brand folder does not exist', () => { + expect(() => loadBrand('missing-brand', repoRoot)).toThrow( + /no brands\/missing-brand\/brand\.json found/, + ); + }); +}); + +describe('readAppEnv', () => { + test('defaults to development when unset', () => { + expect(readAppEnv(undefined)).toBe('development'); + }); + + test.each(['development', 'preview', 'production'] as const)('accepts "%s"', (value) => { + expect(readAppEnv(value)).toBe(value); + }); + + test('throws for an invalid value', () => { + expect(() => readAppEnv('staging')).toThrow(/Invalid APP_ENV "staging"/); + }); +}); diff --git a/app.config.ts b/app.config.ts index 3593f1c..97368a7 100644 --- a/app.config.ts +++ b/app.config.ts @@ -1,4 +1,5 @@ -import { existsSync } from 'node:fs'; +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; import type { ExpoConfig } from 'expo/config'; @@ -7,29 +8,174 @@ import type { ExpoConfig } from 'expo/config'; * time and expose runtime-configurable values (like the API base URL) via `expo-constants`. * * Values consumed by the app at runtime must be read through `expo-constants` - * (see src/config/env.ts) — process.env is only available here, in the Expo config context. + * (see src/config/env.ts, src/config/brand.ts) — process.env is only available here, in the + * Expo config context. + * + * Brand-loading/validation logic lives inline here (not in a separate `config/` module) because + * Expo's config loader only Babel-transpiles this one entry file — a `require()` from inside it + * to another sibling `.ts` file fails with "Cannot find module" (no TS-stripping registered for + * transitive requires). See app.config.test.ts, which imports these exports directly under Jest + * (which *does* handle the full `.ts` require graph) to unit-test them. */ + +export interface BrandConfig { + id: string; + displayName: string; + slug: string; + scheme: string; + ios: { bundleIdentifier: string }; + android: { package: string; adaptiveIconBackgroundColor: string }; + colors: { brand: string; splashBackground: string }; + eas: { projectId: string; owner?: string }; +} + +/** `APP_ENV` selects the environment suffix applied to bundle id / display name / update channel + * — lets dev/preview/production builds coexist on one device and route to distinct EAS Update + * channels. See docs/deploy.md. */ +export type AppEnv = 'development' | 'preview' | 'production'; + +export const APP_ENV_CONFIG: Record< + AppEnv, + { idSuffix: string; nameSuffix: string; channel: string } +> = { + development: { idSuffix: '.dev', nameSuffix: ' (Dev)', channel: 'development' }, + preview: { idSuffix: '.preview', nameSuffix: ' (Test)', channel: 'preview' }, + production: { idSuffix: '', nameSuffix: '', channel: 'production' }, +}; + +const APP_ENVS = Object.keys(APP_ENV_CONFIG) as AppEnv[]; + +function isAppEnv(value: string): value is AppEnv { + return (APP_ENVS as string[]).includes(value); +} + +export function readAppEnv(raw: string | undefined): AppEnv { + const value = raw ?? 'development'; + if (isAppEnv(value)) return value; + throw new Error( + `Invalid APP_ENV "${value}" — expected ${APP_ENVS.map((e) => `"${e}"`).join(', ')}.`, + ); +} + +const HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/; + +/** Hand-rolled validation (matching the src/config/env.ts pattern elsewhere in the repo) rather + * than pulling in zod for one call site that only ever runs in the Node config-evaluation + * context, never bundled into the app. */ +export function validateBrand(raw: unknown, brandId: string): BrandConfig { + const fail = (field: string): never => { + throw new Error(`brands/${brandId}/brand.json is missing or has an invalid "${field}" field.`); + }; + + const asRecord = (value: unknown, field: string): Record => + typeof value === 'object' && value !== null ? (value as Record) : fail(field); + + /** Reads `path` (e.g. "ios.bundleIdentifier") off the raw object as a string. Empty strings are + * rejected unless `allowEmpty`; `optional` also accepts an absent key (returned as ''); `hex` + * additionally requires a 6-digit `#rrggbb` color so a bad value fails here, naming the file, + * instead of at module load deep inside src/theme/tokens.ts. */ + const requireString = ( + path: string, + { + allowEmpty = false, + optional = false, + hex = false, + }: { allowEmpty?: boolean; optional?: boolean; hex?: boolean } = {}, + ): string => { + const value = path.split('.').reduce((obj, key) => asRecord(obj, path)[key], raw); + if (value === undefined && optional) return ''; + if (typeof value !== 'string') return fail(path); + if (!allowEmpty && !value) return fail(path); + if (hex && !HEX_COLOR_PATTERN.test(value)) return fail(path); + return value; + }; + + asRecord(raw, '(root)'); + const owner = requireString('eas.owner', { optional: true, allowEmpty: true }); + + return { + id: requireString('id'), + displayName: requireString('displayName'), + slug: requireString('slug'), + scheme: requireString('scheme'), + ios: { bundleIdentifier: requireString('ios.bundleIdentifier') }, + android: { + package: requireString('android.package'), + adaptiveIconBackgroundColor: requireString('android.adaptiveIconBackgroundColor', { + hex: true, + }), + }, + colors: { + brand: requireString('colors.brand', { hex: true }), + splashBackground: requireString('colors.splashBackground', { hex: true }), + }, + // `owner` is optional; an absent or empty value means "use the logged-in EAS account". + eas: { + projectId: requireString('eas.projectId', { allowEmpty: true }), + owner: owner || undefined, + }, + }; +} + +/** Loads and validates `brands//brand.json` relative to the repo root. */ +export function loadBrand(brandId: string, repoRoot: string): BrandConfig { + const brandDir = join(repoRoot, 'brands', brandId); + const brandJsonPath = join(brandDir, 'brand.json'); + + if (!existsSync(brandJsonPath)) { + throw new Error( + `Unknown BRAND "${brandId}": no brands/${brandId}/brand.json found. ` + + `Run "pnpm brand:new ${brandId}" to create it, or set BRAND to an existing brand folder.`, + ); + } + + const raw: unknown = JSON.parse(readFileSync(brandJsonPath, 'utf8')); + return validateBrand(raw, brandId); +} + +const brandId = process.env.BRAND ?? 'chatbotx'; +const brand = loadBrand(brandId, __dirname); +const appEnv = readAppEnv(process.env.APP_ENV); +const envConfig = APP_ENV_CONFIG[appEnv]; +// Uses the BRAND folder name, not `brand.id` — the two commonly diverge for `_template` (folder +// `_template`, placeholder `id: "example"`) and must not be assumed identical. +const assetsDir = `./brands/${brandId}/assets`; + +// Loud stdout log: `BRAND` must be correct wherever eas-cli evaluates this file locally (e.g. to +// resolve `extra.eas.projectId` before a build upload) — a silently-wrong brand would build straight +// into the wrong customer's EAS project. See plan risk notes in docs/deploy.md. Skipped under Jest +// (app.config.ts is exercised directly by app.config.test.ts) since it's pure noise there. +if (!process.env.JEST_WORKER_ID) { + // eslint-disable-next-line no-console -- deliberate build-time diagnostic, not app runtime code + console.log(`[app.config] brand=${brand.id} appEnv=${appEnv}`); +} + +const hasEasProject = brand.eas.projectId.length > 0; + const config: ExpoConfig = { - name: 'ChatbotX', - slug: 'chatbotx-mobile-app', + name: `${brand.displayName}${envConfig.nameSuffix}`, + slug: brand.slug, version: '1.0.0', orientation: 'portrait', - icon: './assets/images/icon.png', - scheme: 'chatbotxmobileapp', + icon: `${assetsDir}/icon.png`, + scheme: brand.scheme, userInterfaceStyle: 'automatic', // New Architecture is mandatory (no opt-out) as of this SDK — no `newArchEnabled` property // exists in the config schema to set. ios: { icon: './assets/expo.icon', - bundleIdentifier: 'com.chatconnectx.mobile', + bundleIdentifier: `${brand.ios.bundleIdentifier}${envConfig.idSuffix}`, + // Only OS-provided TLS/Keychain + random UUIDs — no custom crypto, so export-compliance exempt. + // Skips the App Store Connect "App Encryption Documentation" prompt on every upload. + infoPlist: { ITSAppUsesNonExemptEncryption: false }, }, android: { - package: 'com.chatconnectx.mobile', + package: `${brand.android.package}${envConfig.idSuffix}`, adaptiveIcon: { - backgroundColor: '#E6F4FE', - foregroundImage: './assets/images/android-icon-foreground.png', - backgroundImage: './assets/images/android-icon-background.png', - monochromeImage: './assets/images/android-icon-monochrome.png', + backgroundColor: brand.android.adaptiveIconBackgroundColor, + foregroundImage: `${assetsDir}/android-icon-foreground.png`, + backgroundImage: `${assetsDir}/android-icon-background.png`, + monochromeImage: `${assetsDir}/android-icon-monochrome.png`, }, predictiveBackGestureEnabled: false, // Edge-to-edge display is mandatory (no opt-out) as of this SDK — no `edgeToEdgeEnabled` knob @@ -37,8 +183,8 @@ const config: ExpoConfig = { // Required for Android FCM V1 push delivery — prerequisite: a Firebase project with this // package name registered, its google-services.json downloaded to the repo root (gitignored, // not committed). Conditional on the file actually existing locally: it's a per-developer/CI - // secret (see README for the EAS file-secret setup), and an unconditional reference here fails - // every clean checkout's Android build/prebuild before that secret is provisioned. + // secret (see docs/deploy.md for the EAS file-secret setup), and an unconditional reference here + // fails every clean checkout's Android build/prebuild before that secret is provisioned. googleServicesFile: existsSync('./google-services.json') ? './google-services.json' : undefined, }, plugins: [ @@ -47,8 +193,8 @@ const config: ExpoConfig = { [ 'expo-splash-screen', { - backgroundColor: '#208AEF', - image: './assets/images/splash-icon.png', + backgroundColor: brand.colors.splashBackground, + image: `${assetsDir}/splash-icon.png`, imageWidth: 76, }, ], @@ -82,8 +228,8 @@ const config: ExpoConfig = { { // No dedicated notification icon asset exists yet (Android requires a flat white // silhouette, distinct from the app icon) — falls back to Expo's generated default until - // one is designed. `color` matches the splash-screen brand color. - color: '#208AEF', + // one is designed. `color` tints that icon with the brand color. + color: brand.colors.brand, }, ], 'expo-updates', @@ -97,9 +243,15 @@ const config: ExpoConfig = { // same `version` above can receive the same update (no native code change assumed between // updates to the same version). runtimeVersion: { policy: 'appVersion' }, - updates: { - url: 'https://u.expo.dev/8cfd58a8-15f8-4f64-b16c-abf26166e80f', - }, + // A brand with no EAS project yet (e.g. a fresh open-source fork, or `_template`) omits + // `updates`/`extra.eas` entirely so `expo start`/Expo Go work with zero EAS setup. Run + // `eas init` (writes the resulting projectId into brands//brand.json, not app.json) to + // opt back in — see docs/deploy.md. + ...(hasEasProject + ? { + updates: { url: `https://u.expo.dev/${brand.eas.projectId}` }, + } + : {}), extra: { // Falls back to the backend's default local dev URL. Override via `API_BASE_URL` env var // (e.g. in `.env`, loaded by `expo start` through the standard EXPO_PUBLIC_ / dotenv support, @@ -111,11 +263,17 @@ const config: ExpoConfig = { // Mirrors the expo-localization plugin's supportsRTL above for Expo Go, which can't read the // native Info.plist/strings.xml values the plugin writes at build time. supportsRTL: true, - // Written by `eas init` — required by `getExpoPushTokenAsync` in src/lib/notifications.ts. - eas: { - projectId: '8cfd58a8-15f8-4f64-b16c-abf26166e80f', - }, + brandId: brand.id, + brandScheme: brand.scheme, + brandColor: brand.colors.brand, + ...(hasEasProject + ? { + // Written by `eas init` — required by `getExpoPushTokenAsync` in src/lib/notifications.ts. + eas: { projectId: brand.eas.projectId }, + } + : {}), }, + ...(brand.eas.owner ? { owner: brand.eas.owner } : {}), }; export default config; diff --git a/assets/images/android-icon-background.png b/brands/_template/assets/android-icon-background.png similarity index 100% rename from assets/images/android-icon-background.png rename to brands/_template/assets/android-icon-background.png diff --git a/assets/images/android-icon-foreground.png b/brands/_template/assets/android-icon-foreground.png similarity index 100% rename from assets/images/android-icon-foreground.png rename to brands/_template/assets/android-icon-foreground.png diff --git a/assets/images/android-icon-monochrome.png b/brands/_template/assets/android-icon-monochrome.png similarity index 100% rename from assets/images/android-icon-monochrome.png rename to brands/_template/assets/android-icon-monochrome.png diff --git a/assets/images/favicon.png b/brands/_template/assets/favicon.png similarity index 100% rename from assets/images/favicon.png rename to brands/_template/assets/favicon.png diff --git a/assets/images/icon.png b/brands/_template/assets/icon.png similarity index 100% rename from assets/images/icon.png rename to brands/_template/assets/icon.png diff --git a/assets/images/splash-icon.png b/brands/_template/assets/splash-icon.png similarity index 100% rename from assets/images/splash-icon.png rename to brands/_template/assets/splash-icon.png diff --git a/brands/_template/brand.json b/brands/_template/brand.json new file mode 100644 index 0000000..70e45d8 --- /dev/null +++ b/brands/_template/brand.json @@ -0,0 +1,22 @@ +{ + "//": "Copy this folder to brands// to create a new brand. Fill in every field below, replace the assets in ./assets with your own (same filenames/sizes as brands/chatbotx/assets), then run `eas init` with BRAND= to fill in eas.projectId — see docs/white-label.md.", + "id": "example", + "displayName": "Example App", + "slug": "example-app", + "scheme": "exampleapp", + "ios": { + "bundleIdentifier": "com.example.app" + }, + "android": { + "package": "com.example.app", + "adaptiveIconBackgroundColor": "#ffffff" + }, + "colors": { + "brand": "#3c6df0", + "splashBackground": "#ffffff" + }, + "eas": { + "projectId": "", + "owner": "" + } +} diff --git a/brands/chatbotx/assets/android-icon-background.png b/brands/chatbotx/assets/android-icon-background.png new file mode 100644 index 0000000..fb41a57 Binary files /dev/null and b/brands/chatbotx/assets/android-icon-background.png differ diff --git a/brands/chatbotx/assets/android-icon-foreground.png b/brands/chatbotx/assets/android-icon-foreground.png new file mode 100644 index 0000000..8506036 Binary files /dev/null and b/brands/chatbotx/assets/android-icon-foreground.png differ diff --git a/brands/chatbotx/assets/android-icon-monochrome.png b/brands/chatbotx/assets/android-icon-monochrome.png new file mode 100644 index 0000000..853559e Binary files /dev/null and b/brands/chatbotx/assets/android-icon-monochrome.png differ diff --git a/brands/chatbotx/assets/favicon.png b/brands/chatbotx/assets/favicon.png new file mode 100644 index 0000000..08e79fb Binary files /dev/null and b/brands/chatbotx/assets/favicon.png differ diff --git a/brands/chatbotx/assets/icon.png b/brands/chatbotx/assets/icon.png new file mode 100644 index 0000000..fcb7782 Binary files /dev/null and b/brands/chatbotx/assets/icon.png differ diff --git a/brands/chatbotx/assets/splash-icon.png b/brands/chatbotx/assets/splash-icon.png new file mode 100644 index 0000000..5e9b1eb Binary files /dev/null and b/brands/chatbotx/assets/splash-icon.png differ diff --git a/brands/chatbotx/brand.json b/brands/chatbotx/brand.json new file mode 100644 index 0000000..43306fa --- /dev/null +++ b/brands/chatbotx/brand.json @@ -0,0 +1,21 @@ +{ + "id": "chatbotx", + "displayName": "ChatbotX", + "slug": "chatbotx-mobile-app", + "scheme": "chatbotxmobileapp", + "ios": { + "bundleIdentifier": "com.chatconnectx.mobile" + }, + "android": { + "package": "com.chatconnectx.mobile", + "adaptiveIconBackgroundColor": "#136EF1" + }, + "colors": { + "brand": "#136EF1", + "splashBackground": "#136EF1" + }, + "eas": { + "projectId": "8cfd58a8-15f8-4f64-b16c-abf26166e80f", + "owner": "" + } +} diff --git a/docs/deploy.md b/docs/deploy.md new file mode 100644 index 0000000..3ad5d7f --- /dev/null +++ b/docs/deploy.md @@ -0,0 +1,129 @@ +# Deploying (TEST and production) + +This app builds and ships through [EAS](https://expo.dev/eas) (Expo Application Services) — EAS +Build for native binaries, EAS Update for OTA JS updates, EAS Submit for store submission. GitHub +Actions (`.github/workflows/ci.yml`) only runs lint/typecheck/test/`expo-doctor`; the actual +build/update/submit pipeline lives in [EAS Workflows](https://docs.expo.dev/eas/workflows/) +(`.eas/workflows/*.yml`), which run on Expo's own infrastructure, not GitHub's. + +See [white-label.md](white-label.md) if you're building this app for a different brand than the +default `chatbotx` one tracked in this repo. + +## Concepts + +- **`BRAND`** selects `brands//brand.json` — app id, name, colors, icons, and EAS project. + Defaults to `chatbotx`. See [white-label.md](white-label.md). +- **`APP_ENV`** (`development` | `preview` | `production`) suffixes the bundle id/app name and + picks the EAS Update channel, so dev/test/prod builds can be installed side-by-side on one + device. See the table in the root `app.config.ts`. +- **TEST = EAS internal distribution.** There is no separate "staging" app-store listing — the + `preview` build profile produces an internal-distribution build (installed via a link EAS + generates, not through TestFlight/Play internal testing) so QA can install it without a store + review cycle. + +## Prerequisites + +1. An [Expo account](https://expo.dev/signup) with access to the project's EAS organization. +2. `eas login` (or `EXPO_TOKEN` in CI — already wired into `.eas/workflows/*.yml` implicitly via + EAS's own auth, no GitHub secret needed for jobs that run natively on EAS). +3. An Apple Developer Program membership and a Google Play Console account, for anything that + submits to a store (`pnpm submit:prod` / the `release` EAS Workflow). + +### First-time EAS project setup (a fresh clone/fork) + +A brand's `eas.projectId` starts empty until you run `eas init` for it: + +```bash +BRAND=chatbotx eas init +``` + +This creates (or links) an EAS project and writes the resulting `projectId` into +`brands/chatbotx/brand.json` — **not** into `app.json`, since there is no `app.json` in this repo +(see `app.config.ts`). Until `eas.projectId` is set, `expo start`/Expo Go work fine with zero EAS +setup; `updates` and `extra.eas` are simply omitted from the resolved config. + +### EAS Environment Variables (per brand, per environment) + +`API_BASE_URL`, `WS_URL`, and the Android `google-services.json` file are **not** committed — +they're set as [EAS Environment Variables](https://docs.expo.dev/eas/environment-variables/), +scoped to the brand's EAS project and to `preview`/`production` separately: + +```bash +eas env:create --environment preview --name API_BASE_URL --value https://preview.example.com +eas env:create --environment preview --name WS_URL --value https://preview-realtime.example.com +eas env:create --environment production --name API_BASE_URL --value https://api.example.com +eas env:create --environment production --name WS_URL --value https://realtime.example.com + +# File-type secret — see docs/push-notifications.md for what this file is +eas env:create --environment preview --name GOOGLE_SERVICES_JSON --type file --value ./google-services.json +eas env:create --environment production --name GOOGLE_SERVICES_JSON --type file --value ./google-services.json +``` + +`eas.json`'s `build.preview`/`build.production` profiles reference these via `"environment": +"preview"` / `"environment": "production"` — the build worker pulls the actual values at build +time, so `preview.example.com`-style placeholders never need to touch `eas.json` itself. + +## Building + +```bash +pnpm build:dev # eas build --profile development — dev-client, internal +pnpm build:test # eas build --profile preview — internal distribution, this is "TEST" +pnpm build:prod # eas build --profile production — store-ready binary +``` + +Every build profile's `env.BRAND` defaults to `chatbotx` (`eas.json`'s `build.base`). Override it +for a customer brand: + +```bash +BRAND=acme pnpm build:test +``` + +`BRAND` must be correct **at the machine that evaluates `app.config.ts`**, which for local builds +is your own shell, and for EAS Workflow builds is the job's `env.BRAND` (see +[white-label.md](white-label.md)) — a wrong value here silently builds into the wrong brand's EAS +project. `app.config.ts` logs `[app.config] brand=... appEnv=...` on every evaluation specifically +so this is visible in build logs. + +## OTA updates + +```bash +pnpm update:test # eas update --channel preview --environment preview +pnpm update:prod # eas update --channel production --environment production +``` + +`runtimeVersion` uses the `appVersion` policy (see `app.config.ts`): an update is only offered to +installed builds that share the same `version`. If you add/upgrade a native module (anything that +changes generated `ios`/`android` code), bump `version` in `app.config.ts` and ship a new build — +an OTA update alone won't reach devices running the old native binary, and one published against a +mismatched `version` is silently never installed. Run `npx expo-doctor` (already part of CI) to +catch native/JS drift before it becomes a support ticket. + +## Submitting to the stores + +```bash +pnpm submit:prod # eas submit --profile production (ios + android) +``` + +`eas.json`'s `submit.production` has no per-brand identifiers (Apple ID / ASC app id / team id, +Play service account) checked in — either let `eas submit` prompt interactively the first time (it +offers to save credentials to your EAS project), or set them as environment variables +(`EXPO_APPLE_ID`, etc. — see `eas submit --help` for the full list) before running non-interactively +in CI. + +## Version bumping + +`eas.json`'s `"appVersionSource": "remote"` means EAS tracks the build number remotely — you don't +hand-maintain `ios.buildNumber`/`android.versionCode`. You do still bump the semantic `version` +field in `app.config.ts` yourself whenever the app should be treated as a new release train (see +the runtime-version note above). + +## Automated pipeline (EAS Workflows) + +| File | Trigger | What it does | +| ---------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `.eas/workflows/preview.yml` | push to `main` | Builds `preview` profile, both platforms — this is the TEST distribution QA installs. | +| `.eas/workflows/update.yml` | push to `main`; or manual with a `channel` input | Publishes a JS-only OTA update (defaults to the `preview` channel; pick `production` manually). | +| `.eas/workflows/release.yml` | push of a `v*` tag; or manual with a `brand` input | Builds + submits a `production` binary for both stores. A non-default `brand` pulls that customer's brand overlay from a private repo first — see [white-label.md](white-label.md). | + +CI (`.github/workflows/ci.yml`) triggers on `main` only. The repo's default branch must be `main` +for both CI and these workflows to fire on ordinary pushes. diff --git a/docs/eas-updates.md b/docs/eas-updates.md index d9ea242..10020a0 100644 --- a/docs/eas-updates.md +++ b/docs/eas-updates.md @@ -1,6 +1,16 @@ # EAS Update This app ships with `expo-updates` configured (`app.config.ts`'s `updates`/`runtimeVersion`), so -production/preview builds can receive OTA JS-bundle updates via `eas update` without an app-store -resubmission. `runtimeVersion` uses the `appVersion` policy — a build only receives updates -published against the same `version` in `app.config.ts`. +`preview`/`production` builds can receive OTA JS-bundle updates via `eas update` without an +app-store resubmission. `runtimeVersion` uses the `appVersion` policy — a build only receives +updates published against the same `version` in `app.config.ts`. + +Each `APP_ENV` maps to its own update channel (`development`/`preview`/`production` — see +`app.config.ts`'s `APP_ENV_CONFIG`), so a `preview` (TEST) build never receives a `production` +update and vice versa. See [deploy.md](deploy.md#ota-updates) for the actual publish commands +(`pnpm update:test` / `pnpm update:prod`) and the EAS Workflow that automates the common case +(`.eas/workflows/update.yml`). + +`updates.url`/`extra.eas.projectId` are per-brand (`brands//brand.json`) — a brand with no +EAS project yet has neither, and `expo-updates` is effectively inert until `eas init` is run for +that brand (see [white-label.md](white-label.md)). diff --git a/docs/push-notifications.md b/docs/push-notifications.md index 8dd8cac..6a0c5c5 100644 --- a/docs/push-notifications.md +++ b/docs/push-notifications.md @@ -1,12 +1,27 @@ -# Android push notifications (`google-services.json`) +# Push notifications (`google-services.json`) -Android FCM V1 push delivery requires a Firebase project with this app's package name -(`com.chatconnectx.mobile`) registered, and its `google-services.json` downloaded to the repo -root — the file is gitignored (per-developer/CI secret, never committed). `app.config.ts` only -references it conditionally (`existsSync` check), so a clean checkout without the file still -builds; Android push registration simply won't work until it's provisioned. +Android FCM V1 push delivery requires a Firebase project with this build's package name +registered, and its `google-services.json` downloaded to the repo root — the file is gitignored +(per-developer/CI secret, never committed). `app.config.ts` only references it conditionally +(`existsSync` check), so a clean checkout without the file still builds; Android push registration +simply won't work until it's provisioned. + +The package name is brand- and environment-specific: +`` (e.g. +`com.chatconnectx.mobile.preview` for the default brand's `preview`/TEST builds, +`com.chatconnectx.mobile` for `production` — see `app.config.ts`'s `APP_ENV_CONFIG`). **Each +`APP_ENV` suffix needs its own entry in the Firebase project** — a single `google-services.json` +can contain multiple package names, or you can register each as a separate Android app within the +same Firebase project and merge the resulting config. Skipping this means push silently fails to +register for whichever suffix wasn't added. For EAS builds, upload it as a [file-type secret](https://docs.expo.dev/eas/environment-variables/#file-environment-variables) via `eas env:create` (or the EAS dashboard) referencing the path `./google-services.json`, rather -than committing it. +than committing it — see [deploy.md](deploy.md#eas-environment-variables-per-brand-per-environment). +It's scoped per brand's EAS project, same as `API_BASE_URL`/`WS_URL`; a white-label customer needs +their own Firebase project registered with their own (brand-specific) package name — see +[white-label.md](white-label.md). + +iOS push doesn't need an equivalent file here: Expo push notifications route through APNs using +credentials EAS manages as part of the iOS build credentials, not a bundled config file. diff --git a/docs/white-label.md b/docs/white-label.md new file mode 100644 index 0000000..e9d703a --- /dev/null +++ b/docs/white-label.md @@ -0,0 +1,101 @@ +# White-label: building this app for a different brand + +The app is built once per customer ("brand") from the same codebase. A brand owns its own app +name, bundle id/package, colors, icons, and EAS project — nothing customer-specific is hardcoded +in application code. See [deploy.md](deploy.md) for the general build/update/submit flow; this doc +covers what's specific to standing up a _new_ brand. + +## Who does this + +The ChatbotX team builds and ships white-label apps for customers — customers don't get an EAS +account or build the app themselves. Each customer gets their own EAS project (in ChatbotX's +org), keeping their credentials, push certificates, and store listings isolated from every other +customer and from the open-source `chatbotx` brand. + +## 1. Scaffold the brand + +```bash +pnpm brand:new acme +``` + +This copies `brands/_template/` to `brands/acme/`, sets `id` to `acme` in the new +`brand.json`, and prints next steps. `brands/*` is gitignored except `brands/chatbotx/` and +`brands/_template/` — a new brand folder never gets committed to this (public) repo. + +## 2. Fill in `brands/acme/brand.json` + +```json +{ + "id": "acme", + "displayName": "Acme Support", + "slug": "acme-support", + "scheme": "acmesupport", + "ios": { "bundleIdentifier": "com.acme.support" }, + "android": { "package": "com.acme.support", "adaptiveIconBackgroundColor": "#0b1220" }, + "colors": { "brand": "#ff6a00", "splashBackground": "#0b1220" }, + "eas": { "projectId": "", "owner": "" } +} +``` + +- `scheme` becomes the app's custom URL scheme (`://auth-callback` for social sign-in, + `://conversations/:id` for push-notification deep links) — must be globally unique and + must be added to the backend's better-auth `trustedOrigins` for that customer's environment. +- `colors.brand` is the only color a brand needs to supply; `brandStrong` (pressed/emphasis state) + is derived automatically (see `src/theme/tokens.ts`). +- Leave `eas.projectId` empty for now — step 4 fills it in. + +## 3. Replace the assets + +Replace every file in `brands/acme/assets/` with the customer's own art, keeping the same +filenames: `icon.png`, `splash-icon.png`, `android-icon-foreground.png`, +`android-icon-background.png`, `android-icon-monochrome.png`, `favicon.png`. Match the source +files in `brands/chatbotx/assets/` for dimensions/format. + +## 4. Create the EAS project + +```bash +BRAND=acme eas init +``` + +This creates a new EAS project scoped to this brand and writes the resulting `projectId` into +`brands/acme/brand.json` (not into an `app.json` — this repo has none, see `app.config.ts`). + +## 5. Set environment variables and secrets + +Same as the default brand, scoped to `acme`'s EAS project — see +[deploy.md](deploy.md#eas-environment-variables-per-brand-per-environment). This customer's +`API_BASE_URL`/`WS_URL` (if the backend is multi-tenant, these may be identical to another +customer's; if not, they're per-customer here) and Android `google-services.json` (from a Firebase +project registered with `com.acme.support[.dev|.preview]` — see +[push-notifications.md](push-notifications.md)) all live here, never in this repo. + +## 6. Build and submit + +```bash +BRAND=acme pnpm build:test # internal TEST build for the customer/QA to try +BRAND=acme pnpm build:prod # store-ready build +BRAND=acme pnpm submit:prod # submit to that customer's App Store Connect / Play Console +``` + +Or trigger the `release` EAS Workflow manually with the `brand` input set to `acme` (see +[deploy.md](deploy.md#automated-pipeline-eas-workflows)) — this is the path used for a tagged +release when the brand isn't the default `chatbotx`. + +## Where customer brand folders actually live + +`brands/*` (other than `chatbotx` and `_template`) is gitignored in this repo on purpose — this +repo is open-source, and a customer's bundle id, EAS project id, and brand assets are not meant to +be public. The team keeps every customer's `brands//` folder in a separate private repository +(`chatbotx-mobile-brands`). The `release` EAS Workflow clones that private repo (using a +`BRANDS_REPO_TOKEN` EAS secret) into `brands//` at build time whenever `brand != chatbotx` — +see `.eas/workflows/release.yml`. Local development against a customer brand works the same way: +clone or copy that brand's folder from the private repo into `brands//` yourself before +running any `BRAND=` command. + +## Runtime (non-build-time) branding — not implemented here + +Everything above is _build-time_: baked into the native binary (icon, splash, bundle id, scheme, +EAS project). A further layer — colors/logo/display name fetched from the backend's tenant +settings at app boot and cached locally, falling back to `brand.json` — is a deliberate follow-up, +not part of this app. `brand.json` and `src/config/brand.ts` are structured so that layer can read +the same shape later without a rework. diff --git a/eas.json b/eas.json index c9b1494..22c3c02 100644 --- a/eas.json +++ b/eas.json @@ -1,36 +1,71 @@ { "cli": { - "version": ">= 13.0.0", + "version": ">= 22.6.0", "appVersionSource": "remote" }, "build": { + "base": { + "env": { + "BRAND": "chatbotx" + } + }, "development": { + "extends": "base", "developmentClient": true, "distribution": "internal", "channel": "development", + "environment": "development", "env": { - "API_BASE_URL": "http://localhost:3123", - "WS_URL": "http://localhost:1999" + "APP_ENV": "development" } }, "preview": { + "extends": "base", "distribution": "internal", "channel": "preview", + "environment": "preview", "env": { - "API_BASE_URL": "https://preview.example.com", - "WS_URL": "https://preview-realtime.example.com" + "APP_ENV": "preview" + }, + "android": { + "buildType": "apk" } }, + "preview-testflight": { + "extends": "preview", + "distribution": "store", + "autoIncrement": true + }, "production": { + "extends": "base", "autoIncrement": true, "channel": "production", + "environment": "production", "env": { - "API_BASE_URL": "https://api.example.com", - "WS_URL": "https://realtime.example.com" + "APP_ENV": "production" } } }, "submit": { - "production": {} + "base": { + "ios": { + "ascApiKeyPath": "./AuthKey_238L44SV57.p8", + "ascApiKeyId": "238L44SV57", + "ascApiKeyIssuerId": "a888294a-adc3-4201-a022-67fbbc4a597d", + "appleTeamId": "5H3UF98Q3H" + } + }, + "preview-testflight": { + "extends": "base", + "ios": { + "ascAppId": "6806470556" + } + }, + "production": { + "extends": "base", + "android": { + "track": "internal" + } + } } } diff --git a/jest.setup.ts b/jest.setup.ts index fe72a1e..d655fa5 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -2,9 +2,10 @@ jest.mock('@react-native-async-storage/async-storage', () => require('@react-native-async-storage/async-storage/jest/async-storage-mock'), ); -// src/config/env.ts reads Expo config at MODULE LOAD and throws when `extra` is absent, so any -// test importing a module that transitively pulls in `env` (e.g. api/client.ts) fails to load -// without this. app.config.ts is not evaluated under Jest, so supply the `extra` block here. +// src/config/env.ts and src/config/brand.ts read Expo config at MODULE LOAD and throw when +// `extra` is absent, so any test importing a module that transitively pulls in either (e.g. +// api/client.ts, theme/tokens.ts) fails to load without this. app.config.ts is not evaluated +// under Jest, so supply the `extra` block here. jest.mock('expo-constants', () => ({ __esModule: true, default: { @@ -12,6 +13,9 @@ jest.mock('expo-constants', () => ({ extra: { apiBaseUrl: 'https://test.invalid', wsUrl: 'wss://test.invalid', + brandId: 'chatbotx', + brandScheme: 'chatbotxmobileapp', + brandColor: '#3c6df0', }, }, }, @@ -79,3 +83,21 @@ jest.mock('expo-document-picker', () => ({ __esModule: true, getDocumentAsync: jest.fn(), })); + +// react-native-gesture-handler's ReanimatedSwipeable (used by SwipeableRow) composes internal +// Tap/Pan gestures whose callbacks are worklet-ized by Reanimated's babel plugin inconsistently +// under Jest's transform — some callbacks read as worklets, some don't — which trips RNGH's own +// `checkGestureCallbacksForWorklets` dev-mode check (react-native-gesture-handler/src/handlers/ +// gestures/GestureDetector/utils.ts). It's a false positive against RNGH's own compiled +// ReanimatedSwipeable.js, not anything in our code, and the gestures work correctly at runtime. +// Filter only this exact message so real console.error calls still fail tests as expected. +const RNGH_WORKLET_MIXED_CALLBACKS_MESSAGE = + "Some of the callbacks in the gesture are worklets and some are not. Either make sure that all calbacks are marked as 'worklet' if you wish to run them on the UI thread or use '.runOnJS(true)' modifier on the gesture explicitly to run all callbacks on the JS thread."; + +const originalConsoleError = console.error.bind(console); +jest.spyOn(console, 'error').mockImplementation((...args: unknown[]) => { + if (typeof args[0] === 'string' && args[0].includes(RNGH_WORKLET_MIXED_CALLBACKS_MESSAGE)) { + return; + } + originalConsoleError(...args); +}); diff --git a/package.json b/package.json index cd2e309..f880b50 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "chatbotx-mobile-app", "main": "expo-router/entry", "version": "1.0.0", + "license": "MIT", "packageManager": "pnpm@11.15.1", "dependencies": { "@expo-google-fonts/plus-jakarta-sans": "^0.4.2", @@ -11,15 +12,15 @@ "@shopify/flash-list": "2.0.2", "@tanstack/react-query": "^5.101.4", "dayjs": "^1.11.23", - "expo": "~57.0.17", + "expo": "~57.0.18", "expo-camera": "~57.0.4", - "expo-constants": "~57.0.15", + "expo-constants": "~57.0.16", "expo-crypto": "~57.0.2", "expo-dev-client": "~57.0.16", "expo-device": "~57.0.1", "expo-document-picker": "~57.0.1", "expo-file-system": "~57.0.6", - "expo-font": "~57.0.1", + "expo-font": "~57.0.2", "expo-haptics": "~57.0.2", "expo-image": "~57.0.3", "expo-image-picker": "~57.0.14", @@ -31,7 +32,7 @@ "expo-splash-screen": "~57.0.8", "expo-status-bar": "~57.0.1", "expo-system-ui": "~57.0.3", - "expo-updates": "~57.0.18", + "expo-updates": "~57.0.19", "expo-web-browser": "~57.0.2", "i18next": "^26.3.6", "openapi-fetch": "^0.17.0", @@ -70,7 +71,16 @@ "format:check": "prettier --check .", "generate:api": "tsx scripts/generate-api-client.ts", "test": "jest", - "test:watch": "jest --watch" + "test:watch": "jest --watch", + "brand:new": "tsx scripts/create-brand.ts", + "prebuild:check": "expo prebuild --clean --no-install", + "build:dev": "eas build --profile development", + "build:test": "eas build --profile preview", + "build:testflight": "eas build --profile preview-testflight -p ios --auto-submit", + "build:prod": "eas build --profile production", + "update:test": "eas update --channel preview --environment preview", + "update:prod": "eas update --channel production --environment production", + "submit:prod": "eas submit --profile production" }, "private": true } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a89ff7..19c25c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 0.4.2 '@expo/vector-icons': specifier: ^15.1.1 - version: 15.1.1(expo-font@57.0.1)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + version: 15.1.1(expo-font@57.0.2)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) '@gorhom/bottom-sheet': specifier: ^5.2.14 version: 5.2.14(c57327f6cff0368afd765304bb73382e) @@ -30,71 +30,71 @@ importers: specifier: ^1.11.23 version: 1.11.23 expo: - specifier: ~57.0.17 - version: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + specifier: ~57.0.18 + version: 57.0.18(4c67990895f3488afb1e1e80811ccb84) expo-camera: specifier: ~57.0.4 - version: 57.0.4(@types/emscripten@1.41.5)(expo@57.0.17)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + version: 57.0.4(@types/emscripten@1.41.5)(expo@57.0.18)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) expo-constants: - specifier: ~57.0.15 - version: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + specifier: ~57.0.16 + version: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) expo-crypto: specifier: ~57.0.2 - version: 57.0.2(expo@57.0.17) + version: 57.0.2(expo@57.0.18) expo-dev-client: specifier: ~57.0.16 - version: 57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + version: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) expo-device: specifier: ~57.0.1 - version: 57.0.1(expo@57.0.17) + version: 57.0.1(expo@57.0.18) expo-document-picker: specifier: ~57.0.1 - version: 57.0.1(expo@57.0.17) + version: 57.0.1(expo@57.0.18) expo-file-system: specifier: ~57.0.6 - version: 57.0.6(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + version: 57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) expo-font: - specifier: ~57.0.1 - version: 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + specifier: ~57.0.2 + version: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) expo-haptics: specifier: ~57.0.2 - version: 57.0.2(expo@57.0.17) + version: 57.0.2(expo@57.0.18) expo-image: specifier: ~57.0.3 - version: 57.0.3(expo@57.0.17)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + version: 57.0.3(expo@57.0.18)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) expo-image-picker: specifier: ~57.0.14 - version: 57.0.14(expo@57.0.17) + version: 57.0.14(expo@57.0.18) expo-linking: specifier: ~57.0.8 - version: 57.0.8(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) + version: 57.0.8(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) expo-localization: specifier: ^57.0.1 - version: 57.0.1(expo@57.0.17)(react@19.2.3) + version: 57.0.1(expo@57.0.18)(react@19.2.3) expo-notifications: specifier: ~57.0.15 - version: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + version: 57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) expo-router: specifier: ~57.0.17 - version: 57.0.17(d6f39c1ccc936eb2d412636bfc344e3d) + version: 57.0.17(71af9823cfd45ac2f686cfca64abe2a5) expo-secure-store: specifier: ^57.0.2 - version: 57.0.2(expo@57.0.17) + version: 57.0.2(expo@57.0.18) expo-splash-screen: specifier: ~57.0.8 - version: 57.0.8(expo@57.0.17)(supports-color@10.2.2)(typescript@6.0.3) + version: 57.0.8(expo@57.0.18)(supports-color@10.2.2)(typescript@6.0.3) expo-status-bar: specifier: ~57.0.1 - version: 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + version: 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) expo-system-ui: specifier: ~57.0.3 - version: 57.0.3(expo@57.0.17)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + version: 57.0.3(expo@57.0.18)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) expo-updates: - specifier: ~57.0.18 - version: 57.0.18(expo-dev-client@57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)))(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) + specifier: ~57.0.19 + version: 57.0.19(expo-dev-client@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) expo-web-browser: specifier: ~57.0.2 - version: 57.0.2(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + version: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) i18next: specifier: ^26.3.6 version: 26.3.6(typescript@6.0.3) @@ -134,7 +134,7 @@ importers: devDependencies: '@testing-library/react-native': specifier: ^14.0.1 - version: 14.0.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(test-renderer@1.2.0(@types/react@19.2.18)(react@19.2.3)) + version: 14.0.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(test-renderer@1.2.0(@types/react@19.2.18)(react@19.2.3)) '@types/jest': specifier: ^29.5.14 version: 29.5.14 @@ -152,10 +152,10 @@ importers: version: 57.0.2(eslint@9.39.5(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + version: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) jest-expo: specifier: ^57.0.5 - version: 57.0.5(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(expo@57.0.17)(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) + version: 57.0.5(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(expo@57.0.18)(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) openapi-typescript: specifier: ^7.13.0 version: 7.13.0(typescript@6.0.3) @@ -628,6 +628,10 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@egjs/hammerjs@2.0.17': resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} engines: {node: '>=0.8.0'} @@ -841,8 +845,8 @@ packages: '@expo-google-fonts/plus-jakarta-sans@0.4.2': resolution: {integrity: sha512-6LYVmVGwjQvH+uzzWlVc9+oMj4lkNQ41aymVDjO+x8aFk8kCye20wOyLomYMZaMezA++Uf1mZRCw3W3Fy/hxEA==} - '@expo/cli@57.0.19': - resolution: {integrity: sha512-HcvVmm0FNL1P3Lf23z1L/sLZtdcWfKW8P5L/doQbICWVG/PL7uI5+G2Ttxnj9QGNmpYgJ89E7+LJefS5jJMUlQ==} + '@expo/cli@57.0.20': + resolution: {integrity: sha512-ZjWz7SA5TBTyKq4+aFRUPgMFxmqHtKkDMv6d85J2UAAjdRhkNRf+B80t+rr5IFo2ywuTvyrPRBth4ei4w08olA==} hasBin: true peerDependencies: expo: '*' @@ -887,15 +891,15 @@ packages: react: '*' react-native: '*' - '@expo/env@2.4.2': - resolution: {integrity: sha512-28pqaEqwnmLduZ00Pq9HkSzE5wbj1MTwp5/n8nm8rD8MCjR9eUnVOwmNksPI3Be2ReAPO/DbPn1puy0mvoocsQ==} + '@expo/env@2.4.3': + resolution: {integrity: sha512-M1NXeZCA1mkMkYOyIe7PlyRX0/jqFtMoJgyblnlq/vpCRfmueFT7RnGSQG8uEFDF5WHOFGijAQ3fogPh3/n5Ng==} engines: {node: '>=20.12.0'} '@expo/expo-modules-macros-plugin@0.6.1': resolution: {integrity: sha512-cpsLZE4rqkc1Y3eZTkxB98jrqY1YXgetmtxFt8q89jBRmk3quRuk1BZo+VcnCSObZardjg99r1k5xijEMONFGA==} - '@expo/fingerprint@0.20.10': - resolution: {integrity: sha512-Ox/smKlpPpyTUwZAXS927xuJ8qICwNxHOtZElv0anp6xJ80FzwkfvCdC/NjCxlALS2Hp3IsmwyKd975gYgW12Q==} + '@expo/fingerprint@0.20.11': + resolution: {integrity: sha512-GC43EcjQwzpzNZISqmhvjKdi+6FTfxnC9ZxOeg6osCkYXJz94j107l0QpPLipg62khD5HAA5G5cUhevffbRC4w==} hasBin: true '@expo/image-utils@0.11.5': @@ -918,8 +922,8 @@ packages: react: '*' react-native: '*' - '@expo/metro-config@57.0.11': - resolution: {integrity: sha512-aIKcCAQALafeIf+HOoHgjj7hOb771VQRFZARDjm+GJRT74Lb3bYHjkATtS4Wv2zqVx/aFYkNqYNqPF/Py3kSlw==} + '@expo/metro-config@57.0.12': + resolution: {integrity: sha512-S62Lrq35HZqBFD55423pmWb8PjaiR/W02zQC1uECBmw1vTN8WZaFz4TJ0i21EeJzwfebMb9MLxL8JZ102Z6VbA==} peerDependencies: expo: '*' peerDependenciesMeta: @@ -1187,6 +1191,9 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@napi-rs/wasm-runtime@1.2.3': resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} @@ -1569,6 +1576,18 @@ packages: resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==} engines: {node: '>= 10'} + '@tsconfig/node10@1.0.13': + resolution: {integrity: sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -2283,6 +2302,9 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-fetch@3.2.0: resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} @@ -2410,6 +2432,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} + dnssd-advertise@1.1.6: resolution: {integrity: sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==} @@ -2694,8 +2720,8 @@ packages: react-native-web: optional: true - expo-constants@57.0.15: - resolution: {integrity: sha512-rLME1H/K+/uFMR/jEpe/p1nribvCEZZmQegzqxu/R1HTyvYweq4E+B38zB0baie+SEwmeIPLaM4KLVMnejhm5A==} + expo-constants@57.0.16: + resolution: {integrity: sha512-HG3yJjGZo2BPTo2F1sBoxdJZRwX7d9C554EhKn8m12K62pxGolCsvPSoh/lQf95OEP9vO34wwXB2C3QFs0KG0g==} peerDependencies: expo: '*' react-native: '*' @@ -2746,8 +2772,8 @@ packages: expo: '*' react-native: '*' - expo-font@57.0.1: - resolution: {integrity: sha512-QyS9L1Kh9sKJg4gfU6rdbpxpmH+DyzBX8z6jVvXMUDoqLr1GqmkO/Wu379KCXjL///kWbhpNlbi7AgBuj4VdIQ==} + expo-font@57.0.2: + resolution: {integrity: sha512-eWR0CAdysgVqg8VewJ8b5wKh1pa6C8YShIEU3SP0+hlSqOk4djUwuJjn3P04KHVzL3hws9FrUuPxCNmd4TGung==} peerDependencies: expo: '*' react: '*' @@ -2917,8 +2943,8 @@ packages: peerDependencies: expo: '*' - expo-updates@57.0.18: - resolution: {integrity: sha512-guTp5U6RbMOivi3GWXsflZA6M/4oTZKj1/M69sEzVW9MII/FQt+lPgbbEHwcIGrpXBr4RuJIYVrh492kkptJvQ==} + expo-updates@57.0.19: + resolution: {integrity: sha512-xX4KIUa8H2xKmiVDe/uEehD96MV6nyyF/OCrE+PBYfOEp6BbS8bYkHZfNFcoDCKMRuT6pg9JrCi8OmnoWlM/2A==} hasBin: true peerDependencies: expo: '*' @@ -2935,8 +2961,8 @@ packages: expo: '*' react-native: '*' - expo@57.0.17: - resolution: {integrity: sha512-RG9BItgEObzSafkJKHPUh5iCnaPCFXJTDwfEJe3t7uhmqipVhcsf6gAJEtME0xaGaMp4Z3C+HLbPW9DMea8G0w==} + expo@57.0.18: + resolution: {integrity: sha512-6nax9hJPhf9dWrstliXUABTJXDNIJrfJKcCtjSxuYVs2Yf127GIhKf3wsEYSFUl+LFdRbPPTNaweJePH159wZA==} hasBin: true peerDependencies: '@expo/dom-webview': '*' @@ -3841,6 +3867,9 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -4923,6 +4952,20 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -5075,6 +5118,9 @@ packages: 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). hasBin: true + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} @@ -5244,6 +5290,10 @@ packages: resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -5833,6 +5883,11 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + optional: true + '@egjs/hammerjs@2.0.17': dependencies: '@types/hammerjs': 2.0.46 @@ -5981,26 +6036,26 @@ snapshots: '@expo-google-fonts/plus-jakarta-sans@0.4.2': {} - '@expo/cli@57.0.19(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(expo-constants@57.0.15)(expo-font@57.0.1)(expo-router@57.0.17)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3)': + '@expo/cli@57.0.20(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16)(expo-font@57.0.2)(expo-router@57.0.17)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@expo/code-signing-certificates': 0.0.6 '@expo/config': 57.0.9(supports-color@10.2.2)(typescript@6.0.3) '@expo/config-plugins': 57.0.9(supports-color@10.2.2)(typescript@6.0.3) '@expo/devcert': 1.2.1(supports-color@10.2.2) - '@expo/env': 2.4.2(supports-color@10.2.2) + '@expo/env': 2.4.3(supports-color@10.2.2) '@expo/image-utils': 0.11.5(supports-color@10.2.2)(typescript@6.0.3) '@expo/inline-modules': 0.1.7(supports-color@10.2.2)(typescript@6.0.3) '@expo/json-file': 11.0.1 - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) '@expo/metro': 56.0.2(supports-color@10.2.2) - '@expo/metro-config': 57.0.11(expo@57.0.17)(supports-color@10.2.2)(typescript@6.0.3) + '@expo/metro-config': 57.0.12(expo@57.0.18)(supports-color@10.2.2)(typescript@6.0.3) '@expo/metro-file-map': 57.0.2(supports-color@10.2.2) '@expo/osascript': 2.7.1 '@expo/package-manager': 1.13.1 '@expo/plist': 0.8.1 '@expo/prebuild-config': 57.0.15(supports-color@10.2.2)(typescript@6.0.3) '@expo/require-utils': 57.0.5(supports-color@10.2.2)(typescript@6.0.3) - '@expo/router-server': 57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.15)(expo-font@57.0.1)(expo-router@57.0.17)(expo-server@57.0.3)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(supports-color@10.2.2) + '@expo/router-server': 57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16)(expo-font@57.0.2)(expo-router@57.0.17)(expo-server@57.0.3)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(supports-color@10.2.2) '@expo/schema-utils': 57.0.2 '@expo/spawn-async': 1.8.0 '@expo/ws-tunnel': 2.0.0(ws@8.21.3) @@ -6017,7 +6072,7 @@ snapshots: connect: 3.7.0(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2) dnssd-advertise: 1.1.6 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) expo-server: 57.0.3 fetch-nodeshim: 0.4.10 getenv: 2.0.0 @@ -6044,7 +6099,7 @@ snapshots: ws: 8.21.3 zod: 3.25.76 optionalDependencies: - expo-router: 57.0.17(d6f39c1ccc936eb2d412636bfc344e3d) + expo-router: 57.0.17(71af9823cfd45ac2f686cfca64abe2a5) react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) transitivePeerDependencies: - '@expo/dom-webview' @@ -6114,13 +6169,13 @@ snapshots: react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - '@expo/dom-webview@57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + '@expo/dom-webview@57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - '@expo/env@2.4.2(supports-color@10.2.2)': + '@expo/env@2.4.3(supports-color@10.2.2)': dependencies: chalk: 4.1.2 debug: 4.4.3(supports-color@10.2.2) @@ -6130,9 +6185,9 @@ snapshots: '@expo/expo-modules-macros-plugin@0.6.1': {} - '@expo/fingerprint@0.20.10(supports-color@10.2.2)': + '@expo/fingerprint@0.20.11(supports-color@10.2.2)': dependencies: - '@expo/env': 2.4.2(supports-color@10.2.2) + '@expo/env': 2.4.3(supports-color@10.2.2) '@expo/spawn-async': 1.8.0 arg: 5.0.2 chalk: 4.1.2 @@ -6179,22 +6234,22 @@ snapshots: - supports-color - typescript - '@expo/log-box@57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + '@expo/log-box@57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': dependencies: - '@expo/dom-webview': 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/dom-webview': 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) anser: 1.4.10 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) stacktrace-parser: 0.1.11 - '@expo/metro-config@57.0.11(expo@57.0.17)(supports-color@10.2.2)(typescript@6.0.3)': + '@expo/metro-config@57.0.12(expo@57.0.18)(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7(supports-color@10.2.2) '@babel/generator': 7.29.8 '@expo/config': 57.0.9(supports-color@10.2.2)(typescript@6.0.3) - '@expo/env': 2.4.2(supports-color@10.2.2) + '@expo/env': 2.4.3(supports-color@10.2.2) '@expo/json-file': 11.0.1 '@expo/metro': 56.0.2(supports-color@10.2.2) '@expo/require-utils': 57.0.5(supports-color@10.2.2)(typescript@6.0.3) @@ -6214,7 +6269,7 @@ snapshots: postcss: 8.5.26 resolve-from: 5.0.0 optionalDependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) transitivePeerDependencies: - bufferutil - supports-color @@ -6232,11 +6287,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/metro-runtime@57.0.14(@expo/log-box@57.0.4)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + '@expo/metro-runtime@57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': dependencies: - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) anser: 1.4.10 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) pretty-format: 29.7.0 react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) @@ -6311,17 +6366,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.15)(expo-font@57.0.1)(expo-router@57.0.17)(expo-server@57.0.3)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(supports-color@10.2.2)': + '@expo/router-server@57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16)(expo-font@57.0.2)(expo-router@57.0.17)(expo-server@57.0.3)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(supports-color@10.2.2)': dependencies: debug: 4.4.3(supports-color@10.2.2) - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-constants: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) - expo-font: 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) expo-server: 57.0.3 react: 19.2.3 optionalDependencies: - '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) - expo-router: 57.0.17(d6f39c1ccc936eb2d412636bfc344e3d) + '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo-router: 57.0.17(71af9823cfd45ac2f686cfca64abe2a5) react-dom: 19.2.3(react@19.2.3) transitivePeerDependencies: - supports-color @@ -6336,9 +6391,9 @@ snapshots: '@expo/sudo-prompt@9.3.2': {} - '@expo/ui@57.0.14(a28db61b81538200eb1a9563fb519989)': + '@expo/ui@57.0.14(7c721135c4e6c4c85c69925e87446f69)': dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) sf-symbols-typescript: 2.2.0 @@ -6351,9 +6406,9 @@ snapshots: - '@types/react' - '@types/react-dom' - '@expo/vector-icons@15.1.1(expo-font@57.0.1)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': + '@expo/vector-icons@15.1.1(expo-font@57.0.2)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)': dependencies: - expo-font: 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) @@ -6421,7 +6476,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(supports-color@10.2.2)': + '@jest/core@29.7.0(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0(supports-color@10.2.2) @@ -6435,7 +6490,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + jest-config: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -6610,6 +6665,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + optional: true + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -7021,7 +7082,7 @@ snapshots: '@tanstack/query-core': 5.101.4 react: 19.2.3 - '@testing-library/react-native@14.0.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(test-renderer@1.2.0(@types/react@19.2.18)(react@19.2.3))': + '@testing-library/react-native@14.0.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(test-renderer@1.2.0(@types/react@19.2.18)(react@19.2.3))': dependencies: jest-matcher-utils: 30.4.1 picocolors: 1.1.1 @@ -7031,10 +7092,22 @@ snapshots: redent: 3.0.0 test-renderer: 1.2.0(@types/react@19.2.18)(react@19.2.3) optionalDependencies: - jest: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + jest: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) '@tootallnate/once@2.0.1': {} + '@tsconfig/node10@1.0.13': + optional: true + + '@tsconfig/node12@1.0.11': + optional: true + + '@tsconfig/node14@1.0.3': + optional: true + + '@tsconfig/node16@1.0.4': + optional: true + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 @@ -7552,7 +7625,7 @@ snapshots: '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7(supports-color@10.2.2)) - babel-preset-expo@57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@babel/runtime@7.29.7)(expo@57.0.17)(react-refresh@0.14.2)(supports-color@10.2.2): + babel-preset-expo@57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@babel/runtime@7.29.7)(expo@57.0.18)(react-refresh@0.14.2)(supports-color@10.2.2): dependencies: '@babel/generator': 7.29.8 '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) @@ -7599,7 +7672,7 @@ snapshots: react-refresh: 0.14.2 optionalDependencies: '@babel/runtime': 7.29.7 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) transitivePeerDependencies: - '@babel/core' - supports-color @@ -7832,13 +7905,13 @@ snapshots: dependencies: browserslist: 4.28.8 - create-jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2): + create-jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + jest-config: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -7847,6 +7920,9 @@ snapshots: - supports-color - ts-node + create-require@1.1.1: + optional: true + cross-fetch@3.2.0: dependencies: node-fetch: 2.7.0 @@ -7959,6 +8035,9 @@ snapshots: diff-sequences@29.6.3: {} + diff@4.0.4: + optional: true + dnssd-advertise@1.1.6: {} doctrine@2.1.0: @@ -8377,25 +8456,25 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - expo-application@57.0.2(expo@57.0.17): + expo-application@57.0.2(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) - expo-asset@57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3): + expo-asset@57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3): dependencies: '@expo/image-utils': 0.11.5(supports-color@10.2.2)(typescript@6.0.3) - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-constants: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) transitivePeerDependencies: - supports-color - typescript - expo-camera@57.0.4(@types/emscripten@1.41.5)(expo@57.0.17)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + expo-camera@57.0.4(@types/emscripten@1.41.5)(expo@57.0.18)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): dependencies: barcode-detector: 3.2.2(@types/emscripten@1.41.5) - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) optionalDependencies: @@ -8403,92 +8482,92 @@ snapshots: transitivePeerDependencies: - '@types/emscripten' - expo-constants@57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2): + expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@expo/env': 2.4.2(supports-color@10.2.2) - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + '@expo/env': 2.4.3(supports-color@10.2.2) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) transitivePeerDependencies: - supports-color - expo-crypto@57.0.2(expo@57.0.17): + expo-crypto@57.0.2(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) - expo-dev-client@57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): + expo-dev-client@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-dev-launcher: 57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) - expo-dev-menu: 57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) - expo-dev-menu-interface: 57.0.0(expo@57.0.17) - expo-manifests: 57.0.1(expo@57.0.17) - expo-updates-interface: 57.0.1(expo@57.0.17) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-dev-launcher: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + expo-dev-menu: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + expo-dev-menu-interface: 57.0.0(expo@57.0.18) + expo-manifests: 57.0.1(expo@57.0.18) + expo-updates-interface: 57.0.1(expo@57.0.18) transitivePeerDependencies: - react-native - expo-dev-launcher@57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): + expo-dev-launcher@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): dependencies: '@expo/schema-utils': 57.0.2 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-dev-menu: 57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) - expo-manifests: 57.0.1(expo@57.0.17) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-dev-menu: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + expo-manifests: 57.0.1(expo@57.0.18) react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - expo-dev-menu-interface@57.0.0(expo@57.0.17): + expo-dev-menu-interface@57.0.0(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) - expo-dev-menu@57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): + expo-dev-menu@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-dev-menu-interface: 57.0.0(expo@57.0.17) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-dev-menu-interface: 57.0.0(expo@57.0.18) react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - expo-device@57.0.1(expo@57.0.17): + expo-device@57.0.1(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) ua-parser-js: 0.7.41 - expo-document-picker@57.0.1(expo@57.0.17): + expo-document-picker@57.0.1(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) expo-eas-client@57.0.2: {} - expo-file-system@57.0.6(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): + expo-file-system@57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - expo-font@57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) fontfaceobserver: 2.3.0 react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - expo-glass-effect@57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + expo-glass-effect@57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - expo-haptics@57.0.2(expo@57.0.17): + expo-haptics@57.0.2(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) - expo-image-loader@57.0.1(expo@57.0.17): + expo-image-loader@57.0.1(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) - expo-image-picker@57.0.14(expo@57.0.17): + expo-image-picker@57.0.14(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-image-loader: 57.0.1(expo@57.0.17) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-image-loader: 57.0.1(expo@57.0.18) - expo-image@57.0.3(expo@57.0.17)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + expo-image@57.0.3(expo@57.0.18)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) sf-symbols-typescript: 2.2.0 @@ -8497,14 +8576,14 @@ snapshots: expo-json-utils@57.0.1: {} - expo-keep-awake@57.0.1(expo@57.0.17)(react@19.2.3): + expo-keep-awake@57.0.1(expo@57.0.18)(react@19.2.3): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 - expo-linking@57.0.8(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2): + expo-linking@57.0.8(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2): dependencies: - expo-constants: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) invariant: 2.2.4 react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) @@ -8512,15 +8591,15 @@ snapshots: - expo - supports-color - expo-localization@57.0.1(expo@57.0.17)(react@19.2.3): + expo-localization@57.0.1(expo@57.0.18)(react@19.2.3): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 rtl-detect: 1.1.2 - expo-manifests@57.0.1(expo@57.0.17): + expo-manifests@57.0.1(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) expo-json-utils: 57.0.1 expo-modules-autolinking@57.0.12(supports-color@10.2.2)(typescript@6.0.3): @@ -8547,26 +8626,26 @@ snapshots: dependencies: react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - expo-notifications@57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3): + expo-notifications@57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3): dependencies: '@expo/image-utils': 0.11.5(supports-color@10.2.2)(typescript@6.0.3) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-application: 57.0.2(expo@57.0.17) - expo-constants: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-application: 57.0.2(expo@57.0.18) + expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) transitivePeerDependencies: - supports-color - typescript - expo-router@57.0.17(d6f39c1ccc936eb2d412636bfc344e3d): + expo-router@57.0.17(71af9823cfd45ac2f686cfca64abe2a5): dependencies: - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) - '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) '@expo/schema-utils': 57.0.2 - '@expo/ui': 57.0.14(a28db61b81538200eb1a9563fb519989) + '@expo/ui': 57.0.14(7c721135c4e6c4c85c69925e87446f69) '@radix-ui/react-slot': 1.3.3(@types/react@19.2.18)(react@19.2.3) '@radix-ui/react-tabs': 1.1.21(@types/react@19.2.18)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@react-native-masked-view/masked-view': 0.3.2(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) @@ -8574,12 +8653,12 @@ snapshots: color: 4.2.3 debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-constants: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) - expo-glass-effect: 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) - expo-linking: 57.0.8(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo-glass-effect: 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo-linking: 57.0.8(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2) expo-server: 57.0.3 - expo-symbols: 57.0.2(expo-font@57.0.1)(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo-symbols: 57.0.2(expo-font@57.0.2)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) fast-deep-equal: 3.1.3 invariant: 2.2.4 nanoid: 3.3.18 @@ -8597,7 +8676,7 @@ snapshots: standard-navigation: 0.0.5 vaul: 1.1.2(@types/react@19.2.18)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) optionalDependencies: - '@testing-library/react-native': 14.0.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(test-renderer@1.2.0(@types/react@19.2.18)(react@19.2.3)) + '@testing-library/react-native': 14.0.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(test-renderer@1.2.0(@types/react@19.2.18)(react@19.2.3)) react-dom: 19.2.3(react@19.2.3) react-native-gesture-handler: 2.32.0(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) react-native-reanimated: 4.5.1(react-native-worklets@0.10.1(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) @@ -8610,55 +8689,55 @@ snapshots: - react-native-worklets - supports-color - expo-secure-store@57.0.2(expo@57.0.17): + expo-secure-store@57.0.2(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) expo-server@57.0.3: {} - expo-splash-screen@57.0.8(expo@57.0.17)(supports-color@10.2.2)(typescript@6.0.3): + expo-splash-screen@57.0.8(expo@57.0.18)(supports-color@10.2.2)(typescript@6.0.3): dependencies: '@expo/config-plugins': 57.0.9(supports-color@10.2.2)(typescript@6.0.3) '@expo/image-utils': 0.11.5(supports-color@10.2.2)(typescript@6.0.3) - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) xml2js: 0.6.0 transitivePeerDependencies: - supports-color - typescript - expo-status-bar@57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + expo-status-bar@57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) expo-structured-headers@57.0.0: {} - expo-symbols@57.0.2(expo-font@57.0.1)(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): + expo-symbols@57.0.2(expo-font@57.0.2)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3): dependencies: '@expo-google-fonts/material-symbols': 0.4.44 - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) - expo-font: 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) + expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) react: 19.2.3 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) sf-symbols-typescript: 2.2.0 - expo-system-ui@57.0.3(expo@57.0.17)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2): + expo-system-ui@57.0.3(expo@57.0.18)(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: '@react-native/normalize-colors': 0.86.3 debug: 4.4.3(supports-color@10.2.2) - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) optionalDependencies: react-native-web: 0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) transitivePeerDependencies: - supports-color - expo-updates-interface@57.0.1(expo@57.0.17): + expo-updates-interface@57.0.1(expo@57.0.18): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) - expo-updates@57.0.18(expo-dev-client@57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)))(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2): + expo-updates@57.0.19(expo-dev-client@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2): dependencies: '@expo/code-signing-certificates': 0.0.6 '@expo/plist': 0.8.1 @@ -8666,11 +8745,11 @@ snapshots: arg: 4.1.3 chalk: 4.1.2 debug: 4.4.3(supports-color@10.2.2) - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) expo-eas-client: 57.0.2 - expo-manifests: 57.0.1(expo@57.0.17) + expo-manifests: 57.0.1(expo@57.0.18) expo-structured-headers: 57.0.0 - expo-updates-interface: 57.0.1(expo@57.0.17) + expo-updates-interface: 57.0.1(expo@57.0.18) getenv: 2.0.0 glob: 13.0.6 ignore: 5.3.2 @@ -8679,34 +8758,34 @@ snapshots: react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) resolve-from: 5.0.0 optionalDependencies: - expo-dev-client: 57.0.16(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + expo-dev-client: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) transitivePeerDependencies: - supports-color - expo-web-browser@57.0.2(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): + expo-web-browser@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)): dependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) - expo@57.0.17(4c67990895f3488afb1e1e80811ccb84): + expo@57.0.18(4c67990895f3488afb1e1e80811ccb84): dependencies: '@babel/runtime': 7.29.7 - '@expo/cli': 57.0.19(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(expo-constants@57.0.15)(expo-font@57.0.1)(expo-router@57.0.17)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + '@expo/cli': 57.0.20(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16)(expo-font@57.0.2)(expo-router@57.0.17)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) '@expo/config': 57.0.9(supports-color@10.2.2)(typescript@6.0.3) '@expo/config-plugins': 57.0.9(supports-color@10.2.2)(typescript@6.0.3) '@expo/devtools': 57.0.1(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) - '@expo/fingerprint': 0.20.10(supports-color@10.2.2) + '@expo/fingerprint': 0.20.11(supports-color@10.2.2) '@expo/local-build-cache-provider': 57.0.8(supports-color@10.2.2)(typescript@6.0.3) - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) '@expo/metro': 56.0.2(supports-color@10.2.2) - '@expo/metro-config': 57.0.11(expo@57.0.17)(supports-color@10.2.2)(typescript@6.0.3) + '@expo/metro-config': 57.0.12(expo@57.0.18)(supports-color@10.2.2)(typescript@6.0.3) '@ungap/structured-clone': 1.3.3 - babel-preset-expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@babel/runtime@7.29.7)(expo@57.0.17)(react-refresh@0.14.2)(supports-color@10.2.2) - expo-asset: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) - expo-constants: 57.0.15(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) - expo-file-system: 57.0.6(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) - expo-font: 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) - expo-keep-awake: 57.0.1(expo@57.0.17)(react@19.2.3) + babel-preset-expo: 57.0.9(@babel/core@7.29.7(supports-color@10.2.2))(@babel/runtime@7.29.7)(expo@57.0.18)(react-refresh@0.14.2)(supports-color@10.2.2) + expo-asset: 57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2)(typescript@6.0.3) + expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(supports-color@10.2.2) + expo-file-system: 57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2)) + expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + expo-keep-awake: 57.0.1(expo@57.0.18)(react@19.2.3) expo-modules-autolinking: 57.0.12(supports-color@10.2.2)(typescript@6.0.3) expo-modules-core: 57.0.14(react-native-worklets@0.10.1(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) pretty-format: 29.7.0 @@ -8715,8 +8794,8 @@ snapshots: react-refresh: 0.14.2 whatwg-url-minimum: 0.1.2 optionalDependencies: - '@expo/dom-webview': 57.0.1(expo@57.0.17)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) - '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.17)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/dom-webview': 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) + '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3) react-dom: 19.2.3(react@19.2.3) react-native-web: 0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) transitivePeerDependencies: @@ -9291,16 +9370,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@26.2.0)(supports-color@10.2.2): + jest-cli@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)): dependencies: - '@jest/core': 29.7.0(supports-color@10.2.2) + '@jest/core': 29.7.0(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + create-jest: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + jest-config: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.3 @@ -9310,7 +9389,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@26.2.0)(supports-color@10.2.2): + jest-config@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)): dependencies: '@babel/core': 7.29.7(supports-color@10.2.2) '@jest/test-sequencer': 29.7.0 @@ -9336,6 +9415,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 26.2.0 + ts-node: 10.9.2(@types/node@26.2.0)(typescript@6.0.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -9390,7 +9470,7 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-expo@57.0.5(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(expo@57.0.17)(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2): + jest-expo@57.0.5(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(expo@57.0.18)(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)))(react-native@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2): dependencies: '@jest/create-cache-key-function': 29.7.0 '@jest/globals': 29.7.0(supports-color@10.2.2) @@ -9399,7 +9479,7 @@ snapshots: jest-environment-jsdom: 29.7.0(supports-color@10.2.2) jest-snapshot: 29.7.0(supports-color@10.2.2) jest-watch-select-projects: 2.0.0 - jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)) + jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3))) json5: 2.2.3 lodash: 4.18.1 react-native: 0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(react@19.2.3)(supports-color@10.2.2))(@react-native/metro-config@0.86.3(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2))(@types/react@19.2.18)(react@19.2.3)(supports-color@10.2.2) @@ -9407,7 +9487,7 @@ snapshots: server-only: 0.0.1 stacktrace-js: 2.0.2 optionalDependencies: - expo: 57.0.17(4c67990895f3488afb1e1e80811ccb84) + expo: 57.0.18(4c67990895f3488afb1e1e80811ccb84) transitivePeerDependencies: - '@babel/core' - bufferutil @@ -9599,11 +9679,11 @@ snapshots: chalk: 3.0.0 prompts: 2.4.2 - jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)): + jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3))): dependencies: ansi-escapes: 6.2.1 chalk: 4.1.2 - jest: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + jest: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -9628,12 +9708,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2): + jest@29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)): dependencies: - '@jest/core': 29.7.0(supports-color@10.2.2) + '@jest/core': 29.7.0(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2) + jest-cli: 29.7.0(@types/node@26.2.0)(supports-color@10.2.2)(ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -9824,6 +9904,9 @@ snapshots: dependencies: semver: 7.8.5 + make-error@1.3.6: + optional: true + makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -11074,6 +11157,25 @@ snapshots: dependencies: typescript: 6.0.3 + ts-node@10.9.2(@types/node@26.2.0)(typescript@6.0.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.13 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 26.2.0 + acorn: 8.18.0 + acorn-walk: 8.3.5 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.4 + make-error: 1.3.6 + typescript: 6.0.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -11240,6 +11342,9 @@ snapshots: uuid@7.0.3: {} + v8-compile-cache-lib@3.0.1: + optional: true + v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -11403,6 +11508,9 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yn@3.1.1: + optional: true + yocto-queue@0.1.0: {} zod-validation-error@4.0.2(zod@3.25.76): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 6436997..e6a069a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,28 +1,31 @@ allowBuilds: + dtrace-provider: false esbuild: true unrs-resolver: true minimumReleaseAgeExclude: - - '@expo/cli@57.0.17' - - '@expo/fingerprint@0.20.9' + - '@expo/cli@57.0.17 || 57.0.20' + - '@expo/fingerprint@0.20.9 || 0.20.11' - '@expo/local-build-cache-provider@57.0.7' - - '@expo/metro-config@57.0.9' + - '@expo/metro-config@57.0.9 || 57.0.12' - '@expo/metro-runtime@57.0.12' - '@expo/prebuild-config@57.0.13' - '@expo/router-server@57.0.7' - '@expo/ui@57.0.12' - expo-asset@57.0.13 - - expo-constants@57.0.13 + - expo-constants@57.0.13 || 57.0.16 - expo-file-system@57.0.5 || 57.0.6 - expo-linking@57.0.7 - expo-modules-core@57.0.12 - expo-modules-jsi@57.0.5 - expo-router@57.0.15 - - expo@57.0.15 + - expo@57.0.15 || 57.0.18 - expo-camera@57.0.4 - expo-image-picker@57.0.12 - - expo-updates@57.0.16 + - expo-updates@57.0.16 || 57.0.19 - expo-dev-client@57.0.14 - expo-dev-launcher@57.0.14 - expo-dev-menu@57.0.14 - expo-notifications@57.0.13 - expo-haptics@57.0.2 + - '@expo/env@2.4.3' + - expo-font@57.0.2 diff --git a/scripts/create-brand.ts b/scripts/create-brand.ts new file mode 100644 index 0000000..d6f2753 --- /dev/null +++ b/scripts/create-brand.ts @@ -0,0 +1,49 @@ +import { cpSync, existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; + +/** + * `pnpm brand:new ` — scaffolds `brands//` from `brands/_template/`, so a new white-label + * brand starts from the placeholder brand.json + stock assets instead of an empty folder. See + * docs/white-label.md for the full brand-onboarding flow. + */ +const repoRoot = join(__dirname, '..'); +const brandId = process.argv[2]; + +if (!brandId) { + console.error('Usage: pnpm brand:new '); + process.exit(1); +} + +if (!/^[a-z0-9-]+$/.test(brandId)) { + console.error(`Invalid brand id "${brandId}": use lowercase letters, numbers, and hyphens only.`); + process.exit(1); +} + +const templateDir = join(repoRoot, 'brands', '_template'); +const targetDir = join(repoRoot, 'brands', brandId); + +if (existsSync(targetDir)) { + console.error(`brands/${brandId} already exists.`); + process.exit(1); +} + +try { + cpSync(templateDir, targetDir, { recursive: true }); + + const brandJsonPath = join(targetDir, 'brand.json'); + const { '//': _templateNote, ...brandJson } = JSON.parse( + readFileSync(brandJsonPath, 'utf8'), + ) as Record; + writeFileSync(brandJsonPath, `${JSON.stringify({ ...brandJson, id: brandId }, null, 2)}\n`); +} catch (error) { + // Don't leave a half-scaffolded folder behind — it would trip the "already exists" guard on retry. + rmSync(targetDir, { recursive: true, force: true }); + throw error; +} + +console.log(`Created brands/${brandId} from brands/_template.`); +console.log( + `Next: edit brands/${brandId}/brand.json, replace brands/${brandId}/assets/*, then run`, +); +console.log(` BRAND=${brandId} eas init`); +console.log('to create the EAS project and fill in eas.projectId. See docs/white-label.md.'); diff --git a/src/api/auth-endpoints.ts b/src/api/auth-endpoints.ts index 1030fae..1b4a534 100644 --- a/src/api/auth-endpoints.ts +++ b/src/api/auth-endpoints.ts @@ -1,3 +1,4 @@ +import { brand } from '@/config/brand'; import { env } from '@/config/env'; import { setAuthToken } from './auth-token'; @@ -122,17 +123,17 @@ export async function signOut(token: string): Promise { export type SocialProvider = 'google' | 'facebook'; -/** The app's custom URL scheme (app.config.ts `scheme: 'chatbotxmobileapp'`) that the OAuth - * broker relays back to once the provider flow completes. */ -export const SOCIAL_CALLBACK_URL = 'chatbotxmobileapp://auth-callback'; +/** The app's custom URL scheme (`brands//brand.json` `scheme`, read via + * src/config/brand.ts) that the OAuth broker relays back to once the provider flow completes. */ +export const SOCIAL_CALLBACK_URL = `${brand.brandScheme}://auth-callback`; /** * Starts a social sign-in flow. Shape per better-auth's `/sign-in/social` route: request * `{ provider, callbackURL }`, response `{ redirect: boolean; url: string }`. * * The returned `url` sends the user through the provider, then the backend's fixed OAuth - * "broker" host relays back to `callbackURL`. `chatbotxmobileapp://` must be in the backend's - * better-auth `trustedOrigins`. + * "broker" host relays back to `callbackURL`. The brand's scheme (e.g. `chatbotxmobileapp://`) + * must be in the backend's better-auth `trustedOrigins` for every brand that can sign in. */ export async function startSocialSignIn(provider: SocialProvider): Promise { const response = await fetch(`${AUTH_BASE_URL}/sign-in/social`, { diff --git a/src/api/auth-token.ts b/src/api/auth-token.ts index 631fbe5..48660e7 100644 --- a/src/api/auth-token.ts +++ b/src/api/auth-token.ts @@ -1,5 +1,7 @@ import * as SecureStore from 'expo-secure-store'; +import { brand } from '@/config/brand'; + /** * Auth token storage, backed by expo-secure-store (Keychain on iOS, Keystore-backed * EncryptedSharedPreferences on Android). @@ -9,7 +11,7 @@ import * as SecureStore from 'expo-secure-store'; * `getAuthToken` currently always resolves to whatever was last persisted (or null), with no * refresh logic. */ -const AUTH_TOKEN_KEY = 'chatbotx.authToken'; +const AUTH_TOKEN_KEY = `${brand.brandId}.authToken`; export async function getAuthToken(): Promise { return SecureStore.getItemAsync(AUTH_TOKEN_KEY); diff --git a/src/api/client.test.ts b/src/api/client.test.ts index ffe859d..45c16eb 100644 --- a/src/api/client.test.ts +++ b/src/api/client.test.ts @@ -10,7 +10,13 @@ jest.mock('expo-constants', () => ({ __esModule: true, default: { expoConfig: { - extra: { apiBaseUrl: 'http://localhost:3123', wsUrl: 'ws://localhost:3123' }, + extra: { + apiBaseUrl: 'http://localhost:3123', + wsUrl: 'ws://localhost:3123', + brandId: 'chatbotx', + brandScheme: 'chatbotxmobileapp', + brandColor: '#3c6df0', + }, }, }, })); diff --git a/src/config/brand.test.ts b/src/config/brand.test.ts new file mode 100644 index 0000000..85ce527 --- /dev/null +++ b/src/config/brand.test.ts @@ -0,0 +1,38 @@ +const VALID_EXTRA = { + brandId: 'chatbotx', + brandScheme: 'chatbotxmobileapp', + brandColor: '#3c6df0', +}; + +function loadBrandWith(extra: Record | undefined): () => typeof import('./brand') { + jest.resetModules(); + jest.doMock('expo-constants', () => ({ + __esModule: true, + default: { expoConfig: extra === undefined ? undefined : { extra } }, + })); + // eslint-disable-next-line @typescript-eslint/no-require-imports -- fresh module load per mock + return () => require('./brand') as typeof import('./brand'); +} + +describe('brand', () => { + afterEach(() => { + jest.dontMock('expo-constants'); + }); + + it('exposes the brand fields from Expo config extra', () => { + const { brand } = loadBrandWith(VALID_EXTRA)(); + expect(brand).toEqual(VALID_EXTRA); + }); + + it.each(['brandId', 'brandScheme', 'brandColor'] as const)( + 'throws at load when "%s" is missing', + (field) => { + const { [field]: _omitted, ...rest } = VALID_EXTRA; + expect(loadBrandWith(rest)).toThrow(new RegExp(`extra\\.${field}`)); + }, + ); + + it('throws at load when expoConfig is absent entirely', () => { + expect(loadBrandWith(undefined)).toThrow(/extra\.brandId/); + }); +}); diff --git a/src/config/brand.ts b/src/config/brand.ts new file mode 100644 index 0000000..73d09ca --- /dev/null +++ b/src/config/brand.ts @@ -0,0 +1,39 @@ +import Constants from 'expo-constants'; + +interface BrandExtraConfig { + brandId: string; + brandScheme: string; + brandColor: string; +} + +const REQUIRED_FIELDS: readonly (keyof BrandExtraConfig)[] = [ + 'brandId', + 'brandScheme', + 'brandColor', +]; + +function readExtra(): BrandExtraConfig { + const extra = (Constants.expoConfig?.extra ?? {}) as Partial; + + for (const field of REQUIRED_FIELDS) { + if (!extra[field]) { + throw new Error( + `Missing "extra.${field}" in Expo config. Check app.config.ts and the BRAND env var.`, + ); + } + } + + return { + brandId: extra.brandId!, + brandScheme: extra.brandScheme!, + brandColor: extra.brandColor!, + }; +} + +/** + * Brand identity the app reads at runtime, sourced from `brands//brand.json` via + * app.config.ts `extra`. Only what src/ actually consumes is exposed here — the display name is + * available as `Constants.expoConfig.name`, and the environment/update channel are build-time + * concerns owned by eas.json. See docs/white-label.md for how a new brand is created and built. + */ +export const brand: BrandExtraConfig = readExtra(); diff --git a/src/features/auth/social-buttons.tsx b/src/features/auth/social-buttons.tsx index 157b4f6..332027d 100644 --- a/src/features/auth/social-buttons.tsx +++ b/src/features/auth/social-buttons.tsx @@ -16,7 +16,7 @@ type Provider = 'google' | 'facebook'; /** * Social sign-in buttons. Flow: `startSocialSignIn` gets the provider authorize URL from * better-auth, `WebBrowser.openAuthSessionAsync` opens it and resolves once the broker redirects - * back to our `chatbotxmobileapp://auth-callback` scheme (see auth-endpoints.ts for the + * back to our brand's `://auth-callback` (see auth-endpoints.ts for the * trustedOrigins gap that currently blocks this redirect server-side — this UI is correct but * won't complete end-to-end until that backend change lands). * @@ -29,7 +29,7 @@ type Provider = 'google' | 'facebook'; * `getSession()` call below only works if a token is ALREADY in SecureStore, which it isn't yet at * this point in the flow. So this currently cannot complete sign-in even once trustedOrigins is * fixed, UNLESS the backend's broker relay is changed to also forward a bearer token (e.g. as a - * `token` query param on the `chatbotxmobileapp://auth-callback` redirect, mirroring what + * `token` query param on the `://auth-callback` redirect, mirroring what * `set-auth-token` does for same-origin requests) — or a dedicated mobile token-exchange endpoint * is added. Neither is implemented here; both are backend-shaped decisions outside this repo. */ diff --git a/src/features/settings/api/use-device-token.ts b/src/features/settings/api/use-device-token.ts index 4959203..b784a0a 100644 --- a/src/features/settings/api/use-device-token.ts +++ b/src/features/settings/api/use-device-token.ts @@ -6,6 +6,7 @@ import { Platform } from 'react-native'; import { apiClient } from '@/api/client'; import { ApiError } from '@/api/errors'; +import { brand } from '@/config/brand'; import { getPushTokenAsync } from '@/lib/notifications'; /** @@ -15,7 +16,7 @@ import { getPushTokenAsync } from '@/lib/notifications'; * re-registration after a token rotation) always targets the token the backend actually has on * file, not whatever `getExpoPushTokenAsync` returns *now* if it has since changed. */ -const LAST_REGISTERED_TOKEN_KEY = 'chatbotx.lastRegisteredPushToken'; +const LAST_REGISTERED_TOKEN_KEY = `${brand.brandId}.lastRegisteredPushToken`; function resolvePlatform(): 'ios' | 'android' | null { if (Platform.OS === 'ios') return 'ios'; diff --git a/src/lib/pending-deep-link.ts b/src/lib/pending-deep-link.ts index b5f9ab2..8b2b1ec 100644 --- a/src/lib/pending-deep-link.ts +++ b/src/lib/pending-deep-link.ts @@ -1,7 +1,7 @@ import * as Linking from 'expo-linking'; /** - * Cold-start deep link to a conversation or contact (`chatbotxmobileapp://conversations/:id` or + * Cold-start deep link to a conversation or contact (`://conversations/:id` or * `.../contacts/:id`, e.g. from a push notification once delivery lands) arrives before the auth * bootstrap gate resolves. `(app)/_layout.tsx` redirects an unauthenticated visitor to sign-in, * which drops the original target — expo-router has no built-in "return to this deep link after @@ -19,7 +19,7 @@ let captured = false; /** Deep-link path shapes this app knows how to resolve to a route, in order of priority. Each * pattern is matched against the URL's path with the scheme/host stripped (what `Linking.parse` * gives us) — accepting both a bare `conversations/:id` / `contacts/:id` link (the natural shape - * for a push-notification deep link, e.g. `chatbotxmobileapp://conversations/12345`) and one that + * for a push-notification deep link, e.g. `://conversations/12345`) and one that * already embeds the `(app)` route-group prefix (e.g. from a universal link that mirrors the * app's own internal route paths verbatim). */ const DEEP_LINK_PATTERNS: { regex: RegExp; buildPath: (id: string) => string }[] = [ diff --git a/src/theme/color-utils.test.ts b/src/theme/color-utils.test.ts index 6e895b4..d9d1e06 100644 --- a/src/theme/color-utils.test.ts +++ b/src/theme/color-utils.test.ts @@ -1,4 +1,4 @@ -import { alphaTokens, withAlpha } from '@/theme/color-utils'; +import { alphaTokens, darken, lighten, withAlpha } from '@/theme/color-utils'; describe('withAlpha', () => { it('converts a 6-digit hex color into an rgba string', () => { @@ -48,3 +48,42 @@ describe('alphaTokens', () => { }); }); }); + +describe('darken', () => { + it('scales every channel toward black by the given amount', () => { + expect(darken('#3c6df0', 0.2)).toBe('#3057c0'); + }); + + it('returns the input unchanged at 0 and black at 1', () => { + expect(darken('#3c6df0', 0)).toBe('#3c6df0'); + expect(darken('#3c6df0', 1)).toBe('#000000'); + }); + + it('clamps out-of-range amounts', () => { + expect(darken('#3c6df0', -1)).toBe('#3c6df0'); + expect(darken('#3c6df0', 5)).toBe('#000000'); + }); + + it('always emits two hex digits per channel', () => { + expect(darken('#0a0a0a', 0.5)).toBe('#050505'); + }); + + it('throws on an invalid hex color', () => { + expect(() => darken('#fff', 0.2)).toThrow(/darken/); + }); +}); + +describe('lighten', () => { + it('blends every channel toward white by the given amount', () => { + expect(lighten('#3c6df0', 0.5)).toBe('#9eb6f8'); + }); + + it('returns the input unchanged at 0 and white at 1', () => { + expect(lighten('#3c6df0', 0)).toBe('#3c6df0'); + expect(lighten('#3c6df0', 1)).toBe('#ffffff'); + }); + + it('throws on an invalid hex color', () => { + expect(() => lighten('blue', 0.2)).toThrow(/lighten/); + }); +}); diff --git a/src/theme/color-utils.ts b/src/theme/color-utils.ts index e7ba956..2657eb4 100644 --- a/src/theme/color-utils.ts +++ b/src/theme/color-utils.ts @@ -6,22 +6,37 @@ const HEX_PATTERN = /^#([0-9a-fA-F]{6})$/; -/** Parses a 6-digit `#rrggbb` hex string and returns an `rgba(r, g, b, alpha)` string. Throws on - * anything else (3-digit shorthand, 8-digit hex-with-alpha, named colors) — callers only ever - * feed this our own token hex values, so a loud failure beats silently returning a wrong color. */ -export function withAlpha(hex: string, alpha: number): string { +type Rgb = readonly [r: number, g: number, b: number]; + +/** Parses a 6-digit `#rrggbb` hex string into channel values. Throws on anything else (3-digit + * shorthand, 8-digit hex-with-alpha, named colors) — callers only ever feed this our own token / + * brand.json hex values, so a loud failure beats silently returning a wrong color. */ +function parseHex(hex: string, caller: string): Rgb { const match = HEX_PATTERN.exec(hex); if (!match) { - throw new Error(`withAlpha: expected a 6-digit hex color like "#3c6df0", got "${hex}"`); + throw new Error(`${caller}: expected a 6-digit hex color like "#3c6df0", got "${hex}"`); } - const intValue = parseInt(match[1], 16); - const r = (intValue >> 16) & 255; - const g = (intValue >> 8) & 255; - const b = intValue & 255; - const clampedAlpha = Math.min(1, Math.max(0, alpha)); + return [(intValue >> 16) & 255, (intValue >> 8) & 255, intValue & 255]; +} - return `rgba(${r}, ${g}, ${b}, ${clampedAlpha})`; +const clamp01 = (value: number): number => Math.min(1, Math.max(0, value)); + +const toHex = ([r, g, b]: Rgb): string => + `#${[r, g, b].map((c) => c.toString(16).padStart(2, '0')).join('')}`; + +/** Linearly blends every channel of `hex` toward `target` (0 = unchanged, 1 = fully `target`). */ +function mixToward(hex: string, target: number, amount: number, caller: string): string { + const t = clamp01(amount); + const blend = (channel: number): number => Math.round(channel + (target - channel) * t); + const [r, g, b] = parseHex(hex, caller); + return toHex([blend(r), blend(g), blend(b)]); +} + +/** Returns an `rgba(r, g, b, alpha)` string for a 6-digit `#rrggbb` hex color. */ +export function withAlpha(hex: string, alpha: number): string { + const [r, g, b] = parseHex(hex, 'withAlpha'); + return `rgba(${r}, ${g}, ${b}, ${clamp01(alpha)})`; } /** Shared alpha values for overlay-style states (hover/press/soft fills/scrims), so call sites @@ -35,3 +50,16 @@ export const alphaTokens = { scrim: 0.4, scrimDark: 0.6, } as const; + +/** Darkens a 6-digit `#rrggbb` hex color toward black by `amount` (0–1). Used to derive the + * light-scheme `brandStrong` (pressed/emphasis) shade from the single brand color in brand.json + * instead of hand-picking a second hex per brand — see src/theme/tokens.ts. */ +export function darken(hex: string, amount: number): string { + return mixToward(hex, 0, amount, 'darken'); +} + +/** Lightens a 6-digit `#rrggbb` hex color toward white by `amount` (0–1). Used to derive the + * dark-scheme brand shades (which need to sit on near-black surfaces) from the same brand color. */ +export function lighten(hex: string, amount: number): string { + return mixToward(hex, 255, amount, 'lighten'); +} diff --git a/src/theme/tokens.test.ts b/src/theme/tokens.test.ts index ae31759..363c8fb 100644 --- a/src/theme/tokens.test.ts +++ b/src/theme/tokens.test.ts @@ -1,4 +1,5 @@ import { colorTokens, radiusTokens, spacingTokens, typographyTokens } from '@/theme/tokens'; +import { darken, lighten } from '@/theme/color-utils'; const NEW_SEMANTIC_COLOR_KEYS = [ 'bg', @@ -157,3 +158,15 @@ describe('typographyTokens', () => { expect(typographyTokens.label.letterSpacing).toBeGreaterThan(0); }); }); + +describe('brand-derived color tokens', () => { + // jest.setup.ts mocks `extra.brandColor` as '#3c6df0'. + it('derives light and dark brand shades from the configured brand color', () => { + expect(colorTokens.light.brand).toBe('#3c6df0'); + expect(colorTokens.light.bubbleOut).toBe('#3c6df0'); + expect(colorTokens.light.brandStrong).toBe(darken('#3c6df0', 0.2)); + expect(colorTokens.dark.brand).toBe(lighten('#3c6df0', 0.35)); + expect(colorTokens.dark.brandStrong).toBe(lighten('#3c6df0', 0.55)); + expect(colorTokens.dark.bubbleOut).toBe(darken('#3c6df0', 0.1)); + }); +}); diff --git a/src/theme/tokens.ts b/src/theme/tokens.ts index d8f2d57..c509c03 100644 --- a/src/theme/tokens.ts +++ b/src/theme/tokens.ts @@ -8,7 +8,23 @@ * meaning (channel identity, unread state, bot state, semantic status) rather than decoration. */ -import { withAlpha } from './color-utils'; +import { brand } from '@/config/brand'; + +import { darken, lighten, withAlpha } from './color-utils'; + +/** Brand shades derived from the single `colors.brand` in brand.json rather than hand-picked per + * brand and per scheme. The light-scheme `brandStrong` (pressed/emphasis) is darkened ~20%; the + * dark scheme lifts the color toward white so it reads on near-black surfaces (`brand` ≈ the + * original ChatbotX `#7d9eff`, `brandStrong` ≈ `#a4bcff`) while `bubbleOut` stays close to the + * base color so outgoing bubbles keep enough contrast against white bubble text. */ +const brandShades = { + light: { brand: brand.brandColor, brandStrong: darken(brand.brandColor, 0.2) }, + dark: { + brand: lighten(brand.brandColor, 0.35), + brandStrong: lighten(brand.brandColor, 0.55), + bubbleOut: darken(brand.brandColor, 0.1), + }, +} as const; // --------------------------------------------------------------------------- // Colors @@ -28,12 +44,12 @@ const lightBase = { // (measured ~4.51:1). textTertiary: '#767063', textInverse: '#ffffff', - brand: '#3c6df0', - brandStrong: '#2851c9', + brand: brandShades.light.brand, + brandStrong: brandShades.light.brandStrong, onBrand: '#ffffff', bubbleIn: '#ffffff', bubbleInText: '#1c1b17', - bubbleOut: '#3c6df0', + bubbleOut: brandShades.light.brand, bubbleOutText: '#ffffff', bubbleBot: '#f1ecff', bubbleBotText: '#2f1f66', @@ -55,12 +71,12 @@ const darkBase = { textSecondary: '#b9b3a2', textTertiary: '#847d6b', textInverse: '#1c1b17', - brand: '#7d9eff', - brandStrong: '#a4bcff', + brand: brandShades.dark.brand, + brandStrong: brandShades.dark.brandStrong, onBrand: '#0e152b', bubbleIn: '#28261f', bubbleInText: '#f4f2ec', - bubbleOut: '#3c5fd9', + bubbleOut: brandShades.dark.bubbleOut, bubbleOutText: '#ffffff', bubbleBot: '#2a2145', bubbleBotText: '#e4d9ff',