diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 4914875..e3507d1 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -34,20 +34,6 @@ jobs: working-directory: app run: yarn install --immutable - - name: Cache bcsc-core build output - uses: actions/cache@v3 - with: - path: packages/bcsc-core/lib - # Cache will be invalidated if any source file changes - key: ${{ runner.os }}-bcsc-core-build-${{ hashFiles('packages/bcsc-core/src/**') }} - restore-keys: | - ${{ runner.os }}-bcsc-core-build- - - # Note: The `bcsc-core` package must be built before type checking. - - name: Build bcsc-core - working-directory: packages/bcsc-core - run: yarn build - - name: Check style working-directory: app run: | @@ -58,12 +44,9 @@ jobs: working-directory: app run: yarn lint - # TEMPORARILY DISABLED: TypeScript check - # TODO: Re-enable after fixing theme.ts type errors in separate PR - # - name: Check types - # working-directory: app - # # Note: To pass the type check, the `bcsc-core` package must be built first. - # run: yarn typecheck + - name: Check types + working-directory: app + run: yarn typecheck test: runs-on: ubuntu-22.04 diff --git a/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch b/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch new file mode 100644 index 0000000..63a99d9 --- /dev/null +++ b/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch @@ -0,0 +1,21 @@ +diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt +index 5cc55c5ee3d05cbe9a7b92b0d1b031e0166c7456..3639134c3858f2cad688b6eebf778db8105006d4 100644 +--- a/android/CMakeLists.txt ++++ b/android/CMakeLists.txt +@@ -87,7 +87,15 @@ if(${REACT_NATIVE_VERSION} LESS 71) + ) + endif() + +-if(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) ++if(${REACT_NATIVE_VERSION} GREATER_EQUAL 76) ++ # RN 0.76 merged libreactnativejni into a single libreactnative.so prefab target ++ target_link_libraries( ++ ${PACKAGE_NAME} ++ ReactAndroid::jsi ++ ReactAndroid::reactnative ++ fbjni::fbjni ++ ) ++elseif(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) + target_link_libraries( + ${PACKAGE_NAME} + ReactAndroid::jsi diff --git a/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch b/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch new file mode 100644 index 0000000..6775de7 --- /dev/null +++ b/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch @@ -0,0 +1,21 @@ +diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt +index 74b6aff9c7cf062724475a58b9030f655a939e18..54b65bc306c926a866c10e74c88a6fff8d1c3eca 100644 +--- a/android/CMakeLists.txt ++++ b/android/CMakeLists.txt +@@ -87,7 +87,15 @@ if(${REACT_NATIVE_VERSION} LESS 71) + ) + endif() + +-if(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) ++if(${REACT_NATIVE_VERSION} GREATER_EQUAL 76) ++ # RN 0.76 merged libreactnativejni into a single libreactnative.so prefab target ++ target_link_libraries( ++ ${PACKAGE_NAME} ++ ReactAndroid::jsi ++ ReactAndroid::reactnative ++ fbjni::fbjni ++ ) ++elseif(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) + target_link_libraries( + ${PACKAGE_NAME} + ReactAndroid::jsi diff --git a/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch b/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch index 8555e52..cfefbf5 100644 --- a/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch +++ b/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch @@ -1,3 +1,24 @@ +diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt +index c84556e989cd95a18c5a8296931c8d97671a3c5c..47ef06ff796d4ce0ca0ffd1338dc5dc7965834a9 100644 +--- a/android/CMakeLists.txt ++++ b/android/CMakeLists.txt +@@ -87,7 +87,15 @@ if(${REACT_NATIVE_VERSION} LESS 71) + ) + endif() + +-if(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) ++if(${REACT_NATIVE_VERSION} GREATER_EQUAL 76) ++ # RN 0.76 merged libreactnativejni into a single libreactnative.so prefab target ++ target_link_libraries( ++ ${PACKAGE_NAME} ++ ReactAndroid::jsi ++ ReactAndroid::reactnative ++ fbjni::fbjni ++ ) ++elseif(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) + target_link_libraries( + ${PACKAGE_NAME} + ReactAndroid::jsi diff --git a/android/build.gradle b/android/build.gradle index 9017d77eb32573415c7922cd83dae5cd792a885f..083320b13d82925625e57b929387a20a6d42c841 100644 --- a/android/build.gradle diff --git a/UPGRADE_PROGRESS.md b/UPGRADE_PROGRESS.md new file mode 100644 index 0000000..887904e --- /dev/null +++ b/UPGRADE_PROGRESS.md @@ -0,0 +1,307 @@ +# Keyring Wallet — Upstream Sync & Upgrade Progress + +> **Purpose of this file**: hand-off document so any agent/human can resume the upgrade +> effort with zero conversation context. Update it at every phase gate and whenever a +> significant decision or discovery is made. Keep it factual and current. + +Last updated: 2026-07-04 (Phase 2 COMPLETE — RN 0.77.3, BCSC dropped, E2E green both platforms) + +--- + +## 1. Goal + +Bring Keyring Wallet (fork of bcgov/bc-wallet-mobile + openwallet-foundation/bifold-wallet) +as close to upstream as possible: React Native, React, native toolchains, credo-ts, and all +major dependencies. The VRC (Verifiable Relationship Credential) module is Keyring's unique +contribution and must keep working (its tests are the contract). Proof of success = app +bundles AND runs on both platforms, verified by an Appium E2E script that does full +onboarding + a VRC exchange between two devices/emulators. + +Secondary goal (last phase): move VRC issuance to W3C VC Data Model 2.0. +DIDComm v2 is **out of scope** — not shipped in any stable credo release (PR +openwallet-foundation/credo-ts#2704 still open as of 2026-06). + +## 2. Decisions already made (by Alberto, 2026-07-04) + +| Topic | Decision | +| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| App upstream reference | `bcgov/bc-wallet-mobile` (NOT BC-Wallet-Demo, that's a web demo) | +| BCSC (BC Services Card) code | **Drop it** (`react-native-bcsc-core` pkg, bcsc API code) — but **keep the Keyring theme** (`app/src/keyring-theme/`, which lives alongside the bcsc-theme scaffolding it was derived from) | +| Storybook | Drop it (Storybook 5.3 won't survive React 19; user doesn't care) | +| VC 2.0 old-credential migration | Not needed (~0 users). Bump RCE protocol version so old/new wallets fail cleanly | +| E2E devices | Emulators/simulators first; fall back to real devices (user has both) if attestation/biometrics block simulators | +| Mediator + witness-server for E2E | Already hosted; endpoints configured in `app/.env` | +| Bifold sync strategy | "Branch swap": new branch in `berkmancenter/keyring-bifold` starting from upstream 3.0.16 content, port Keyring delta onto it. Same repo, no new repo. Gives shared git history with upstream going forward | +| RN upgrade path | Two hops: 0.73→0.77 (last React-18 RN) first, then 0.81+React 19 together with bifold 3.x/credo 0.6 | + +## 3. Current versions vs upstream targets + +| Component | Current | Target (upstream, 2026-07) | +| ------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| `@bifold/*` | 2.7.4 (fork, portal: to `bifold/packages/*`) | 3.0.16 | +| credo-ts | 0.5.17 (+ yarn patches) | 0.6.3 (DIDComm split into `@credo-ts/didcomm`; agent API moves to `agent.modules.*` / `agent.didcomm.*`) | +| React Native | 0.73.11 | 0.81.5 | +| React | 18.3.1 | 19.1.0 | +| askar | `@hyperledger/aries-askar-react-native` 0.2.3 | renamed `@openwallet-foundation/askar-*` 0.6.0 | +| anoncreds RN | 0.2.4 | check upstream bifold 3.0.16 resolutions | +| indy-vdr RN | 0.2.2 (patched) | 0.2.4 (upstream carries its own patch) | +| VRC signature suite | Ed25519Signature2018 (VCDM 1.1) | Phase 5: DataIntegrityProof / eddsa-rdfc-2022 (VCDM 2.0) — verify credo JSON-LD VCDM 2.0 support first | + +Upstream bifold 3.0.16 root resolutions worth copying: react 19.1.0, react-native 0.81.5, +react-native-vision-camera 4.7.3, expo ~54 (they added expo modules!), plus their patch set +(`.yarn/patches` upstream): credo-ts-react-native biometrics patch, indy-vdr-react-native 0.2.4 +patch, animo pex + sphereon pex patches (same ones we carry). + +## 4. Repo topology & baselines + +- Parent repo: `berkmancenter/keyring-wallet` (this repo). Yarn 4 workspaces: `app`, `packages/*` + (only `packages/bcsc-core` — to be dropped). `bifold/` is a nested git repo + (gitlink in parent) → `berkmancenter/keyring-bifold`. +- `@bifold/*` deps resolve via `portal:bifold/packages/*` in root package.json resolutions. +- Branches at baseline: parent on `feat/configurable-mediator-v2-batch-pickup`; bifold on + `fix/disable-native-build-triggers` (1 commit ahead of its origin/main). +- **Baseline tags created (Phase 0): `upgrade-baseline-p0` in BOTH repos.** +- Upstream remote added inside `bifold/`: `upstream` → openwallet-foundation/bifold-wallet + (tag `v2.7.4` fetched; upstream/main fetched). +- bc-wallet-mobile reference clone: `/tmp/bc-wallet-mobile` (full clone; re-clone if gone). + +## 5. Delta extraction results (Phase 0) + +### 5.1 keyring-bifold vs upstream `v2.7.4` (exact diff: `git diff v2.7.4 HEAD` inside `bifold/`) + +Fork point is exact: upstream tag `v2.7.4`. 457 files changed (excl. lockfiles): +290 added / 158 modified / 9 deleted. + +**Added (the Keyring contribution — ports cleanly, upstream never touches these paths):** + +- `packages/core/src/modules/vrc/` — 67 files, the VRC module (managers, protocol, types, tests) +- `packages/witness-server/` — 66 files (server component; not an RN package) +- `packages/vrc-reference/` — 46 files (reference implementation + conformance) +- `packages/vrc-shared/` — 7 files (documentLoader etc.) +- `packages/vrc-contexts/` — 5 files (JSON-LD contexts) +- Non-VRC additions to core: Messages/chat screens (`Messages.tsx`, `MessageStack.tsx`, + `useUnreadMessages`, `activeChatTracker`, `InAppMessageNotifier`, `MessageNotificationToast`), + wallet Export/Import screens, `About.tsx`, Toggle screens (HardwareAttestation, Witnessing, + WitnessReporting), `BiometricConfirmationModal` + `biometric-confirmation` context, + `QRCodeExchangeSlider`, pseudonym utils, seedTestCredentials, ~18 SVG assets, 39 test files +- Docs: `docs/VRC_*.md`, `docs/WITNESSED_EXCHANGE_FLOW.md`, etc. + +**Modified (158 files — must be re-applied by hand onto 3.0.16 where upstream moved):** + +- Heaviest churn (ins/del): `hooks/chat-messages.tsx` (803/84), `screens/CredentialOffer.tsx` + (476/61), `screens/Settings.tsx` (351/78), `components/chat/ChatMessage.tsx` (258/82), + `navigators/SettingStack.tsx` (216/133), `navigators/TabStack.tsx` (133/132), + `screens/Onboarding.tsx`, `contexts/reducers/store.ts` (+148), `index.ts` (+91 exports), + `container-api.ts` / `container-impl.ts`, `theme.ts` / `theme.interface.ts`, + localization en/fr/pt-br, `utils/agent.ts`, `hooks/useBifoldAgentSetup.ts` +- Native: `packages/react-native-attestation/` — heavily customized + (`AttestationModule.kt` ~1.5k lines, `Attestation.mm` ~1.5k lines, build.gradle, podspec, + `NativeAttestation.ts`) — hardware-backed VRC signing lives here. Treat as Keyring-owned; + diff upstream's 3.0.16 version for template changes (New Arch!) and port ours onto it. +- Total modified-src churn: ~5.2k insertions / 1.3k deletions across 80 core src files. + +**Deleted upstream files (9)**: `ListContacts.tsx`, `ContactDetails.tsx` (+ their tests/snaps), +`InfoIcon.tsx`, CODEOWNERS, MAINTAINERS.md — Keyring replaced contacts UI with its own. + +Full list: regenerate anytime with +`cd bifold && git diff --name-status v2.7.4 HEAD -- . ':!yarn.lock' ':!package-lock.json'` + +### 5.2 app/ vs bc-wallet-mobile fork point + +Fork point: bc-wallet-mobile commit **`f628bb23`** (2025-09-17, "feat: update address #2452", +bifold 2.7.4 / credo 0.5.17 era; `e12ca6d1` scores identically — either works as reference). + +**Keyring-only (added) in `app/`:** + +- `src/keyring-theme/` — THE KEEPER (user decision) +- `src/types/`, `src/components/SetupCard.tsx`, `src/screens/Biometry.tsx` +- Keyring branding assets (fonts GT-America/SourceSans3, Keyring/ASML logos, onboarding/tab SVGs) +- `universal-link-site/`, `witness-link-site/`, `patches/` (jsonld-signatures, rdf-canonize), + `__mocks__/@bifold`, `.jest/`, extra tests (`__tests__/navigation`, `__tests__/utils`) + +**Modified vs fork point (~45 files):** `App.tsx`, `container-imp.ts`, `index.js`, +`src/store.tsx`, `src/constants.ts`, `src/theme.ts`, `src/onboarding.ts`, +`src/hooks/useBCAgentSetup.ts`, `src/utils/bc-agent-modules.ts`, `src/utils/mediator.ts`, +`src/components/OnboardingPages.tsx`, localization index files, several screens +(Splash, Terms, Preface, Developer, PINExplainer, RemoteLogWarning), `bcsc-theme/` scaffolding +(MainStack, RootStack, Settings, theme, navigators types), Podfile, build.gradle, +gradle.properties, settings.gradle, AppDelegate.mm, Info.plist, entitlements, app.json, +babel/metro/jest configs, `.env.sample`. + +**bcwallet-only (we deleted):** `src/bcwallet-theme/`, BCSans fonts, android release.keystore. + +### 5.3 Yarn patches carried (root `.yarn/patches` + `app/patches`) + +- credo 0.5.17: anoncreds, core, indy-vdr → **die with credo 0.6.3** (re-derive only if the + underlying fix is still missing; check upstream 3.0.16 patch set first — they carry + equivalents for pex/indy-vdr) +- `@animo-id/pex`, `@sphereon/pex` → upstream 3.0.16 carries the SAME patches; adopt theirs +- indy-vdr-react-native / indy-vdr-shared 0.2.2 → upstream patches 0.2.4 instead +- app/patches (patch-package): `@digitalcredentials/jsonld-signatures@9.4.0`, + `rdf-canonize@5.0.0` → VRC-related, keep and re-verify + +## 6. Phase plan & status + +- [x] **Phase 0 — Baseline & delta extraction** (this document; tags `upgrade-baseline-p0`) + - [x] Delta bifold vs v2.7.4 + - [x] Delta app vs bc-wallet-mobile f628bb23 + - [x] Baseline test run recorded (§7 — all green) +- [x] **Phase 1 — Appium E2E harness on CURRENT app** — COMPLETE 2026-07-04. + **Green run**: `node e2e/run-vrc-exchange.js` → full two-wallet exchange + (Android emulator Pixel_6_API_33 ↔ iOS simulator iPhone 17) in ~7 min: + both onboardings → invitation → paste → connection → bidirectional VRC offers → + manual accepts → "added to your wallet" ×2 → peer R-card names visible in Contacts ×2. + - Environment verified 2026-07-04: Appium 3.5.0 with xcuitest 11.10.0 + uiautomator2 7.6.1 + installed; iOS 26.3 simulators (iPhone 17 etc.); AVDs `Pixel_6_API_31`, `Pixel_6_API_33`. + - Harness lives in `e2e/` (plain node + webdriverio, no test-runner framework): + `run-onboarding-smoke.js` (single device) and `run-vrc-exchange.js` (two devices). + Artifacts (screenshots + page-source XML) land in `e2e/artifacts/`. + - [x] Android debug APK builds (`cd app/android && ./gradlew assembleDebug`) + - [x] iOS simulator app builds (`cd app/ios && xcodebuild -workspace AriesBifold.xcworkspace +-scheme AriesBifold -configuration Debug -sdk iphonesimulator -derivedDataPath build/e2e-dd build`) + → product is `KeyRing.app`. DO NOT pass CODE_SIGNING_ALLOWED=NO: it strips the keychain + entitlements and the app fails onboarding with "Error code 1001 … required entitlement". + - [x] **Android onboarding smoke passes** (fresh install → GetStarted → PIN explainer → + PIN → biometry Continue → wallet naming → R-Card form → main tabs). + - [x] iOS onboarding smoke passes (rebuilt without CODE_SIGNING_ALLOWED=NO; numeric-keypad + dismissal = tap neutral content area x:235,y:240; `appium:platformVersion` must match an + installed simctl SDK, currently 26.3). + - [x] Two-device VRC exchange (Android emulator ↔ iOS simulator) PASSES. + Flow facts the harness encodes (don't rediscover): + - VRC offers are NOT auto-accepted. Each wallet gets a chat message "Credential offer + received — Would you like to accept it? YES/NO" (`ChatMessage.tsx` + CredentialOfferActions; YES has NO testID → find by text) → CredentialOffer screen → + `AcceptCredentialOffer` → `ContactAddedToYourWallet` (VRC flow shows the Contact + variant, not `CredentialAddedToYourWallet`) → `Done`. + - VRCs are HIDDEN from the Wallet credential list by design + (`ListCredentials.shouldHideFromWallet` filters RelationshipCredential/DTGCredential). + Success signal = peer's R-card name in the Contacts list (proves credential content + arrived, not just the connection). + - Wallet auto-locks after 5 min inactivity; mediator round-trips can exceed it — + harness has `unlockIfLocked` (PIN re-entry) woven into every wait loop. + - Mediator delivery is slow (pickup polling); full run ≈ 9–10 min. + - A redelivered duplicate offer-credential message logs "Error handling message … + offer-credential" + "Failed to process message" with empty error `{}` — benign, + exchange still completes. + - Simulator/emulator hardware-signing caveats (logged by [VRC:Sign], NON-fatal — flow falls + back to software keys): iOS sim "App Attest not supported"; Android emulator "Secure lock + screen must be enabled" (no lock screen configured on AVD); embedded Google root CA expired. + - Known red-box noise on both devices: unhandled rejection `IndyVdrError … did +'TeT8SJGHruVL9up3Erp4o' … Pool timeout` (indy ledger DID lookup from container-imp.ts + OCA/ledger config; unrelated to VRC, but it paints a dev-mode toast over the UI). + - IMPORTANT (harness ops): metro must NOT be piped through `tail`/`grep` when started — it + swallows all RN JS console logs. Start plainly: `cd app && npx react-native start`. + Both apps' JS logs stream into the metro terminal; that's the primary debugging signal. + - Learnings encoded in the harness (don't rediscover these): + - Debug builds need metro on the host (`cd app && npx react-native start`) and, for + Android, `adb -s reverse tcp:8081 tcp:8081` BEFORE first app launch — + caps use `appium:autoLaunch:false`, harness runs reverse then `activateApp`. + - Two adb devices may be attached (user's physical phone) — always pass `-s `. + - Appium needs ANDROID_HOME exported; start: + `ANDROID_HOME=$HOME/Library/Android/sdk appium --port 4723 --relaxed-security`. + - Invitation URL is read from a `__DEV__`-only hidden ThemedText with + testID `InvitationUrl` added to `bifold/.../components/misc/QRScanner.tsx` + (accessibilityLabel = invitation URL). Receiver uses the stock PasteUrl screen + (`PasteUrlButton` → `PastedUrl` input → `ScanPastedUrl`). + - A feature-tour popup ("Contact requests") shows over the Contacts screen after + onboarding; dismiss via testID `Close` before doing anything. + - testID prefix is `com.ariesbifold:id/` (bifold `testIdWithKey`); Android → resource-id, + iOS → accessibility id. + - Fresh install (uninstall first) → onboarding → VRC exchange between Android emulator + and iOS simulator. QR problem solved via invite-link injection, NOT camera. Good news: + bifold core already ships a `PasteUrl` screen (`packages/core/src/screens/PasteUrl.tsx`, + reachable from Scan/ConnectStack) — the harness can read the invitation URL from wallet A + (expose via testID on the QR/connect screen) and paste it into wallet B. A temporary code + hook may not be needed at all. Uses hosted mediator/witness from `app/.env`. + - No existing e2e tooling in the repo (no appium/wdio/detox anywhere) — build fresh under + `e2e/` at repo root. + - Check first: does hardware attestation/biometry block simulators? If yes, add dev bypass + flag or use real devices. +- [x] **Phase 2 — RN 0.73.11 → 0.77.x, React 18 kept, credo/bifold untouched** — COMPLETE. + Branch: `upgrade/phase2-rn77` (root repo). DONE (2026-07-04): + - RN 0.77.3 template applied (Upgrade Helper diff): Gradle 8.10.2, AGP 8.7.3, + Kotlin 2.0.21, buildTools 35, NDK 27.1.12297006, iOS deployment target 15.1, + settings.gradle plugin-based autolinking, `MainApplication.kt` OpenSourceMergedSoMapping, + `AppDelegate.mm` -bundleURL, Podfile Flipper removal + `$VCEnableLocation=false`. + - Ecosystem bumps: gesture-handler 2.22, safe-area-context 5.1, screens 4.6, svg 15.11, + vision-camera 4.7.3, webview 13.13 (13.10 fails Kotlin 2.0 compile). bifold core + peerDeps loosened to `>=`. + - `dependenciesMeta.built=false` for @2060.io/ffi-napi+ref-napi (node-gyp/distutils breakage, + not needed at runtime). Jest mock path: `react-native/src/private/animated/NativeAnimatedHelper`. + - RN 0.77 BackHandler API: `subscription.remove()` in bifold Onboarding/ProofDetails/ + ProofRequesting. Kotlin 2.0 null-safety fix in react-native-attestation. + - **RN 0.76+ prefab breakage (KEY LEARNING)**: @hyperledger/{anoncreds,aries-askar,indy-vdr} + -react-native CMakeLists link `ReactAndroid::reactnativejni`, which no longer exists + (merged into `ReactAndroid::reactnative` = single libreactnative.so). Fixed via yarn + patches (indy-vdr patch REPLACES the pre-existing 627d424b96 patch — same filename, now + also carries the CMake fix). Plus app/build.gradle `packagingOptions.jniLibs.pickFirsts` + for libreactnative/jsi/fbjni/c++\_shared (libraries copy prefab .so into their AARs). + - RN 0.77 codegen is stricter: bcsc-core spec couldn't use `Omit<>`, indexer+named props, + or `any` → replaced JWTClaims with `UnsafeObject` (react-native/Libraries/Types/CodegenTypes). + Moot once bcsc-core is dropped, but unblocked pod install. + - iOS pods: full `rm -rf Pods Podfile.lock` needed (boost snapshot conflict from 0.73 lock). + - GATE STATUS: app jest 23/88 PASS, bifold core jest 134/1242 PASS, + `assembleDebug` BUILD SUCCESSFUL, iOS simulator `xcodebuild` BUILD SUCCEEDED. + - BCSC removal DONE (2026-07-04): deleted `packages/bcsc-core` workspace, + `app/src/bcsc-theme/`, `useSetupSteps`, bcsc tests. `store.tsx` stripped of + BCSCState/BCSCDispatchAction/Mode (KeyRing is the only mode now; Root always renders + KeyRingRootStack). Removed `BCSCApiClientProvider` from App, BCSC/KeyRingSC theme + names + Developer screen theme/mode toggles, `@bcsc-theme` aliases + (babel/tsconfig/metro), bcsc-core refs in package.jsons. keyring-theme KEPT. + Unused BCSC localization strings left in place (inert; prune later). + Post-removal gate: typecheck PASS, eslint PASS, app jest 14 suites/27 tests PASS + (Developer snapshot updated), Android assembleDebug PASS (gradle locks regenerated), + iOS pod install + simulator build PASS (RNBcscCore pod gone). + - E2E VRC exchange rerun DONE (2026-07-04): green on BOTH platforms after two fixes: + 1. `@react-native-firebase` 14.x is incompatible with RN 0.77 (iOS crashed at startup, + "No Firebase App '[DEFAULT]'"); bumped app+messaging to ~21.14.0, and added + `RCTAppDependencyProvider` to AppDelegate.mm (required by RN 0.77 for third-party + Fabric component/module resolution — its absence caused the + `setSheetLargestUndimmedDetent` unrecognized-selector crash). + 2. **RN 0.77 / safe-area-context 5.x layout regression (KEY LEARNING)**: ScrollView + with `height:'100%'` inside a SafeAreaView that lacks `flex:1` pushes the + bottom controls (marginTop:'auto') off-screen. Fixed by `flex:1` on both the + SafeAreaView and the ScrollView in: CredentialOfferAccept, ProofRequestAccept, + CameraDisclosureModal, MobileVerifierLoading, CommonRemoveModal (bifold) and + PersonCredentialLoading (app keyring-theme). Snapshots updated. + - PHASE 2 GATE PASSED: app jest 14/27 PASS, bifold core jest 134 suites / 1242 PASS, + Android + iOS build PASS, two-device E2E VRC exchange PASS on Android and iOS. +- [ ] **Phase 3 — Big hop: bifold 3.0.16 + credo 0.6.3 + React 19 + RN 0.81** + - In `bifold/`: new branch `upgrade/bifold-3.x` = upstream v3.0.16 content; port §5.1 delta + onto it. Mechanical credo API rewrite everywhere: `agent.credentials` → + `agent.modules.credentials`, explicit DIDComm module registration, askar rename. + - Attestation package: start from upstream 3.0.16 version, re-apply Keyring crypto/signing. + - App: RN 0.81 + React 19 (reference: bc-wallet-mobile main), drop Storybook. + - New Architecture: try `newArchEnabled=true` (upstream default); custom native modules + (attestation) must be audited; fall back to false if needed, but record it. + - Adopt upstream patch set; wallet-open/migration smoke test (askar store compat). + - Gate: VRC conformance tests green, jest green, both bundle, E2E green. +- [ ] **Phase 4 — App-layer upstream sync** (port wanted bc-wallet-mobile improvements; + containers/DI, screens). Gate: full suite + E2E. +- [ ] **Phase 5 — VC 2.0 for VRC** (secondary goal) + - FIRST verify credo 0.6.3 supports issuing/verifying JSON-LD Data Integrity VCDM 2.0 + (its VCDM 2.0 support is documented for vc+jwt / dc+sd-jwt; LDP 2.0 unverified). + - contexts v2 in `vrc-contexts`, documentLoader in `vrc-shared`, witness-server verification, + conformance tests, RCE protocol version bump. No data migration (user decision). + +## 7. Baseline test results (Phase 0 gate — all green, recorded 2026-07-04) + +- `app`: `yarn test` → **PASS** (23 suites, 88 tests, 13 snapshots) +- `bifold` (all workspaces): `yarn test` → **PASS**; `packages/core` alone: + **134 suites, 1242 passed / 2 skipped, 137 snapshots** (includes VRC module tests) +- `app`: `yarn typecheck` → **PASS** +- `bifold`: `yarn typecheck` (all workspaces) → **PASS** + +Note: sandboxed shells can't reach watchman (`Operation not permitted` on its socket); +run jest outside sandbox or with `--watchman=false`. + +## 8. How to resume (for the next agent) + +1. Read this file top to bottom. +2. `git -C . status` and `git -C bifold status` — check for WIP beyond `.codegraph/.cursor`. +3. Find the first unchecked box in §6; that's the active phase. Respect the gates. +4. Baseline tags `upgrade-baseline-p0` exist in both repos if you need to diff/rollback. +5. Conventions: bifold commits need `Signed-off-by: Alberto L ` as the + last line; never add Cursor co-author trailers. Don't push without being asked. +6. Regenerate deltas with the commands in §5 if trees have moved. +7. Update §6 checkboxes, §7 results, and the "Last updated" line before you stop. diff --git a/app/.bundle/config b/app/.bundle/config index 87bd688..95838fc 100644 --- a/app/.bundle/config +++ b/app/.bundle/config @@ -1,3 +1,4 @@ --- BUNDLE_FORCE_RUBY_PLATFORM: "1" -BUNDLE_FROZEN: "true" +BUNDLE_FROZEN: "false" +BUNDLE_DEPLOYMENT: "false" diff --git a/app/.env.sample b/app/.env.sample index 25f7ba0..1b6dcaf 100644 --- a/app/.env.sample +++ b/app/.env.sample @@ -1,6 +1,8 @@ # OCA_URL sourced from upstream bcgov/aries-oca-bundles repository OCA_URL=https://raw.githubusercontent.com/bcgov/aries-oca-bundles/main/ MEDIATOR_URL=https://f326-207-194-65-204.ngrok.io?c_i=eyJAdHlwZSI6ICJodHRwczovL2RpZGNvbW0ub3JnL2Nvbm5lY3Rpb25zLzEuMC9pbnZpdGF0aW9uIiwgIkBpZCI6ICI2MjQ0ZThiNS0wNWYzLTRhYWItYjM1Yy1lYWVlMWNmZTAyM2MiLCAicmVjaXBpZW50S2V5cyI6IFsiQ3lqM1BHRUJzQ3RyUGFtTTQyRngza3BlYmR2QWdNd1lGejlFS3RmNnlUN3giXSwgImxhYmVsIjogIk1lZGlhdG9yIiwgInNlcnZpY2VFbmRwb2ludCI6ICJodHRwczovL2YzMjYtMjA3LTE5NC02NS0yMDQubmdyb2suaW8ifQ== +# Enable Pickup V2 live mode + batch pickup (required for Credo-TS mediators) +MEDIATOR_USE_V2_BATCH_PICKUP=false MEDIATOR_USE_PUSH_NOTIFICATIONS=false LOAD_STORYBOOK=false PROOF_TEMPLATE_URL= diff --git a/app/App.tsx b/app/App.tsx index 8618dde..7442ca7 100644 --- a/app/App.tsx +++ b/app/App.tsx @@ -27,7 +27,6 @@ import Toast from 'react-native-toast-message' import { container } from 'tsyringe' import Root from '@/Root' -import { BCSCApiClientProvider } from '@/bcsc-theme/contexts/BCSCApiClientContext' import { KeyRingThemeNames, surveyMonkeyExitUrl, surveyMonkeyUrl } from '@/constants' import { localization } from '@/localization' import { initialState, reducer } from '@/store' @@ -70,30 +69,28 @@ const App = () => { - - - - - - - - - setSurveyVisible(false)} - /> - - - - - - - - - - + + + + + + + + setSurveyVisible(false)} + /> + + + + + + + + + diff --git a/app/Gemfile b/app/Gemfile index 268b2a3..65aa988 100644 --- a/app/Gemfile +++ b/app/Gemfile @@ -1,5 +1,8 @@ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version ruby ">= 2.6.10" -gem 'cocoapods', '~> 1.14.3' -gem 'activesupport', '~> 7.0.8' +# Exclude problematic versions of cocoapods and activesupport that cause build failures. +gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' +gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' +gem 'xcodeproj', '< 1.26.0' +gem 'concurrent-ruby', '< 1.3.4' diff --git a/app/Gemfile.lock b/app/Gemfile.lock index 35f3dfe..3af5b20 100644 --- a/app/Gemfile.lock +++ b/app/Gemfile.lock @@ -1,27 +1,34 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.7) + CFPropertyList (3.0.9) + activesupport (7.1.6) base64 - nkf - rexml - activesupport (7.0.8) + benchmark (>= 0.3) + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) + mutex_m + securerandom (>= 0.3) tzinfo (~> 2.0) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) - base64 (0.2.0) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (4.1.2) claide (1.1.0) - cocoapods (1.14.3) + cocoapods (1.15.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.3) + cocoapods-core (= 1.15.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -36,7 +43,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.3) + cocoapods-core (1.15.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -56,47 +63,53 @@ GEM netrc (~> 0.11) cocoapods-try (1.2.0) colored2 (3.1.2) - concurrent-ruby (1.2.2) + concurrent-ruby (1.3.3) + connection_pool (2.5.5) + drb (2.2.3) escape (0.0.4) - ethon (0.16.0) + ethon (0.18.0) ffi (>= 1.15.0) - ffi (1.17.1) + logger + ffi (1.17.4) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) httpclient (2.9.0) mutex_m - i18n (1.14.1) + i18n (1.14.8) concurrent-ruby (~> 1.0) - json (2.10.2) - minitest (5.20.0) + json (2.20.0) + logger (1.7.0) + minitest (5.26.1) molinillo (0.8.0) mutex_m (0.3.0) - nanaimo (0.4.0) + nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) - nkf (0.2.0) public_suffix (4.0.7) - rexml (3.4.1) + rexml (3.4.4) ruby-macho (2.5.1) - typhoeus (1.4.1) - ethon (>= 0.9.0) + securerandom (0.3.2) + typhoeus (1.6.0) + ethon (>= 0.18.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.27.0) + xcodeproj (1.25.1) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.4.0) + nanaimo (~> 0.3.0) rexml (>= 3.3.6, < 4.0) PLATFORMS ruby DEPENDENCIES - activesupport (~> 7.0.8) - cocoapods (~> 1.14.3) + activesupport (>= 6.1.7.5, != 7.1.0) + cocoapods (>= 1.13, != 1.15.1, != 1.15.0) + concurrent-ruby (< 1.3.4) + xcodeproj (< 1.26.0) RUBY VERSION ruby 2.7.8p225 diff --git a/app/__tests__/bcsc-theme/api/useConfigApi.test.ts b/app/__tests__/bcsc-theme/api/useConfigApi.test.ts deleted file mode 100644 index 70a0431..0000000 --- a/app/__tests__/bcsc-theme/api/useConfigApi.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import useConfigApi from '@bcsc-theme/api/hooks/useConfigApi' -import { renderHook } from '@testing-library/react-native' -import { Platform } from 'react-native' - -const mockApiClient = { - baseURL: 'https://mock-api-base-url.com', - get: jest.fn().mockImplementation(() => Promise.resolve({ data: {} })), -} - -describe('useConfigApi', () => { - beforeEach(() => { - Platform.OS = 'ios' - jest.clearAllMocks() - }) - - const config = renderHook(() => useConfigApi(mockApiClient as any)).result.current - - describe('getServerStatus', () => { - it('calls the correct endpoint for android', async () => { - // eslint-disable-next-line no-extra-semi - ;(mockApiClient.get as jest.Mock).mockResolvedValueOnce({ data: { status: 'ok' } }) - Platform.OS = 'android' - - // Call the method we're testing - const response = await config.getServerStatus() - - // Verify correct endpoint called with the mocked baseURL - expect(mockApiClient.get).toHaveBeenCalledWith(`${mockApiClient.baseURL}/cardtap/v3/status/android/mobile_card`, { - skipBearerAuth: true, - }) - expect(response).toEqual({ status: 'ok' }) - }) - - it('calls the correct endpoint for ios', async () => { - // eslint-disable-next-line no-extra-semi - ;(mockApiClient.get as jest.Mock).mockResolvedValueOnce({ data: { status: 'ok' } }) - const response = await config.getServerStatus() - - expect(mockApiClient.get).toHaveBeenCalledWith(`${mockApiClient.baseURL}/cardtap/v3/status/ios/mobile_card`, { - skipBearerAuth: true, - }) - expect(response).toEqual({ status: 'ok' }) - }) - - it('handles API errors gracefully', async () => { - // eslint-disable-next-line no-extra-semi - ;(mockApiClient.get as jest.Mock).mockRejectedValueOnce(new Error('Network error')) - await expect(config.getServerStatus()).rejects.toThrow('Network error') - }) - }) - - describe('getTermsOfUse', () => { - it('calls the correct endpoint', async () => { - // eslint-disable-next-line no-extra-semi - ;(mockApiClient.get as jest.Mock).mockResolvedValueOnce({ data: { terms: 'Sample terms' } }) - const response = await config.getTermsOfUse() - - expect(mockApiClient.get).toHaveBeenCalledWith(`${mockApiClient.baseURL}/cardtap/v3/terms`) - expect(response).toEqual({ terms: 'Sample terms' }) - }) - - it('handles API errors gracefully', async () => { - // eslint-disable-next-line no-extra-semi - ;(mockApiClient.get as jest.Mock).mockRejectedValueOnce(new Error('Network error')) - await expect(config.getTermsOfUse()).rejects.toThrow('Network error') - }) - }) -}) diff --git a/app/__tests__/bcsc-theme/hooks/useFactoryReset.test.ts b/app/__tests__/bcsc-theme/hooks/useFactoryReset.test.ts deleted file mode 100644 index b5635a5..0000000 --- a/app/__tests__/bcsc-theme/hooks/useFactoryReset.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { renderHook, act } from '@testing-library/react-native' -import * as BcscCore from 'react-native-bcsc-core' -import * as Bifold from '@bifold/core' -import useApi from '@/bcsc-theme/api/hooks/useApi' -import { useFactoryReset } from '@/bcsc-theme/api/hooks/useFactoryReset' -import { BCDispatchAction } from '@/store' -import { DispatchAction } from '@bifold/core' - -jest.mock('@/bcsc-theme/api/hooks/useApi') -jest.mock('@bifold/core') - -describe('useFactoryReset', () => { - beforeEach(() => { - jest.resetAllMocks() - }) - - it('should factory reset the device when successful', async () => { - const bcscCoreMock = jest.mocked(BcscCore) - const useApiMock = jest.mocked(useApi) - const bifoldMock = jest.mocked(Bifold) - - const deleteRegistrationMock = jest.fn().mockResolvedValue({ success: true }) - const registerMock = jest.fn() - const dispatchMock = jest.fn() - - bcscCoreMock.getAccount.mockResolvedValue({ clientID: 'test-client-id' } as any) - useApiMock.mockImplementation( - () => - ({ - registration: { - deleteRegistration: deleteRegistrationMock, - register: registerMock, - }, - } as any) - ) - bifoldMock.useStore.mockReturnValue([{} as any, dispatchMock]) - bifoldMock.useServices.mockReturnValue([{ info: jest.fn(), error: jest.fn() }] as any) - - const hook = renderHook(() => useFactoryReset()) - - await act(async () => { - const result = await hook.result.current() - expect(result.success).toBe(true) - }) - - expect(bcscCoreMock.getAccount).toHaveBeenCalledWith() - expect(deleteRegistrationMock).toHaveBeenCalledWith('test-client-id') - expect(bcscCoreMock.removeAccount).toHaveBeenCalledWith() - expect(dispatchMock.mock.calls[0]).toStrictEqual([{ type: BCDispatchAction.CLEAR_BCSC }]) - expect(registerMock).toHaveBeenCalledWith() - expect(dispatchMock.mock.calls[1]).toStrictEqual([{ type: DispatchAction.DID_AUTHENTICATE, payload: [false] }]) - }) - - it('should return an error if account is null', async () => { - const bcscCoreMock = jest.mocked(BcscCore) - const useApiMock = jest.mocked(useApi) - const bifoldMock = jest.mocked(Bifold) - - const deleteRegistrationMock = jest.fn() - - bcscCoreMock.getAccount.mockResolvedValue(null) - useApiMock.mockImplementation(() => ({ registration: { deleteRegistration: deleteRegistrationMock } } as any)) - bifoldMock.useStore.mockReturnValue([{} as any, jest.fn()]) - bifoldMock.useServices.mockReturnValue([{ info: jest.fn(), error: jest.fn() }] as any) - - const hook = renderHook(() => useFactoryReset()) - - await act(async () => { - const result = await hook.result.current() - if (result.success) { - expect(true).toBe(false) // Force fail if success is true - } else { - expect(result.success).toBe(false) - expect(result.error.message).toContain('Local account') - } - }) - - expect(bcscCoreMock.getAccount).toHaveBeenCalled() - expect(deleteRegistrationMock).not.toHaveBeenCalled() - }) - - it('should return an error if IAS account deletion fails', async () => { - const bcscCoreMock = jest.mocked(BcscCore) - const useApiMock = jest.mocked(useApi) - const bifoldMock = jest.mocked(Bifold) - - const deleteRegistrationMock = jest.fn().mockResolvedValue({ success: false }) - - bcscCoreMock.getAccount.mockResolvedValue({ clientID: 'test-client-id' } as any) - useApiMock.mockImplementation(() => ({ registration: { deleteRegistration: deleteRegistrationMock } } as any)) - bifoldMock.useStore.mockReturnValue([{} as any, jest.fn()]) - bifoldMock.useServices.mockReturnValue([{ info: jest.fn(), error: jest.fn() }] as any) - - const hook = renderHook(() => useFactoryReset()) - - await act(async () => { - const result = await hook.result.current() - if (result.success) { - expect(true).toBe(false) // Force fail if success is true - } else { - expect(result.success).toBe(false) - expect(result.error.message).toContain('IAS') - } - }) - - expect(bcscCoreMock.getAccount).toHaveBeenCalled() - expect(deleteRegistrationMock).toHaveBeenCalledWith('test-client-id') - }) - - it('should return an error if local account file deletion fails', async () => { - const bcscCoreMock = jest.mocked(BcscCore) - const useApiMock = jest.mocked(useApi) - const bifoldMock = jest.mocked(Bifold) - - const deleteRegistrationMock = jest.fn().mockResolvedValue({ success: true }) - - bcscCoreMock.getAccount.mockResolvedValue({ clientID: 'test-client-id' } as any) - bcscCoreMock.removeAccount.mockRejectedValue(new Error('Failed to remove account')) - useApiMock.mockImplementation(() => ({ registration: { deleteRegistration: deleteRegistrationMock } } as any)) - bifoldMock.useStore.mockReturnValue([{} as any, jest.fn()]) - bifoldMock.useServices.mockReturnValue([{ info: jest.fn(), error: jest.fn() }] as any) - - const hook = renderHook(() => useFactoryReset()) - - await act(async () => { - const result = await hook.result.current() - if (result.success) { - expect(true).toBe(false) // Force fail if success is true - } else { - expect(result.success).toBe(false) - expect(result.error.message).toContain('Failed to remove account') - } - }) - - expect(bcscCoreMock.getAccount).toHaveBeenCalled() - expect(deleteRegistrationMock).toHaveBeenCalledWith('test-client-id') - expect(bcscCoreMock.removeAccount).toHaveBeenCalled() - }) - - it('should return an error if re-registration fails', async () => { - const bcscCoreMock = jest.mocked(BcscCore) - const useApiMock = jest.mocked(useApi) - const bifoldMock = jest.mocked(Bifold) - - const deleteRegistrationMock = jest.fn().mockResolvedValue({ success: true }) - const registerMock = jest.fn().mockRejectedValue(new Error('Failed to register new account')) - - bcscCoreMock.getAccount.mockResolvedValue({ clientID: 'test-client-id' } as any) - useApiMock.mockImplementation( - () => - ({ - registration: { - deleteRegistration: deleteRegistrationMock, - register: registerMock, - }, - } as any) - ) - bifoldMock.useStore.mockReturnValue([{} as any, jest.fn()]) - bifoldMock.useServices.mockReturnValue([{ info: jest.fn(), error: jest.fn() }] as any) - - const hook = renderHook(() => useFactoryReset()) - - await act(async () => { - const result = await hook.result.current() - if (result.success) { - expect(true).toBe(false) // Force fail if success is true - } else { - expect(result.success).toBe(false) - expect(result.error.message).toContain('Failed to register') - } - }) - - expect(bcscCoreMock.getAccount).toHaveBeenCalled() - expect(deleteRegistrationMock).toHaveBeenCalledWith('test-client-id') - expect(bcscCoreMock.removeAccount).toHaveBeenCalled() - expect(registerMock).toHaveBeenCalled() - }) -}) diff --git a/app/__tests__/bcsc-theme/hooks/useFilterServiceClients.test.ts b/app/__tests__/bcsc-theme/hooks/useFilterServiceClients.test.ts deleted file mode 100644 index b6bf25b..0000000 --- a/app/__tests__/bcsc-theme/hooks/useFilterServiceClients.test.ts +++ /dev/null @@ -1,271 +0,0 @@ -import * as Bifold from '@bifold/core' -import { useFilterServiceClients } from '@/bcsc-theme/features/services/hooks/useFilterServiceClients' -import { renderHook, waitFor } from '@testing-library/react-native' -import * as useApi from '@/bcsc-theme/api/hooks/useApi' -import * as navigation from '@react-navigation/native' -import { ClientMetadata } from '@/bcsc-theme/api/hooks/useMetadataApi' -import { BCSCCardProcess } from '@/bcsc-theme/types/cards' - -jest.mock('@bifold/core') -jest.mock('@/bcsc-theme/api/hooks/useApi') -jest.mock('@react-navigation/native') - -const mockServiceClientA: ClientMetadata = { - client_ref_id: 'test-client-id-a', - client_name: 'TEST CLIENT ALPHA', - client_uri: 'https://test.client.a', - application_type: 'web', - claims_description: 'claims', - suppress_confirmation_info: false, - suppress_bookmark_prompt: false, - allowed_identification_processes: [BCSCCardProcess.BCSC], - bc_address: true, -} - -const mockServiceClientB: ClientMetadata = { - client_ref_id: 'test-client-id-b', - client_name: 'TEST CLIENT BETA', - client_uri: 'https://test.client.b', - application_type: 'web', - claims_description: 'claims', - suppress_confirmation_info: false, - suppress_bookmark_prompt: false, - allowed_identification_processes: [BCSCCardProcess.NonBCSC], - bc_address: false, -} - -describe('useFilterServiceClients', () => { - beforeEach(() => { - jest.resetAllMocks() - }) - - describe('no filters', () => { - it('should return all service clients when no filters are applied', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({})) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(2) - expect(hook.result.current[0].client_ref_id).toBe(mockServiceClientA.client_ref_id) - expect(hook.result.current[1].client_ref_id).toBe(mockServiceClientB.client_ref_id) - }) - }) - }) - - describe('card process filter', () => { - it('should filter out service clients by card process', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({ cardProcessFilter: BCSCCardProcess.BCSC })) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(1) - expect(hook.result.current[0].client_ref_id).toBe(mockServiceClientA.client_ref_id) - }) - }) - }) - - describe('BC address filter', () => { - it('should filter out non BC service clients', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({ requireBCAddressFilter: true })) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(1) - expect(hook.result.current[0].client_ref_id).toBe(mockServiceClientA.client_ref_id) - }) - }) - }) - - describe('partial name filter', () => { - it('should filter service clients by partial name match', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({ partialNameFilter: 'ALPHA' })) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(1) - expect(hook.result.current[0].client_ref_id).toBe(mockServiceClientA.client_ref_id) - }) - }) - - it('should filter service clients by partial name match (case insensitive)', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({ partialNameFilter: 'Alpha' })) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(1) - expect(hook.result.current[0].client_ref_id).toBe(mockServiceClientA.client_ref_id) - }) - }) - - it('should filter service clients by partial name match multiple words', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({ partialNameFilter: 'client alpha' })) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(1) - expect(hook.result.current[0].client_ref_id).toBe(mockServiceClientA.client_ref_id) - }) - }) - - it('should return no service clients when no match', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({ partialNameFilter: 'badbadbad' })) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(0) - }) - }) - - it('should return no service clients when partial name words are not contiguous', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useFilterServiceClients({ partialNameFilter: 'TEST ALPHA' })) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(0) - }) - }) - }) - - describe('combined filters', () => { - it('should filter service clients by multiple criteria', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => - useFilterServiceClients({ - cardProcessFilter: BCSCCardProcess.BCSC, - requireBCAddressFilter: true, - partialNameFilter: 'ALPHA', - }) - ) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(1) - expect(hook.result.current[0].client_ref_id).toBe(mockServiceClientA.client_ref_id) - }) - }) - - it('should filter service clients by multiple criteria and return zero when one filter misses', async () => { - const bifoldMock = jest.mocked(Bifold) - const useApiMock = jest.mocked(useApi) - const navigationMock = jest.mocked(navigation) - - useApiMock.default.mockReturnValue({ - metadata: { - getClientMetadata: jest.fn().mockResolvedValue([mockServiceClientA, mockServiceClientB]), - }, - } as any) - navigationMock.useNavigation.mockReturnValue({ navigation: jest.fn() }) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => - useFilterServiceClients({ - cardProcessFilter: BCSCCardProcess.NonBCSC, - requireBCAddressFilter: true, - partialNameFilter: 'ALPHA', - }) - ) - - await waitFor(() => { - expect(hook.result.current).toHaveLength(0) - }) - }) - }) -}) diff --git a/app/__tests__/bcsc-theme/hooks/useQuickLoginURL.test.ts b/app/__tests__/bcsc-theme/hooks/useQuickLoginURL.test.ts deleted file mode 100644 index a0aa692..0000000 --- a/app/__tests__/bcsc-theme/hooks/useQuickLoginURL.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import * as useApi from '@/bcsc-theme/api/hooks/useApi' -import * as useBCSCApiClient from '@/bcsc-theme/hooks/useBCSCApiClient' -import * as BcscCore from 'react-native-bcsc-core' -import * as tokens from '@/bcsc-theme/utils/push-notification-tokens' -import { useQuickLoginURL } from '@/bcsc-theme/hooks/useQuickLoginUrl' -import * as Bifold from '@bifold/core' -import { renderHook } from '@testing-library/react-native' - -jest.mock('@bifold/core') -jest.mock('@/bcsc-theme/api/hooks/useApi') -jest.mock('@/bcsc-theme/hooks/useBCSCApiClient') -jest.mock('@bcsc-theme/utils/push-notification-tokens') - -describe('useQuickLoginURL', () => { - beforeEach(() => { - jest.resetAllMocks() - }) - - it('should return error when no initiate login uri', async () => { - const useApiMock = jest.mocked(useApi) - const useClientMock = jest.mocked(useBCSCApiClient) - const bifoldMock = jest.mocked(Bifold) - - useApiMock.default.mockReturnValue({ jwks: { getFirstJwk: jest.fn() } } as any) - useClientMock.useBCSCApiClient.mockReturnValue({} as any) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useQuickLoginURL()) - const result = await hook.result.current({ client_ref_id: 'test' }) - - expect(result).toEqual({ success: false, error: expect.stringContaining('login unavailable') }) - }) - - it('should return error when no client access token', async () => { - const useApiMock = jest.mocked(useApi) - const useClientMock = jest.mocked(useBCSCApiClient) - const bifoldMock = jest.mocked(Bifold) - - useApiMock.default.mockReturnValue({ jwks: { getFirstJwk: jest.fn() } } as any) - useClientMock.useBCSCApiClient.mockReturnValue({} as any) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useQuickLoginURL()) - const result = await hook.result.current({ client_ref_id: 'test', initiate_login_uri: 'https://example.com' }) - - expect(result).toEqual({ success: false, error: expect.stringContaining('access token') }) - }) - - it('should return error when no notification tokens available', async () => { - const useApiMock = jest.mocked(useApi) - const useClientMock = jest.mocked(useBCSCApiClient) - const bifoldMock = jest.mocked(Bifold) - const bcscCoreMock = jest.mocked(BcscCore) - const tokensMock = jest.mocked(tokens) - - const getFirstJwkMock = jest.fn() - bcscCoreMock.getAccount = jest.fn() - tokensMock.getNotificationTokens = jest.fn() - - useApiMock.default.mockReturnValue({ jwks: { getFirstJwk: getFirstJwkMock } } as any) - useClientMock.useBCSCApiClient.mockReturnValue({ tokens: { access_token: true } } as any) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useQuickLoginURL()) - const result = await hook.result.current({ client_ref_id: 'test', initiate_login_uri: 'https://example.com' }) - - expect(result).toEqual({ success: false, error: expect.stringContaining('notification tokens') }) - - expect(tokensMock.getNotificationTokens).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.getAccount).toHaveBeenCalledTimes(1) - expect(getFirstJwkMock).toHaveBeenCalledTimes(1) - }) - - it('should return error when no account available', async () => { - const useApiMock = jest.mocked(useApi) - const useClientMock = jest.mocked(useBCSCApiClient) - const bifoldMock = jest.mocked(Bifold) - const bcscCoreMock = jest.mocked(BcscCore) - const tokensMock = jest.mocked(tokens) - - const getFirstJwkMock = jest.fn() - bcscCoreMock.getAccount = jest.fn() - tokensMock.getNotificationTokens = jest.fn().mockResolvedValue(true) - - useApiMock.default.mockReturnValue({ jwks: { getFirstJwk: getFirstJwkMock } } as any) - useClientMock.useBCSCApiClient.mockReturnValue({ tokens: { access_token: true } } as any) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useQuickLoginURL()) - const result = await hook.result.current({ client_ref_id: 'test', initiate_login_uri: 'https://example.com' }) - - expect(result).toEqual({ success: false, error: expect.stringContaining('account') }) - - expect(tokensMock.getNotificationTokens).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.getAccount).toHaveBeenCalledTimes(1) - expect(getFirstJwkMock).toHaveBeenCalledTimes(1) - }) - - it('should return error when no jwk available', async () => { - const useApiMock = jest.mocked(useApi) - const useClientMock = jest.mocked(useBCSCApiClient) - const bifoldMock = jest.mocked(Bifold) - const bcscCoreMock = jest.mocked(BcscCore) - const tokensMock = jest.mocked(tokens) - - const getFirstJwkMock = jest.fn() - bcscCoreMock.getAccount = jest.fn().mockResolvedValue(true) - tokensMock.getNotificationTokens = jest.fn().mockResolvedValue(true) - - useApiMock.default.mockReturnValue({ jwks: { getFirstJwk: getFirstJwkMock } } as any) - useClientMock.useBCSCApiClient.mockReturnValue({ tokens: { access_token: true } } as any) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useQuickLoginURL()) - const result = await hook.result.current({ client_ref_id: 'test', initiate_login_uri: 'https://example.com' }) - - expect(result).toEqual({ success: false, error: expect.stringContaining('JWK') }) - - expect(tokensMock.getNotificationTokens).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.getAccount).toHaveBeenCalledTimes(1) - expect(getFirstJwkMock).toHaveBeenCalledTimes(1) - }) - - it('should return error when failed to create quick login JWT', async () => { - const useApiMock = jest.mocked(useApi) - const useClientMock = jest.mocked(useBCSCApiClient) - const bifoldMock = jest.mocked(Bifold) - const bcscCoreMock = jest.mocked(BcscCore) - const tokensMock = jest.mocked(tokens) - - const getFirstJwkMock = jest.fn().mockResolvedValue(true) - bcscCoreMock.getAccount = jest.fn().mockResolvedValue(true) - tokensMock.getNotificationTokens = jest.fn().mockResolvedValue(true) - bcscCoreMock.createQuickLoginJWT = jest.fn().mockRejectedValue(new Error('failed jwt')) - - useApiMock.default.mockReturnValue({ jwks: { getFirstJwk: getFirstJwkMock } } as any) - useClientMock.useBCSCApiClient.mockReturnValue({ tokens: { access_token: true } } as any) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useQuickLoginURL()) - const result = await hook.result.current({ client_ref_id: 'test', initiate_login_uri: 'https://example.com' }) - - expect(result).toEqual({ success: false, error: expect.stringContaining('failed jwt') }) - - expect(tokensMock.getNotificationTokens).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.getAccount).toHaveBeenCalledTimes(1) - expect(getFirstJwkMock).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.createQuickLoginJWT).toHaveBeenCalledTimes(1) - }) - - it('should return the quick login URL', async () => { - const useApiMock = jest.mocked(useApi) - const useClientMock = jest.mocked(useBCSCApiClient) - const bifoldMock = jest.mocked(Bifold) - const bcscCoreMock = jest.mocked(BcscCore) - const tokensMock = jest.mocked(tokens) - - const getFirstJwkMock = jest.fn().mockResolvedValue('jwk') - bcscCoreMock.getAccount = jest.fn().mockResolvedValue({ clientID: 'client-id', issuer: 'issuer' } as any) - tokensMock.getNotificationTokens = jest.fn().mockResolvedValue({ fcmDeviceToken: 'fcm', apnsToken: 'apns' }) - bcscCoreMock.createQuickLoginJWT = jest.fn().mockResolvedValue('test-jwt') - - useApiMock.default.mockReturnValue({ jwks: { getFirstJwk: getFirstJwkMock } } as any) - useClientMock.useBCSCApiClient.mockReturnValue({ tokens: { access_token: 'access-token' } } as any) - bifoldMock.useServices.mockReturnValue([{ error: jest.fn() }] as any) - - const hook = renderHook(() => useQuickLoginURL()) - const result = await hook.result.current({ client_ref_id: 'test', initiate_login_uri: 'https://example.com' }) - - expect(result).toEqual({ success: true, url: `https://example.com?login_hint=${encodeURIComponent('test-jwt')}` }) - - expect(tokensMock.getNotificationTokens).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.getAccount).toHaveBeenCalledTimes(1) - expect(getFirstJwkMock).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.createQuickLoginJWT).toHaveBeenCalledTimes(1) - expect(bcscCoreMock.createQuickLoginJWT).toHaveBeenCalledWith( - 'access-token', - 'client-id', - 'issuer', - 'test', - 'jwk', - 'fcm', - 'apns' - ) - }) -}) diff --git a/app/__tests__/bcsc-theme/utils/address-utils.test.ts b/app/__tests__/bcsc-theme/utils/address-utils.test.ts deleted file mode 100644 index 713b0c5..0000000 --- a/app/__tests__/bcsc-theme/utils/address-utils.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { isCanadianPostalCode } from '@/bcsc-theme/utils/address-utils' - -describe('address-utils', () => { - describe('isCanadianPostalCode', () => { - it('should return true for valid postal codes', () => { - expect(isCanadianPostalCode('A1B 2C3')).toBeTruthy() - expect(isCanadianPostalCode('K1A 0B1')).toBeTruthy() - expect(isCanadianPostalCode('V6B 1A1')).toBeTruthy() - expect(isCanadianPostalCode('H2Y 1N4')).toBeTruthy() - expect(isCanadianPostalCode('T5J 1N9')).toBeTruthy() - expect(isCanadianPostalCode('R3C 4T3')).toBeTruthy() - expect(isCanadianPostalCode('S7K 3J8')).toBeTruthy() - expect(isCanadianPostalCode('Y1A 5B2')).toBeTruthy() - expect(isCanadianPostalCode('X1A 2P3')).toBeTruthy() - expect(isCanadianPostalCode('X0A 1H0')).toBeTruthy() - expect(isCanadianPostalCode('B2H 3K4')).toBeTruthy() - expect(isCanadianPostalCode('C1A 4N5')).toBeTruthy() - expect(isCanadianPostalCode('E3B 5L6')).toBeTruthy() - expect(isCanadianPostalCode('G1R 2X5')).toBeTruthy() - expect(isCanadianPostalCode('M5V 3L9')).toBeTruthy() - expect(isCanadianPostalCode('R2M 3S8')).toBeTruthy() - expect(isCanadianPostalCode('S4P 2K5')).toBeTruthy() - expect(isCanadianPostalCode('V5K 0A1')).toBeTruthy() - expect(isCanadianPostalCode('Y1A 0A8')).toBeTruthy() - expect(isCanadianPostalCode('X0B 1E0')).toBeTruthy() - expect(isCanadianPostalCode('V8Z 1C8')).toBeTruthy() - }) - - it('should return true for valid postal codes without spaces', () => { - expect(isCanadianPostalCode('A1B2C3')).toBeTruthy() - }) - - it('should return true for valid postal codes in lowercase', () => { - expect(isCanadianPostalCode('a1b 2c3')).toBeTruthy() - }) - - it('should return true for valid postal codes in lowercase without spaces', () => { - expect(isCanadianPostalCode('a1b2c3')).toBeTruthy() - }) - - it('should return true for valid postal codes with hyphens', () => { - expect(isCanadianPostalCode('A1B-2C3')).toBeTruthy() - }) - - it('should return true for valid postal codes with any combination of casing, spaces and hyphens', () => { - expect(isCanadianPostalCode('a1B-2c3')).toBeTruthy() - expect(isCanadianPostalCode('A1b-2C3')).toBeTruthy() - expect(isCanadianPostalCode('a1B 2c3')).toBeTruthy() - expect(isCanadianPostalCode('A1b 2C3')).toBeTruthy() - expect(isCanadianPostalCode('a1B2c3')).toBeTruthy() - expect(isCanadianPostalCode('A1b2C3')).toBeTruthy() - }) - - it('should return false for invalid postal codes', () => { - expect(isCanadianPostalCode('123 456')).toBeFalsy() - expect(isCanadianPostalCode('ABC DEF')).toBeFalsy() - expect(isCanadianPostalCode('A1B2C')).toBeFalsy() - expect(isCanadianPostalCode('A1B 2C34')).toBeFalsy() - expect(isCanadianPostalCode('A1B-2C34')).toBeFalsy() - expect(isCanadianPostalCode('A1B_2C3')).toBeFalsy() - expect(isCanadianPostalCode('A1 2C3')).toBeFalsy() - expect(isCanadianPostalCode('1A1 2C3')).toBeFalsy() - expect(isCanadianPostalCode('A11 2C3')).toBeFalsy() - expect(isCanadianPostalCode('A1A 22C3')).toBeFalsy() - expect(isCanadianPostalCode('A1A 2CC3')).toBeFalsy() - expect(isCanadianPostalCode('A1A2C3 ')).toBeFalsy() - expect(isCanadianPostalCode(' A1A2C3')).toBeFalsy() - expect(isCanadianPostalCode('')).toBeFalsy() - expect(isCanadianPostalCode(' ')).toBeFalsy() - expect(isCanadianPostalCode('A B C D E F')).toBeFalsy() - expect(isCanadianPostalCode('A-1B-2C-3')).toBeFalsy() - expect(isCanadianPostalCode('A_1B_2C_3')).toBeFalsy() - expect(isCanadianPostalCode('A1B@2C3')).toBeFalsy() - expect(isCanadianPostalCode('A1B#2C3')).toBeFalsy() - expect(isCanadianPostalCode('A1B$2C3')).toBeFalsy() - expect(isCanadianPostalCode('A1B%2C3')).toBeFalsy() - expect(isCanadianPostalCode('A1B^2C3')).toBeFalsy() - }) - }) -}) diff --git a/app/__tests__/bcsc-theme/utils/card-utils.test.ts b/app/__tests__/bcsc-theme/utils/card-utils.test.ts deleted file mode 100644 index 76c36bf..0000000 --- a/app/__tests__/bcsc-theme/utils/card-utils.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { BCSCCardProcess, BCSCCardType } from '@/bcsc-theme/types/cards' -import { getCardProcessForCardType } from '@/bcsc-theme/utils/card-utils' - -describe('Card Utils', () => { - describe('getCardProcessForCardType', () => { - it('should return BCSC for Combined card type', () => { - expect(getCardProcessForCardType(BCSCCardType.Combined)).toBe(BCSCCardProcess.BCSC) - }) - - it('should return BCSC for Photo card type', () => { - expect(getCardProcessForCardType(BCSCCardType.Photo)).toBe(BCSCCardProcess.BCSC) - }) - - it('should return BCSCNonPhoto for NonPhoto card type', () => { - expect(getCardProcessForCardType(BCSCCardType.NonPhoto)).toBe(BCSCCardProcess.BCSCNonPhoto) - }) - - it('should return NonBCSC for Other card type', () => { - expect(getCardProcessForCardType(BCSCCardType.Other)).toBe(BCSCCardProcess.NonBCSC) - }) - - it('should throw an error for None card type', () => { - expect(() => getCardProcessForCardType(BCSCCardType.None)).toThrow(`Invalid card type: ${BCSCCardType.None}}`) - }) - - it('should throw an error for unknown card type', () => { - expect(() => getCardProcessForCardType(99 as any)).toThrow('Unknown card type: 99') - }) - - it('should support all BCSCCardType values', () => { - const cardTypes = Object.values(BCSCCardType) - cardTypes.forEach((cardType) => { - if (cardType === BCSCCardType.None) { - expect(() => getCardProcessForCardType(cardType)).toThrow() - } else { - const process = getCardProcessForCardType(cardType) - expect(Object.values(BCSCCardProcess)).toContain(process) - } - }) - }) - }) -}) diff --git a/app/__tests__/components/AppBanner.test.tsx b/app/__tests__/components/AppBanner.test.tsx deleted file mode 100644 index 03b845f..0000000 --- a/app/__tests__/components/AppBanner.test.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react' -import { render, fireEvent } from '@testing-library/react-native' -import { AppBanner, AppBannerSection, AppBannerSectionProps } from '../../src/bcsc-theme/components/AppBanner' -import { testIdWithKey } from '@bifold/core' - -describe('AppBanner', () => { - it('renders correctly with multiple messages', () => { - const messages: AppBannerSectionProps[] = [ - { title: 'Error Message', type: 'error', dismissible: true }, - { title: 'Warning Message', type: 'warning', dismissible: false }, - ] - - const { getByText } = render() - - expect(getByText('Error Message')).toBeTruthy() - expect(getByText('Warning Message')).toBeTruthy() - }) - - it('dismisses a banner when dismissible and tapped', () => { - const messages: AppBannerSectionProps[] = [ - { title: 'Dismissible Message', type: 'info', dismissible: true }, - { title: 'Non dismissible Message', type: 'warning', dismissible: false }, - ] - - const { getByText, queryByText } = render() - - expect(getByText('Dismissible Message')).toBeTruthy() - - fireEvent.press(getByText('Dismissible Message')) - - expect(queryByText('Dismissible Message')).toBeFalsy() - expect(getByText('Non dismissible Message')).toBeTruthy() - }) - - it('does not dismiss a non-dismissible banner when tapped', () => { - const messages: AppBannerSectionProps[] = [ - { title: 'Non dismissible Message', type: 'warning', dismissible: false }, - ] - - const { getByText } = render() - - fireEvent.press(getByText('Non dismissible Message')) - - expect(getByText('Non dismissible Message')).toBeTruthy() - }) -}) - -describe('AppBannerSection', () => { - it('renders correctly with the correct icon and color for type', () => { - const { getByText, getByTestId } = render( - - ) - - expect(getByText('Success Message')).toBeTruthy() - expect(getByTestId(testIdWithKey('icon-success'))).toBeTruthy() - }) - - it('calls onDismiss when tapped and dismissible', () => { - const onDismissMock = jest.fn() - - const { getByText } = render( - - ) - - fireEvent.press(getByText('Dismissible Message')) - - expect(onDismissMock).toHaveBeenCalled() - }) - - it('does not call onDismiss when not dismissible', () => { - const onDismissMock = jest.fn() - - const { getByText } = render( - - ) - - fireEvent.press(getByText('Non-dismissible Message')) - - expect(onDismissMock).not.toHaveBeenCalled() - }) -}) diff --git a/app/__tests__/hooks/useSetupSteps.test.tsx b/app/__tests__/hooks/useSetupSteps.test.tsx deleted file mode 100644 index 6b4cbbf..0000000 --- a/app/__tests__/hooks/useSetupSteps.test.tsx +++ /dev/null @@ -1,308 +0,0 @@ -import { BCSCCardType } from '@/bcsc-theme/types/cards' -import { useSetupSteps } from '@/hooks/useSetupSteps' -import { initialState } from '@/store' -import { renderHook } from '@testing-library/react-native' -import lodash from 'lodash' - -describe('useSetupSteps Hook', () => { - describe('Init', () => { - it('all steps should not be focused and completed', () => { - // note: const store = { ...initialState } clones only top level, nested objects remain references - const store = lodash.cloneDeep(initialState) - - const { result: hook } = renderHook(() => useSetupSteps(store)) - - expect(hook.current.id.completed).toBe(false) - expect(hook.current.id.focused).toBe(true) - expect(hook.current.address.completed).toBe(false) - expect(hook.current.address.focused).toBe(false) - expect(hook.current.email.completed).toBe(false) - expect(hook.current.email.focused).toBe(false) - expect(hook.current.verify.completed).toBe(false) - expect(hook.current.verify.focused).toBe(false) - }) - }) - - describe('ID Step', () => { - it('Combo Card: should be completed when serial and email provided', () => { - const store = lodash.cloneDeep(initialState) - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.id.completed).toBe(false) - expect(hook.result.current.id.focused).toBe(true) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - - hook.rerender(store) - - expect(hook.result.current.id.completed).toBe(true) - expect(hook.result.current.id.focused).toBe(false) - }) - - it('Non-Photo Card: should be completed when serial, email, and photo ID provided', () => { - const store = lodash.cloneDeep(initialState) - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.id.completed).toBe(false) - expect(hook.result.current.id.focused).toBe(true) - expect(hook.result.current.id.nonPhotoBcscNeedsAdditionalCard).toBe(false) - - store.bcsc.cardType = BCSCCardType.NonPhoto - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - - hook.rerender(store) - - expect(hook.result.current.id.completed).toBe(false) - expect(hook.result.current.id.focused).toBe(true) - expect(hook.result.current.id.nonPhotoBcscNeedsAdditionalCard).toBe(true) - - store.bcsc.additionalEvidenceData = [ - { - evidenceType: { - has_photo: true, - }, - }, - ] as any[] - - hook.rerender(store) - - expect(hook.result.current.id.completed).toBe(true) - expect(hook.result.current.id.focused).toBe(false) - expect(hook.result.current.id.nonPhotoBcscNeedsAdditionalCard).toBe(false) - }) - - it('Non-BCSC Card: should be completed when 2 IDs provided', () => { - const store = lodash.cloneDeep(initialState) - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.id.completed).toBe(false) - expect(hook.result.current.id.focused).toBe(true) - expect(hook.result.current.id.nonBcscNeedsAdditionalCard).toBe(false) - - store.bcsc.cardType = BCSCCardType.Other - - hook.rerender(store) - - expect(hook.result.current.id.completed).toBe(false) - expect(hook.result.current.id.focused).toBe(true) - expect(hook.result.current.id.nonBcscNeedsAdditionalCard).toBe(false) - - store.bcsc.additionalEvidenceData = [ - { - evidenceType: { - has_photo: false, - }, - }, - ] as any[] - - hook.rerender(store) - - expect(hook.result.current.id.completed).toBe(false) - expect(hook.result.current.id.focused).toBe(true) - expect(hook.result.current.id.nonBcscNeedsAdditionalCard).toBe(true) - - store.bcsc.additionalEvidenceData = [ - { - evidenceType: { - has_photo: false, - }, - }, - { - evidenceType: { - has_photo: true, - }, - }, - ] as any[] - - hook.rerender(store) - - expect(hook.result.current.id.completed).toBe(true) - expect(hook.result.current.id.focused).toBe(false) - expect(hook.result.current.id.nonBcscNeedsAdditionalCard).toBe(false) - }) - }) - - describe('Residential Address Step', () => { - it('should be focused when ID step completed but address not yet completed', () => { - const store = lodash.cloneDeep(initialState) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - - const hook = renderHook(() => useSetupSteps(store)) - - // Address step should be focused - expect(hook.result.current.address.focused).toBe(true) - expect(hook.result.current.address.completed).toBe(false) - }) - - it('should be completed when device code is provided', () => { - const store = lodash.cloneDeep(initialState) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - store.bcsc.deviceCode = 'ABCDEFGH' - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.address.focused).toBe(false) - expect(hook.result.current.address.completed).toBe(true) - }) - }) - - describe('Email Step', () => { - it('should be focused when ID step completed, address step completed, but email not yet completed', () => { - const store = lodash.cloneDeep(initialState) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - store.bcsc.deviceCode = 'ABCDEFGH' - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.email.focused).toBe(true) - expect(hook.result.current.email.completed).toBe(false) - }) - - it('should be completed when email and emailConfirmed are provided', () => { - const store = lodash.cloneDeep(initialState) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - store.bcsc.deviceCode = 'ABCDEFGH' - store.bcsc.emailConfirmed = true - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.email.focused).toBe(false) - expect(hook.result.current.email.completed).toBe(true) - }) - }) - - describe('Verify Step', () => { - it('should be focused when ID step completed, address step completed, email step completed, but verify not yet completed', () => { - const store = lodash.cloneDeep(initialState) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - store.bcsc.deviceCode = 'ABCDEFGH' - store.bcsc.emailConfirmed = true - store.bcsc.verified = false - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.verify.focused).toBe(true) - expect(hook.result.current.verify.completed).toBe(false) - }) - - it('should be completed when verified is true', () => { - const store = lodash.cloneDeep(initialState) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - store.bcsc.deviceCode = 'ABCDEFGH' - store.bcsc.emailConfirmed = true - store.bcsc.verified = true - store.bcsc.pendingVerification = false - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.verify.focused).toBe(false) - expect(hook.result.current.verify.completed).toBe(true) - }) - - it('should be focused when pendingVerification is true', () => { - const store = lodash.cloneDeep(initialState) - - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - store.bcsc.deviceCode = 'ABCDEFGH' - store.bcsc.emailConfirmed = true - store.bcsc.verified = true - store.bcsc.pendingVerification = true - - const hook = renderHook(() => useSetupSteps(store)) - - expect(hook.result.current.verify.focused).toBe(true) - expect(hook.result.current.verify.completed).toBe(false) - }) - }) - - describe('Full workflow', () => { - it('should progress through all steps to completion', () => { - const store = lodash.cloneDeep(initialState) - - const hook = renderHook(() => useSetupSteps(store)) - - // Step 1: ID step should be focused - expect(hook.result.current.id.completed).toBe(false) - expect(hook.result.current.id.focused).toBe(true) - expect(hook.result.current.address.completed).toBe(false) - expect(hook.result.current.address.focused).toBe(false) - expect(hook.result.current.email.completed).toBe(false) - expect(hook.result.current.email.focused).toBe(false) - expect(hook.result.current.verify.completed).toBe(false) - expect(hook.result.current.verify.focused).toBe(false) - - // Complete Step 1 - store.bcsc.cardType = BCSCCardType.Combined - store.bcsc.serial = '123456789' - store.bcsc.email = 'steveBrule@email.com' - - hook.rerender(store) - - expect(hook.result.current.id.completed).toBe(true) - expect(hook.result.current.id.focused).toBe(false) - - // Step 2: Address step should be focused - expect(hook.result.current.address.completed).toBe(false) - expect(hook.result.current.address.focused).toBe(true) - - // Complete Step 2 - store.bcsc.deviceCode = 'ABCDEFGH' - - hook.rerender(store) - - expect(hook.result.current.address.completed).toBe(true) - expect(hook.result.current.address.focused).toBe(false) - - // Step 3: Email step should be focused - expect(hook.result.current.email.completed).toBe(false) - expect(hook.result.current.email.focused).toBe(true) - - // Complete Step 3 - store.bcsc.emailConfirmed = true - - hook.rerender(store) - - expect(hook.result.current.email.completed).toBe(true) - expect(hook.result.current.email.focused).toBe(false) - - // Step 4: Verify step should be focused - expect(hook.result.current.verify.completed).toBe(false) - expect(hook.result.current.verify.focused).toBe(true) - - // Complete Step 4 - store.bcsc.verified = true - store.bcsc.pendingVerification = false - - hook.rerender(store) - - expect(hook.result.current.verify.completed).toBe(true) - expect(hook.result.current.verify.focused).toBe(false) - }) - }) -}) diff --git a/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap b/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap index 89d2a7b..4df73c2 100644 --- a/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap +++ b/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap @@ -1323,194 +1323,6 @@ exports[`Developer Screen screen renders correctly 1`] = ` - - - - Developer.SwitchTheme - - - - - - - - - - Developer.SwitchMode - - - - - - ex.autolinkLibrariesFromCommand() } rootProject.name = 'KeyRing' -apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' includeBuild('../node_modules/@react-native/gradle-plugin') diff --git a/app/babel.config.js b/app/babel.config.js index 01c1231..5b6cac5 100644 --- a/app/babel.config.js +++ b/app/babel.config.js @@ -9,7 +9,6 @@ const plugins = [ '@': './src', '@assets': './src/assets', '@keyring-theme': './src/keyring-theme', - '@bcsc-theme': './src/bcsc-theme', '@components': './src/components', '@events': './src/events', '@hooks': './src/hooks', diff --git a/app/container-imp.ts b/app/container-imp.ts index 746888a..7fcf388 100644 --- a/app/container-imp.ts +++ b/app/container-imp.ts @@ -28,7 +28,6 @@ import { BrandingOverlayType, RemoteOCABundleResolver } from '@bifold/oca/build/ import { getProofRequestTemplates } from '@bifold/verifier' // import { Agent } from '@credo-ts/core' // DISABLED: Only used by push notifications import { NavigationProp } from '@react-navigation/native' -import moment from 'moment' import { TFunction } from 'react-i18next' // import { Linking } from 'react-native' import { Config } from 'react-native-config' @@ -68,11 +67,9 @@ import { VersionCheckService } from './src/services/version' import { BCDispatchAction, BCLocalStorageKeys, - BCSCState, BCState, DismissPersonCredentialOffer, IASEnvironment, - Mode, RemoteDebuggingState, initialState, } from './src/store' @@ -341,8 +338,6 @@ export class AppContainer implements Container { let onboarding = initialState.onboarding let personCredOfferDissmissed = initialState.dismissPersonCredentialOffer let { environment, remoteDebugging, enableProxy, enableAppToAppPersonFlow } = initialState.developer - let bcsc = initialState.bcsc - let mode = initialState.mode let witness = initialState.witness await Promise.all([ @@ -363,36 +358,12 @@ export class AppContainer implements Container { loadState(BCLocalStorageKeys.RemoteDebugging, (val) => (remoteDebugging = val)), loadState(BCLocalStorageKeys.EnableProxy, (val) => (enableProxy = val)), loadState(BCLocalStorageKeys.EnableAppToAppPersonFlow, (val) => (enableAppToAppPersonFlow = val)), - loadState(BCLocalStorageKeys.BCSC, (val) => (bcsc = val)), - loadState(BCLocalStorageKeys.Mode, (val) => (mode = val)), loadState(LocalStorageKeys.WitnessSettings, (val) => { // console.log('[DEBUG] Loaded WitnessSettings from storage:', JSON.stringify(val)) witness = val }), ]) - // Convert date string to Date object (async-storage converts Dates to strings) - // timezone-safe parsing to prevent off-by-one date errors (consistent with date picker) - if (typeof bcsc.birthdate === 'string') { - const momentDate = moment(bcsc.birthdate) - const year = momentDate.year() - const month = momentDate.month() - const day = momentDate.date() - bcsc.birthdate = new Date(year, month, day, 12, 0, 0, 0) - } - - if (typeof bcsc.deviceCodeExpiresAt === 'string') { - bcsc.deviceCodeExpiresAt = new Date(Date.parse(bcsc.deviceCodeExpiresAt)) - } - - // Reset paths and prompts on load as they should not be persisted - bcsc.photoPath = undefined - bcsc.videoPath = undefined - bcsc.videoThumbnailPath = undefined - bcsc.prompts = undefined - bcsc.photoMetadata = undefined - bcsc.videoMetadata = undefined - const state = { loginAttempt: { ...initialState.loginAttempt, ...loginAttempt }, preferences: { ...initialState.preferences, ...preferences }, @@ -410,8 +381,6 @@ export class AppContainer implements Container { enableProxy, enableAppToAppPersonFlow, }, - bcsc: { ...initialState.bcsc, ...bcsc }, - mode, witness: { ...initialState.witness, ...witness }, } as BCState diff --git a/app/index.js b/app/index.js index d2ba6d4..8af22e8 100644 --- a/app/index.js +++ b/app/index.js @@ -129,8 +129,13 @@ if (!global.atob) { global.atob = decode } -// Register the app -const { AppRegistry } = require('react-native') +// Dev-only: silence the LogBox toast for known-noisy warnings (indy ledger DID +// cache warm-up times out on test networks; the toast overlays the UI and breaks +// E2E taps). Errors still land in the metro console. +const { AppRegistry, LogBox } = require('react-native') +if (global.__DEV__) { + LogBox.ignoreLogs([/IndyVdrError/, /Possible unhandled promise rejection/]) +} const App = require('./App').default const { name: appName } = require('./app.json') diff --git a/app/ios/AriesBifold.xcodeproj/project.pbxproj b/app/ios/AriesBifold.xcodeproj/project.pbxproj index ba2e375..f448916 100644 --- a/app/ios/AriesBifold.xcodeproj/project.pbxproj +++ b/app/ios/AriesBifold.xcodeproj/project.pbxproj @@ -351,14 +351,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold-AriesBifoldTests/Pods-AriesBifold-AriesBifoldTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold-AriesBifoldTests/Pods-AriesBifold-AriesBifoldTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AriesBifold-AriesBifoldTests/Pods-AriesBifold-AriesBifoldTests-frameworks.sh\"\n"; @@ -372,14 +368,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold-AriesBifoldTests/Pods-AriesBifold-AriesBifoldTests-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold-AriesBifoldTests/Pods-AriesBifold-AriesBifoldTests-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AriesBifold-AriesBifoldTests/Pods-AriesBifold-AriesBifoldTests-resources.sh\"\n"; @@ -393,14 +385,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold/Pods-AriesBifold-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold/Pods-AriesBifold-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AriesBifold/Pods-AriesBifold-frameworks.sh\"\n"; @@ -436,14 +424,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold/Pods-AriesBifold-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-AriesBifold/Pods-AriesBifold-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AriesBifold/Pods-AriesBifold-resources.sh\"\n"; @@ -458,11 +442,9 @@ "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", ); name = "[CP-User] [RNFB] Core Configuration"; - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##########################################################################\n##########################################################################\n#\n# NOTE THAT IF YOU CHANGE THIS FILE YOU MUST RUN pod install AFTERWARDS\n#\n# This file is installed as an Xcode build script in the project file\n# by cocoapods, and you will not see your changes until you pod install\n#\n##########################################################################\n##########################################################################\n\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; }; D19D45CA82EB16EA5021312D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -547,7 +529,7 @@ "$(inherited)", ); INFOPLIST_FILE = AriesBifoldTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -572,7 +554,7 @@ COPY_PHASE_STRIP = NO; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = AriesBifoldTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -722,7 +704,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -739,6 +721,7 @@ OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; USE_HERMES = true; }; name = Debug; @@ -789,7 +772,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", diff --git a/app/ios/AriesBifold/AppDelegate.mm b/app/ios/AriesBifold/AppDelegate.mm index 17bc4d6..b276e45 100644 --- a/app/ios/AriesBifold/AppDelegate.mm +++ b/app/ios/AriesBifold/AppDelegate.mm @@ -2,6 +2,7 @@ #import #import +#import #import #import #import @@ -17,6 +18,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [FIRApp configure]; self.moduleName = @"KeyRing"; + // RN 0.77+: third-party Fabric components/modules are resolved through this provider + self.dependencyProvider = [RCTAppDependencyProvider new]; // You can add your custom initial props in the dictionary below. // They will be passed down to the ViewController used by React Native. self.initialProps = @{}; @@ -30,10 +33,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { - return [self getBundleURL]; + return [self bundleURL]; } -- (NSURL *)getBundleURL +// RN 0.74+ RCTAppDelegate calls -bundleURL (sourceURLForBridge: kept for compat) +- (NSURL *)bundleURL { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; diff --git a/app/ios/Podfile b/app/ios/Podfile index 5a74709..17a09ec 100644 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -1,6 +1,9 @@ source 'https://cdn.cocoapods.org' require_relative '../node_modules/react-native/scripts/react_native_pods' +# prevents location usage from react-native-vision-camera (matches upstream bc-wallet) +$VCEnableLocation = false + # From RNP docs here: https://www.npmjs.com/package/react-native-permissions/v/4.0.1 def node_require(script) # Resolve script with node to allow for hoisting @@ -41,17 +44,6 @@ setup_permissions([ # 'StoreKit', ]) -# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. -# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded -# -# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` -# ```js -# module.exports = { -# dependencies: { -# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), -# ``` -flipper_config = FlipperConfiguration.disabled - linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 3be8538..7b969e6 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -7,467 +7,652 @@ PODS: - React - React-callinvoker - React-Core - - BcscCore (0.1.0-alpha.1): - - glog - - RCT-Folly (= 2022.05.16.00) - - React-Core - - boost (1.83.0) + - boost (1.84.0) - BVLinearGradient (2.8.3): - React-Core - CatCrypto (0.3.2) - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - - FBLazyVector (0.73.11) - - FBReactNativeSpec (0.73.11): - - RCT-Folly (= 2022.05.16.00) - - RCTRequired (= 0.73.11) - - RCTTypeSafety (= 0.73.11) - - React-Core (= 0.73.11) - - React-jsi (= 0.73.11) - - ReactCommon/turbomodule/core (= 0.73.11) - - Firebase (8.15.0): - - Firebase/Core (= 8.15.0) - - Firebase/Core (8.15.0): + - fast_float (6.1.4) + - FBLazyVector (0.77.3) + - Firebase (11.11.0): + - Firebase/Core (= 11.11.0) + - Firebase/Core (11.11.0): - Firebase/CoreOnly - - FirebaseAnalytics (~> 8.15.0) - - Firebase/CoreOnly (8.15.0): - - FirebaseCore (= 8.15.0) - - Firebase/Messaging (8.15.0): + - FirebaseAnalytics (~> 11.11.0) + - Firebase/CoreOnly (11.11.0): + - FirebaseCore (~> 11.11.0) + - Firebase/Messaging (11.11.0): - Firebase/CoreOnly - - FirebaseMessaging (~> 8.15.0) - - FirebaseAnalytics (8.15.0): - - FirebaseAnalytics/AdIdSupport (= 8.15.0) - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) - - GoogleUtilities/Network (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - nanopb (~> 2.30908.0) - - FirebaseAnalytics/AdIdSupport (8.15.0): - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleAppMeasurement (= 8.15.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) - - GoogleUtilities/Network (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - nanopb (~> 2.30908.0) - - FirebaseCore (8.15.0): - - FirebaseCoreDiagnostics (~> 8.0) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Logger (~> 7.7) - - FirebaseCoreDiagnostics (8.15.0): - - GoogleDataTransport (~> 9.1) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Logger (~> 7.7) - - nanopb (~> 2.30908.0) - - FirebaseCoreInternal (10.29.0): - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseInstallations (8.15.0): - - FirebaseCore (~> 8.0) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/UserDefaults (~> 7.7) - - PromisesObjC (< 3.0, >= 1.2) - - FirebaseMessaging (8.15.0): - - FirebaseCore (~> 8.0) - - FirebaseInstallations (~> 8.0) - - GoogleDataTransport (~> 9.1) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Reachability (~> 7.7) - - GoogleUtilities/UserDefaults (~> 7.7) - - nanopb (~> 2.30908.0) - - fmt (6.2.1) + - FirebaseMessaging (~> 11.11.0) + - FirebaseAnalytics (11.11.0): + - FirebaseAnalytics/AdIdSupport (= 11.11.0) + - FirebaseCore (~> 11.11.0) + - FirebaseInstallations (~> 11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/MethodSwizzler (~> 8.0) + - GoogleUtilities/Network (~> 8.0) + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - nanopb (~> 3.30910.0) + - FirebaseAnalytics/AdIdSupport (11.11.0): + - FirebaseCore (~> 11.11.0) + - FirebaseInstallations (~> 11.0) + - GoogleAppMeasurement (= 11.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/MethodSwizzler (~> 8.0) + - GoogleUtilities/Network (~> 8.0) + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - nanopb (~> 3.30910.0) + - FirebaseCore (11.11.0): + - FirebaseCoreInternal (~> 11.11.0) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/Logger (~> 8.0) + - FirebaseCoreExtension (11.11.0): + - FirebaseCore (~> 11.11.0) + - FirebaseCoreInternal (11.11.0): + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - FirebaseInstallations (11.11.0): + - FirebaseCore (~> 11.11.0) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/UserDefaults (~> 8.0) + - PromisesObjC (~> 2.4) + - FirebaseMessaging (11.11.0): + - FirebaseCore (~> 11.11.0) + - FirebaseInstallations (~> 11.0) + - GoogleDataTransport (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/Reachability (~> 8.0) + - GoogleUtilities/UserDefaults (~> 8.0) + - nanopb (~> 3.30910.0) + - fmt (11.0.2) - glog (0.3.5) - - GoogleAppMeasurement (8.15.0): - - GoogleAppMeasurement/AdIdSupport (= 8.15.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) - - GoogleUtilities/Network (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.15.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.15.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) - - GoogleUtilities/Network (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.15.0): - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) - - GoogleUtilities/Network (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - nanopb (~> 2.30908.0) - - GoogleDataTransport (9.4.1): - - GoogleUtilities/Environment (~> 7.7) - - nanopb (< 2.30911.0, >= 2.30908.0) - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities (7.13.3): - - GoogleUtilities/AppDelegateSwizzler (= 7.13.3) - - GoogleUtilities/Environment (= 7.13.3) - - GoogleUtilities/ISASwizzler (= 7.13.3) - - GoogleUtilities/Logger (= 7.13.3) - - GoogleUtilities/MethodSwizzler (= 7.13.3) - - GoogleUtilities/Network (= 7.13.3) - - "GoogleUtilities/NSData+zlib (= 7.13.3)" - - GoogleUtilities/Privacy (= 7.13.3) - - GoogleUtilities/Reachability (= 7.13.3) - - GoogleUtilities/SwizzlerTestHelpers (= 7.13.3) - - GoogleUtilities/UserDefaults (= 7.13.3) - - GoogleUtilities/AppDelegateSwizzler (7.13.3): + - GoogleAppMeasurement (11.11.0): + - GoogleAppMeasurement/AdIdSupport (= 11.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/MethodSwizzler (~> 8.0) + - GoogleUtilities/Network (~> 8.0) + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/AdIdSupport (11.11.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 11.11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/MethodSwizzler (~> 8.0) + - GoogleUtilities/Network (~> 8.0) + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/WithoutAdIdSupport (11.11.0): + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/MethodSwizzler (~> 8.0) + - GoogleUtilities/Network (~> 8.0) + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - nanopb (~> 3.30910.0) + - GoogleDataTransport (10.1.0): + - nanopb (~> 3.30910.0) + - PromisesObjC (~> 2.4) + - GoogleUtilities (8.1.2): + - GoogleUtilities/AppDelegateSwizzler (= 8.1.2) + - GoogleUtilities/Environment (= 8.1.2) + - GoogleUtilities/Logger (= 8.1.2) + - GoogleUtilities/MethodSwizzler (= 8.1.2) + - GoogleUtilities/Network (= 8.1.2) + - "GoogleUtilities/NSData+zlib (= 8.1.2)" + - GoogleUtilities/Privacy (= 8.1.2) + - GoogleUtilities/Reachability (= 8.1.2) + - GoogleUtilities/SwizzlerTestHelpers (= 8.1.2) + - GoogleUtilities/UserDefaults (= 8.1.2) + - GoogleUtilities/AppDelegateSwizzler (8.1.2): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - GoogleUtilities/Privacy - - GoogleUtilities/Environment (7.13.3): + - GoogleUtilities/Environment (8.1.2): - GoogleUtilities/Privacy - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/ISASwizzler (7.13.3): - - GoogleUtilities/Privacy - - GoogleUtilities/Logger (7.13.3): + - GoogleUtilities/Logger (8.1.2): - GoogleUtilities/Environment - GoogleUtilities/Privacy - - GoogleUtilities/MethodSwizzler (7.13.3): + - GoogleUtilities/MethodSwizzler (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - GoogleUtilities/Network (7.13.3): + - GoogleUtilities/Network (8.1.2): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Privacy - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.13.3)": + - "GoogleUtilities/NSData+zlib (8.1.2)": - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (7.13.3) - - GoogleUtilities/Reachability (7.13.3): + - GoogleUtilities/Privacy (8.1.2) + - GoogleUtilities/Reachability (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - GoogleUtilities/SwizzlerTestHelpers (7.13.3): + - GoogleUtilities/SwizzlerTestHelpers (8.1.2): - GoogleUtilities/MethodSwizzler - - GoogleUtilities/UserDefaults (7.13.3): + - GoogleUtilities/UserDefaults (8.1.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - - hermes-engine (0.73.11): - - hermes-engine/Pre-built (= 0.73.11) - - hermes-engine/Pre-built (0.73.11) + - hermes-engine (0.77.3): + - hermes-engine/Pre-built (= 0.77.3) + - hermes-engine/Pre-built (0.77.3) - indy-vdr (0.2.2): - React - React-callinvoker - React-Core - JitsiWebRTC (124.0.2) - - libevent (2.1.12) - Mute (0.6.1) - - nanopb (2.30908.0): - - nanopb/decode (= 2.30908.0) - - nanopb/encode (= 2.30908.0) - - nanopb/decode (2.30908.0) - - nanopb/encode (2.30908.0) - - PromisesObjC (2.4.0) - - RCT-Folly (2022.05.16.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - RCT-Folly/Default (= 2022.05.16.00) - - RCT-Folly/Default (2022.05.16.00): + - nanopb (3.30910.0): + - nanopb/decode (= 3.30910.0) + - nanopb/encode (= 3.30910.0) + - nanopb/decode (3.30910.0) + - nanopb/encode (3.30910.0) + - PromisesObjC (2.4.1) + - RCT-Folly (2024.11.18.00): - boost - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - - RCT-Folly/Fabric (2022.05.16.00): + - RCT-Folly/Default (= 2024.11.18.00) + - RCT-Folly/Default (2024.11.18.00): - boost - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - - RCT-Folly/Futures (2022.05.16.00): + - RCT-Folly/Fabric (2024.11.18.00): - boost - DoubleConversion - - fmt (~> 6.2.1) - - glog - - libevent - - RCTRequired (0.73.11) - - RCTTypeSafety (0.73.11): - - FBLazyVector (= 0.73.11) - - RCTRequired (= 0.73.11) - - React-Core (= 0.73.11) - - React (0.73.11): - - React-Core (= 0.73.11) - - React-Core/DevSupport (= 0.73.11) - - React-Core/RCTWebSocket (= 0.73.11) - - React-RCTActionSheet (= 0.73.11) - - React-RCTAnimation (= 0.73.11) - - React-RCTBlob (= 0.73.11) - - React-RCTImage (= 0.73.11) - - React-RCTLinking (= 0.73.11) - - React-RCTNetwork (= 0.73.11) - - React-RCTSettings (= 0.73.11) - - React-RCTText (= 0.73.11) - - React-RCTVibration (= 0.73.11) - - React-callinvoker (0.73.11) - - React-Codegen (0.73.11): - - DoubleConversion - - FBReactNativeSpec - - glog - - hermes-engine - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - React-jsi - - React-jsiexecutor - - React-NativeModulesApple - - React-rncore - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - React-Core (0.73.11): + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - RCTDeprecation (0.77.3) + - RCTRequired (0.77.3) + - RCTTypeSafety (0.77.3): + - FBLazyVector (= 0.77.3) + - RCTRequired (= 0.77.3) + - React-Core (= 0.77.3) + - React (0.77.3): + - React-Core (= 0.77.3) + - React-Core/DevSupport (= 0.77.3) + - React-Core/RCTWebSocket (= 0.77.3) + - React-RCTActionSheet (= 0.77.3) + - React-RCTAnimation (= 0.77.3) + - React-RCTBlob (= 0.77.3) + - React-RCTImage (= 0.77.3) + - React-RCTLinking (= 0.77.3) + - React-RCTNetwork (= 0.77.3) + - React-RCTSettings (= 0.77.3) + - React-RCTText (= 0.77.3) + - React-RCTVibration (= 0.77.3) + - React-callinvoker (0.77.3) + - React-Core (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-Core/Default (= 0.73.11) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default (= 0.77.3) - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/CoreModulesHeaders (0.73.11): + - React-Core/CoreModulesHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/Default (0.73.11): + - React-Core/Default (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/DevSupport (0.73.11): + - React-Core/DevSupport (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-Core/Default (= 0.73.11) - - React-Core/RCTWebSocket (= 0.73.11) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default (= 0.77.3) + - React-Core/RCTWebSocket (= 0.77.3) - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor - - React-jsinspector (= 0.73.11) + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTActionSheetHeaders (0.73.11): + - React-Core/RCTActionSheetHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTAnimationHeaders (0.73.11): + - React-Core/RCTAnimationHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTBlobHeaders (0.73.11): + - React-Core/RCTBlobHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTImageHeaders (0.73.11): + - React-Core/RCTImageHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTLinkingHeaders (0.73.11): + - React-Core/RCTLinkingHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTNetworkHeaders (0.73.11): + - React-Core/RCTNetworkHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTSettingsHeaders (0.73.11): + - React-Core/RCTSettingsHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTTextHeaders (0.73.11): + - React-Core/RCTTextHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTVibrationHeaders (0.73.11): + - React-Core/RCTVibrationHeaders (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation - React-Core/Default - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-Core/RCTWebSocket (0.73.11): + - React-Core/RCTWebSocket (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-Core/Default (= 0.73.11) + - RCT-Folly (= 2024.11.18.00) + - RCTDeprecation + - React-Core/Default (= 0.77.3) - React-cxxreact + - React-featureflags - React-hermes - React-jsi - React-jsiexecutor + - React-jsinspector - React-perflogger - React-runtimescheduler - React-utils - - SocketRocket (= 0.6.1) + - SocketRocket (= 0.7.1) - Yoga - - React-CoreModules (0.73.11): - - RCT-Folly (= 2022.05.16.00) - - RCTTypeSafety (= 0.73.11) - - React-Codegen - - React-Core/CoreModulesHeaders (= 0.73.11) - - React-jsi (= 0.73.11) + - React-CoreModules (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - RCT-Folly (= 2024.11.18.00) + - RCTTypeSafety (= 0.77.3) + - React-Core/CoreModulesHeaders (= 0.77.3) + - React-jsi (= 0.77.3) + - React-jsinspector - React-NativeModulesApple - React-RCTBlob - - React-RCTImage (= 0.73.11) + - React-RCTFBReactNativeSpec + - React-RCTImage (= 0.77.3) - ReactCommon - - SocketRocket (= 0.6.1) - - React-cxxreact (0.73.11): - - boost (= 1.83.0) + - SocketRocket (= 0.7.1) + - React-cxxreact (0.77.3): + - boost + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.3) + - React-debug (= 0.77.3) + - React-jsi (= 0.77.3) + - React-jsinspector + - React-logger (= 0.77.3) + - React-perflogger (= 0.77.3) + - React-runtimeexecutor (= 0.77.3) + - React-timing (= 0.77.3) + - React-debug (0.77.3) + - React-defaultsnativemodule (0.77.3): + - hermes-engine + - RCT-Folly + - React-domnativemodule + - React-featureflagsnativemodule + - React-idlecallbacksnativemodule + - React-jsi + - React-jsiexecutor + - React-microtasksnativemodule + - React-RCTFBReactNativeSpec + - React-domnativemodule (0.77.3): + - hermes-engine + - RCT-Folly + - React-Fabric + - React-FabricComponents + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - Yoga + - React-Fabric (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/animations (= 0.77.3) + - React-Fabric/attributedstring (= 0.77.3) + - React-Fabric/componentregistry (= 0.77.3) + - React-Fabric/componentregistrynative (= 0.77.3) + - React-Fabric/components (= 0.77.3) + - React-Fabric/core (= 0.77.3) + - React-Fabric/dom (= 0.77.3) + - React-Fabric/imagemanager (= 0.77.3) + - React-Fabric/leakchecker (= 0.77.3) + - React-Fabric/mounting (= 0.77.3) + - React-Fabric/observers (= 0.77.3) + - React-Fabric/scheduler (= 0.77.3) + - React-Fabric/telemetry (= 0.77.3) + - React-Fabric/templateprocessor (= 0.77.3) + - React-Fabric/uimanager (= 0.77.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/animations (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/attributedstring (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/componentregistry (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/componentregistrynative (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/components/legacyviewmanagerinterop (= 0.77.3) + - React-Fabric/components/root (= 0.77.3) + - React-Fabric/components/view (= 0.77.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/legacyviewmanagerinterop (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-callinvoker (= 0.73.11) - - React-debug (= 0.73.11) - - React-jsi (= 0.73.11) - - React-jsinspector (= 0.73.11) - - React-logger (= 0.73.11) - - React-perflogger (= 0.73.11) - - React-runtimeexecutor (= 0.73.11) - - React-debug (0.73.11) - - React-Fabric (0.73.11): + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/root (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug - - React-Fabric/animations (= 0.73.11) - - React-Fabric/attributedstring (= 0.73.11) - - React-Fabric/componentregistry (= 0.73.11) - - React-Fabric/componentregistrynative (= 0.73.11) - - React-Fabric/components (= 0.73.11) - - React-Fabric/core (= 0.73.11) - - React-Fabric/imagemanager (= 0.73.11) - - React-Fabric/leakchecker (= 0.73.11) - - React-Fabric/mounting (= 0.73.11) - - React-Fabric/scheduler (= 0.73.11) - - React-Fabric/telemetry (= 0.73.11) - - React-Fabric/templateprocessor (= 0.73.11) - - React-Fabric/textlayoutmanager (= 0.73.11) - - React-Fabric/uimanager (= 0.73.11) + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -476,17 +661,19 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/animations (0.73.11): + - React-Fabric/components/view (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -495,17 +682,20 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/attributedstring (0.73.11): + - Yoga + - React-Fabric/core (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -514,17 +704,19 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/componentregistry (0.73.11): + - React-Fabric/dom (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -533,17 +725,19 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/componentregistrynative (0.73.11): + - React-Fabric/imagemanager (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -552,28 +746,19 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components (0.73.11): + - React-Fabric/leakchecker (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug - - React-Fabric/components/inputaccessory (= 0.73.11) - - React-Fabric/components/legacyviewmanagerinterop (= 0.73.11) - - React-Fabric/components/modal (= 0.73.11) - - React-Fabric/components/rncore (= 0.73.11) - - React-Fabric/components/root (= 0.73.11) - - React-Fabric/components/safeareaview (= 0.73.11) - - React-Fabric/components/scrollview (= 0.73.11) - - React-Fabric/components/text (= 0.73.11) - - React-Fabric/components/textinput (= 0.73.11) - - React-Fabric/components/unimplementedview (= 0.73.11) - - React-Fabric/components/view (= 0.73.11) + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -582,17 +767,19 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/inputaccessory (0.73.11): + - React-Fabric/mounting (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -601,17 +788,20 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/legacyviewmanagerinterop (0.73.11): + - React-Fabric/observers (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric/observers/events (= 0.77.3) + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -620,17 +810,19 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/modal (0.73.11): + - React-Fabric/observers/events (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -639,36 +831,42 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/rncore (0.73.11): + - React-Fabric/scheduler (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric/observers/events + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger + - React-performancetimeline - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/root (0.73.11): + - React-Fabric/telemetry (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -677,17 +875,19 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/safeareaview (0.73.11): + - React-Fabric/templateprocessor (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -696,55 +896,67 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/scrollview (0.73.11): + - React-Fabric/uimanager (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric/uimanager/consistency (= 0.77.3) + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger + - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/text (0.73.11): + - React-Fabric/uimanager/consistency (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger + - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/textinput (0.73.11): + - React-FabricComponents (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-FabricComponents/components (= 0.77.3) + - React-FabricComponents/textlayoutmanager (= 0.77.3) + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -753,17 +965,30 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/unimplementedview (0.73.11): + - Yoga + - React-FabricComponents/components (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-FabricComponents/components/inputaccessory (= 0.77.3) + - React-FabricComponents/components/iostextinput (= 0.77.3) + - React-FabricComponents/components/modal (= 0.77.3) + - React-FabricComponents/components/rncore (= 0.77.3) + - React-FabricComponents/components/safeareaview (= 0.77.3) + - React-FabricComponents/components/scrollview (= 0.77.3) + - React-FabricComponents/components/text (= 0.77.3) + - React-FabricComponents/components/textinput (= 0.77.3) + - React-FabricComponents/components/unimplementedview (= 0.77.3) + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -772,17 +997,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/view (0.73.11): + - Yoga + - React-FabricComponents/components/inputaccessory (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -792,17 +1021,20 @@ PODS: - React-utils - ReactCommon/turbomodule/core - Yoga - - React-Fabric/core (0.73.11): + - React-FabricComponents/components/iostextinput (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -811,17 +1043,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/imagemanager (0.73.11): + - Yoga + - React-FabricComponents/components/modal (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -830,17 +1066,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/leakchecker (0.73.11): + - Yoga + - React-FabricComponents/components/rncore (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -849,17 +1089,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/mounting (0.73.11): + - Yoga + - React-FabricComponents/components/safeareaview (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -868,17 +1112,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/scheduler (0.73.11): + - Yoga + - React-FabricComponents/components/scrollview (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -887,17 +1135,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/telemetry (0.73.11): + - Yoga + - React-FabricComponents/components/text (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -906,17 +1158,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/templateprocessor (0.73.11): + - Yoga + - React-FabricComponents/components/textinput (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -925,18 +1181,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/textlayoutmanager (0.73.11): + - Yoga + - React-FabricComponents/components/unimplementedview (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug - - React-Fabric/uimanager + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -945,17 +1204,21 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/uimanager (0.73.11): + - Yoga + - React-FabricComponents/textlayoutmanager (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-featureflags - React-graphics - React-jsi - React-jsiexecutor @@ -964,42 +1227,67 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-FabricImage (0.73.11): + - Yoga + - React-FabricImage (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) - - RCTRequired (= 0.73.11) - - RCTTypeSafety (= 0.73.11) + - RCT-Folly/Fabric (= 2024.11.18.00) + - RCTRequired (= 0.77.3) + - RCTTypeSafety (= 0.77.3) - React-Fabric + - React-featureflags - React-graphics - React-ImageManager - React-jsi - - React-jsiexecutor (= 0.73.11) + - React-jsiexecutor (= 0.77.3) - React-logger - React-rendererdebug - React-utils - ReactCommon - Yoga - - React-graphics (0.73.11): + - React-featureflags (0.77.3) + - React-featureflagsnativemodule (0.77.3): + - hermes-engine + - RCT-Folly + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - React-graphics (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - - RCT-Folly/Fabric (= 2022.05.16.00) - - React-Core/Default (= 0.73.11) + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-jsi + - React-jsiexecutor - React-utils - - React-hermes (0.73.11): + - React-hermes (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - RCT-Folly/Futures (= 2022.05.16.00) - - React-cxxreact (= 0.73.11) + - RCT-Folly (= 2024.11.18.00) + - React-cxxreact (= 0.77.3) + - React-jsi + - React-jsiexecutor (= 0.77.3) + - React-jsinspector + - React-perflogger (= 0.77.3) + - React-runtimeexecutor + - React-idlecallbacksnativemodule (0.77.3): + - hermes-engine + - RCT-Folly - React-jsi - - React-jsiexecutor (= 0.73.11) - - React-jsinspector (= 0.73.11) - - React-perflogger (= 0.73.11) - - React-ImageManager (0.73.11): + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimescheduler + - ReactCommon/turbomodule/core + - React-ImageManager (0.77.3): - glog - RCT-Folly/Fabric - React-Core/Default @@ -1008,47 +1296,124 @@ PODS: - React-graphics - React-rendererdebug - React-utils - - React-jserrorhandler (0.73.11): - - RCT-Folly/Fabric (= 2022.05.16.00) + - React-jserrorhandler (0.77.3): + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-cxxreact - React-debug + - React-featureflags - React-jsi - - React-Mapbuffer - - React-jsi (0.73.11): - - boost (= 1.83.0) + - ReactCommon/turbomodule/bridging + - React-jsi (0.77.3): + - boost - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-jsiexecutor (0.73.11): + - RCT-Folly (= 2024.11.18.00) + - React-jsiexecutor (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-cxxreact (= 0.73.11) - - React-jsi (= 0.73.11) - - React-perflogger (= 0.73.11) - - React-jsinspector (0.73.11) - - React-logger (0.73.11): + - RCT-Folly (= 2024.11.18.00) + - React-cxxreact (= 0.77.3) + - React-jsi (= 0.77.3) + - React-jsinspector + - React-perflogger (= 0.77.3) + - React-jsinspector (0.77.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-featureflags + - React-jsi + - React-perflogger (= 0.77.3) + - React-runtimeexecutor (= 0.77.3) + - React-jsitracing (0.77.3): + - React-jsi + - React-logger (0.77.3): - glog - - React-Mapbuffer (0.73.11): + - React-Mapbuffer (0.77.3): - glog - React-debug + - React-microtasksnativemodule (0.77.3): + - hermes-engine + - RCT-Folly + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core - react-native-attestation (0.1.0-alpha.1): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-config (1.5.5): - react-native-config/App (= 1.5.5) - react-native-config/App (1.5.5): - React-Core - react-native-date-picker (5.0.13): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-document-picker (9.3.1): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-encrypted-storage (4.0.3): - React-Core - react-native-get-random-values (1.11.0): @@ -1057,230 +1422,562 @@ PODS: - React-Core - react-native-orientation-locker (1.6.0): - React-Core - - react-native-safe-area-context (4.8.2): - - React-Core - - react-native-screenguard (1.1.0): + - react-native-safe-area-context (5.1.0): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) - - React-Core - - SDWebImage (~> 5.21.0) - - react-native-splash-screen (3.3.0): - - React-Core - - react-native-tcp-socket (6.0.6): - - CocoaAsyncSocket + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-safe-area-context/common (= 5.1.0) + - react-native-safe-area-context/fabric (= 5.1.0) + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/common (5.1.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-safe-area-context/fabric (5.1.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-safe-area-context/common + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-screenguard (1.1.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SDWebImage (~> 5.21.0) + - Yoga + - react-native-splash-screen (3.3.0): + - React-Core + - react-native-tcp-socket (6.0.6): + - CocoaAsyncSocket - React-Core - react-native-video (6.16.1): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager - react-native-video/Video (= 6.16.1) + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-video/Fabric (6.16.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-video/Video (6.16.1): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - react-native-video/Fabric + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-volume-manager (1.10.0): - Mute - React-Core - react-native-webrtc (124.0.6): - JitsiWebRTC (~> 124.0.0) - React-Core - - react-native-webview (13.10.7): + - react-native-webview (13.13.5): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-zeroconf (0.14.0): - React-Core - - React-nativeconfig (0.73.11) - - React-NativeModulesApple (0.73.11): + - React-nativeconfig (0.77.3) + - React-NativeModulesApple (0.77.3): - glog - hermes-engine - React-callinvoker - React-Core - React-cxxreact - React-jsi + - React-jsinspector - React-runtimeexecutor - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-perflogger (0.73.11) - - React-RCTActionSheet (0.73.11): - - React-Core/RCTActionSheetHeaders (= 0.73.11) - - React-RCTAnimation (0.73.11): - - RCT-Folly (= 2022.05.16.00) + - React-perflogger (0.77.3): + - DoubleConversion + - RCT-Folly (= 2024.11.18.00) + - React-performancetimeline (0.77.3): + - RCT-Folly (= 2024.11.18.00) + - React-cxxreact + - React-featureflags + - React-timing + - React-RCTActionSheet (0.77.3): + - React-Core/RCTActionSheetHeaders (= 0.77.3) + - React-RCTAnimation (0.77.3): + - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety - - React-Codegen - React-Core/RCTAnimationHeaders - React-jsi - React-NativeModulesApple + - React-RCTFBReactNativeSpec - ReactCommon - - React-RCTAppDelegate (0.73.11): - - RCT-Folly + - React-RCTAppDelegate (0.77.3): + - RCT-Folly (= 2024.11.18.00) - RCTRequired - RCTTypeSafety - React-Core - React-CoreModules + - React-debug + - React-defaultsnativemodule + - React-Fabric + - React-featureflags + - React-graphics - React-hermes - React-nativeconfig - React-NativeModulesApple - React-RCTFabric + - React-RCTFBReactNativeSpec - React-RCTImage - React-RCTNetwork + - React-rendererdebug + - React-RuntimeApple + - React-RuntimeCore + - React-RuntimeHermes - React-runtimescheduler + - React-utils - ReactCommon - - React-RCTBlob (0.73.11): + - React-RCTBlob (0.77.3): + - DoubleConversion + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-Codegen + - RCT-Folly (= 2024.11.18.00) - React-Core/RCTBlobHeaders - React-Core/RCTWebSocket - React-jsi + - React-jsinspector - React-NativeModulesApple + - React-RCTFBReactNativeSpec - React-RCTNetwork - ReactCommon - - React-RCTFabric (0.73.11): + - React-RCTFabric (0.77.3): - glog - hermes-engine - - RCT-Folly/Fabric (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) - React-Core - React-debug - React-Fabric + - React-FabricComponents - React-FabricImage + - React-featureflags - React-graphics - React-ImageManager - React-jsi + - React-jsinspector - React-nativeconfig + - React-performancetimeline - React-RCTImage - React-RCTText + - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - Yoga - - React-RCTImage (0.73.11): - - RCT-Folly (= 2022.05.16.00) + - React-RCTFBReactNativeSpec (0.77.3): + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - ReactCommon + - React-RCTImage (0.77.3): + - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety - - React-Codegen - React-Core/RCTImageHeaders - React-jsi - React-NativeModulesApple + - React-RCTFBReactNativeSpec - React-RCTNetwork - ReactCommon - - React-RCTLinking (0.73.11): - - React-Codegen - - React-Core/RCTLinkingHeaders (= 0.73.11) - - React-jsi (= 0.73.11) + - React-RCTLinking (0.77.3): + - React-Core/RCTLinkingHeaders (= 0.77.3) + - React-jsi (= 0.77.3) - React-NativeModulesApple + - React-RCTFBReactNativeSpec - ReactCommon - - ReactCommon/turbomodule/core (= 0.73.11) - - React-RCTNetwork (0.73.11): - - RCT-Folly (= 2022.05.16.00) + - ReactCommon/turbomodule/core (= 0.77.3) + - React-RCTNetwork (0.77.3): + - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety - - React-Codegen - React-Core/RCTNetworkHeaders - React-jsi - React-NativeModulesApple + - React-RCTFBReactNativeSpec - ReactCommon - - React-RCTSettings (0.73.11): - - RCT-Folly (= 2022.05.16.00) + - React-RCTSettings (0.77.3): + - RCT-Folly (= 2024.11.18.00) - RCTTypeSafety - - React-Codegen - React-Core/RCTSettingsHeaders - React-jsi - React-NativeModulesApple + - React-RCTFBReactNativeSpec - ReactCommon - - React-RCTText (0.73.11): - - React-Core/RCTTextHeaders (= 0.73.11) + - React-RCTText (0.77.3): + - React-Core/RCTTextHeaders (= 0.77.3) - Yoga - - React-RCTVibration (0.73.11): - - RCT-Folly (= 2022.05.16.00) - - React-Codegen + - React-RCTVibration (0.77.3): + - RCT-Folly (= 2024.11.18.00) - React-Core/RCTVibrationHeaders - React-jsi - React-NativeModulesApple + - React-RCTFBReactNativeSpec - ReactCommon - - React-rendererdebug (0.73.11): + - React-rendererconsistency (0.77.3) + - React-rendererdebug (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) - - RCT-Folly (= 2022.05.16.00) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) + - RCT-Folly (= 2024.11.18.00) - React-debug - - React-rncore (0.73.11) - - React-runtimeexecutor (0.73.11): - - React-jsi (= 0.73.11) - - React-runtimescheduler (0.73.11): + - React-rncore (0.77.3) + - React-RuntimeApple (0.77.3): + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-callinvoker + - React-Core/Default + - React-CoreModules + - React-cxxreact + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-Mapbuffer + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-runtimescheduler + - React-utils + - React-RuntimeCore (0.77.3): - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-cxxreact + - React-Fabric + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-performancetimeline + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - React-runtimeexecutor (0.77.3): + - React-jsi (= 0.77.3) + - React-RuntimeHermes (0.77.3): + - hermes-engine + - RCT-Folly/Fabric (= 2024.11.18.00) + - React-featureflags + - React-hermes + - React-jsi + - React-jsinspector + - React-jsitracing + - React-nativeconfig + - React-RuntimeCore + - React-utils + - React-runtimescheduler (0.77.3): + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) - React-callinvoker - React-cxxreact - React-debug + - React-featureflags - React-jsi + - React-performancetimeline + - React-rendererconsistency - React-rendererdebug - React-runtimeexecutor + - React-timing - React-utils - - React-utils (0.73.11): + - React-timing (0.77.3) + - React-utils (0.77.3): - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - React-debug + - React-jsi (= 0.77.3) + - ReactAppDependencyProvider (0.77.3): + - ReactCodegen + - ReactCodegen (0.77.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core - React-debug - - ReactCommon (0.73.11): - - React-logger (= 0.73.11) - - ReactCommon/turbomodule (= 0.73.11) - - ReactCommon/turbomodule (0.73.11): + - React-Fabric + - React-FabricImage + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-RCTAppDelegate + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactCommon (0.77.3): + - ReactCommon/turbomodule (= 0.77.3) + - ReactCommon/turbomodule (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-callinvoker (= 0.73.11) - - React-cxxreact (= 0.73.11) - - React-jsi (= 0.73.11) - - React-logger (= 0.73.11) - - React-perflogger (= 0.73.11) - - ReactCommon/turbomodule/bridging (= 0.73.11) - - ReactCommon/turbomodule/core (= 0.73.11) - - ReactCommon/turbomodule/bridging (0.73.11): + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.3) + - React-cxxreact (= 0.77.3) + - React-jsi (= 0.77.3) + - React-logger (= 0.77.3) + - React-perflogger (= 0.77.3) + - ReactCommon/turbomodule/bridging (= 0.77.3) + - ReactCommon/turbomodule/core (= 0.77.3) + - ReactCommon/turbomodule/bridging (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-callinvoker (= 0.73.11) - - React-cxxreact (= 0.73.11) - - React-jsi (= 0.73.11) - - React-logger (= 0.73.11) - - React-perflogger (= 0.73.11) - - ReactCommon/turbomodule/core (0.73.11): + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.3) + - React-cxxreact (= 0.77.3) + - React-jsi (= 0.77.3) + - React-logger (= 0.77.3) + - React-perflogger (= 0.77.3) + - ReactCommon/turbomodule/core (0.77.3): - DoubleConversion - - fmt (~> 6.2.1) + - fast_float (= 6.1.4) + - fmt (= 11.0.2) - glog - hermes-engine - - RCT-Folly (= 2022.05.16.00) - - React-callinvoker (= 0.73.11) - - React-cxxreact (= 0.73.11) - - React-jsi (= 0.73.11) - - React-logger (= 0.73.11) - - React-perflogger (= 0.73.11) + - RCT-Folly (= 2024.11.18.00) + - React-callinvoker (= 0.77.3) + - React-cxxreact (= 0.77.3) + - React-debug (= 0.77.3) + - React-featureflags (= 0.77.3) + - React-jsi (= 0.77.3) + - React-logger (= 0.77.3) + - React-perflogger (= 0.77.3) + - React-utils (= 0.77.3) - ReactNativeIncallManager (4.2.1): - React-Core - RNArgon2 (2.0.1): - CatCrypto - React-Core - RNCAsyncStorage (1.22.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNCClipboard (1.16.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNDeviceInfo (8.7.1): - React-Core - - RNFBApp (14.12.0): - - Firebase/CoreOnly (= 8.15.0) + - RNFBApp (21.14.0): + - Firebase/CoreOnly (= 11.11.0) - React-Core - - RNFBMessaging (14.12.0): - - Firebase/Messaging (= 8.15.0) + - RNFBMessaging (21.14.0): + - Firebase/Messaging (= 11.11.0) + - FirebaseCoreExtension - React-Core - RNFBApp - RNFS (2.20.0): - React-Core - - RNGestureHandler (2.18.1): + - RNGestureHandler (2.22.1): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RNInAppBrowser (3.7.0): - React-Core - RNKeychain (8.1.3): @@ -1288,70 +1985,194 @@ PODS: - RNLocalize (2.2.6): - React-Core - RNPermissions (5.4.2): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNScreens (4.6.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core - - RNScreens (4.4.0): + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNScreens/common (= 4.6.0) + - Yoga + - RNScreens/common (4.6.0): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric - React-RCTImage - - RNSVG (15.0.0): + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNSVG (15.11.2): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core - - RNVectorIcons (10.0.3): + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNSVG/common (= 15.11.2) + - Yoga + - RNSVG/common (15.11.2): + - DoubleConversion - glog - - RCT-Folly (= 2022.05.16.00) + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core - - SDWebImage (5.21.2): - - SDWebImage/Core (= 5.21.2) - - SDWebImage/Core (5.21.2) - - SocketRocket (0.6.1) - - VisionCamera (4.3.2): - - VisionCamera/Core (= 4.3.2) - - VisionCamera/React (= 4.3.2) - - VisionCamera/Core (4.3.2) - - VisionCamera/React (4.3.2): + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNVectorIcons (10.0.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.11.18.00) + - RCTRequired + - RCTTypeSafety - React-Core - - Yoga (1.14.0) + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - SDWebImage (5.21.7): + - SDWebImage/Core (= 5.21.7) + - SDWebImage/Core (5.21.7) + - SocketRocket (0.7.1) + - VisionCamera (4.7.3): + - VisionCamera/Core (= 4.7.3) + - VisionCamera/React (= 4.7.3) + - VisionCamera/Core (4.7.3) + - VisionCamera/React (4.7.3): + - React-Core + - Yoga (0.0.0) DEPENDENCIES: - "anoncreds (from `../node_modules/@hyperledger/anoncreds-react-native`)" - "aries-askar (from `../node_modules/@hyperledger/aries-askar-react-native`)" - - BcscCore (from `../node_modules/react-native-bcsc-core`) - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - BVLinearGradient (from `../node_modules/react-native-linear-gradient`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - Firebase - FirebaseCore - FirebaseCoreInternal + - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - GoogleUtilities - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - "indy-vdr (from `../node_modules/@hyperledger/indy-vdr-react-native`)" - - libevent (~> 2.1.12) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) + - RCTRequired (from `../node_modules/react-native/Libraries/Required`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - React (from `../node_modules/react-native/`) - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - - React-Codegen (from `build/generated/ios`) - React-Core (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`) + - React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`) - React-Fabric (from `../node_modules/react-native/ReactCommon`) + - React-FabricComponents (from `../node_modules/react-native/ReactCommon`) - React-FabricImage (from `../node_modules/react-native/ReactCommon`) + - React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`) + - React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`) - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`) - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`) - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) + - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) + - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) - "react-native-attestation (from `../node_modules/@bifold/react-native-attestation`)" - react-native-config (from `../node_modules/react-native-config`) - react-native-date-picker (from `../node_modules/react-native-date-picker`) @@ -1372,22 +2193,31 @@ DEPENDENCIES: - React-nativeconfig (from `../node_modules/react-native/ReactCommon`) - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) - React-RCTFabric (from `../node_modules/react-native/React`) + - React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`) - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`) - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`) - React-rncore (from `../node_modules/react-native/ReactCommon`) + - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`) + - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`) - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`) - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-timing (from `../node_modules/react-native/ReactCommon/react/timing`) - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) + - ReactAppDependencyProvider (from `build/generated/ios`) + - ReactCodegen (from `build/generated/ios`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - ReactNativeIncallManager (from `../node_modules/react-native-incall-manager`) - RNArgon2 (from `../node_modules/react-native-argon2`) @@ -1415,16 +2245,14 @@ SPEC REPOS: - Firebase - FirebaseAnalytics - FirebaseCore - - FirebaseCoreDiagnostics + - FirebaseCoreExtension - FirebaseCoreInternal - FirebaseInstallations - FirebaseMessaging - - fmt - GoogleAppMeasurement - GoogleDataTransport - GoogleUtilities - JitsiWebRTC - - libevent - Mute - nanopb - PromisesObjC @@ -1436,37 +2264,37 @@ EXTERNAL SOURCES: :path: "../node_modules/@hyperledger/anoncreds-react-native" aries-askar: :path: "../node_modules/@hyperledger/aries-askar-react-native" - BcscCore: - :path: "../node_modules/react-native-bcsc-core" boost: :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" BVLinearGradient: :path: "../node_modules/react-native-linear-gradient" DoubleConversion: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + fast_float: + :podspec: "../node_modules/react-native/third-party-podspecs/fast_float.podspec" FBLazyVector: :path: "../node_modules/react-native/Libraries/FBLazyVector" - FBReactNativeSpec: - :path: "../node_modules/react-native/React/FBReactNativeSpec" + fmt: + :podspec: "../node_modules/react-native/third-party-podspecs/fmt.podspec" glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" - :tag: hermes-2024-04-29-RNv0.73.8-644c8be78af1eae7c138fa4093fb87f0f4f8db85 + :tag: hermes-2024-11-25-RNv0.77.0-d4f25d534ab744866448b36ca3bf3d97c08e638c indy-vdr: :path: "../node_modules/@hyperledger/indy-vdr-react-native" RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTDeprecation: + :path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" RCTRequired: - :path: "../node_modules/react-native/Libraries/RCTRequired" + :path: "../node_modules/react-native/Libraries/Required" RCTTypeSafety: :path: "../node_modules/react-native/Libraries/TypeSafety" React: :path: "../node_modules/react-native/" React-callinvoker: :path: "../node_modules/react-native/ReactCommon/callinvoker" - React-Codegen: - :path: build/generated/ios React-Core: :path: "../node_modules/react-native/" React-CoreModules: @@ -1475,14 +2303,26 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/cxxreact" React-debug: :path: "../node_modules/react-native/ReactCommon/react/debug" + React-defaultsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults" + React-domnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom" React-Fabric: :path: "../node_modules/react-native/ReactCommon" + React-FabricComponents: + :path: "../node_modules/react-native/ReactCommon" React-FabricImage: :path: "../node_modules/react-native/ReactCommon" + React-featureflags: + :path: "../node_modules/react-native/ReactCommon/react/featureflags" + React-featureflagsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags" React-graphics: :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" React-hermes: :path: "../node_modules/react-native/ReactCommon/hermes" + React-idlecallbacksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" React-ImageManager: :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" React-jserrorhandler: @@ -1493,10 +2333,14 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/jsiexecutor" React-jsinspector: :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" + React-jsitracing: + :path: "../node_modules/react-native/ReactCommon/hermes/executor/" React-logger: :path: "../node_modules/react-native/ReactCommon/logger" React-Mapbuffer: :path: "../node_modules/react-native/ReactCommon" + React-microtasksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" react-native-attestation: :path: "../node_modules/@bifold/react-native-attestation" react-native-config: @@ -1537,6 +2381,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" React-perflogger: :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-performancetimeline: + :path: "../node_modules/react-native/ReactCommon/react/performance/timeline" React-RCTActionSheet: :path: "../node_modules/react-native/Libraries/ActionSheetIOS" React-RCTAnimation: @@ -1547,6 +2393,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/Libraries/Blob" React-RCTFabric: :path: "../node_modules/react-native/React" + React-RCTFBReactNativeSpec: + :path: "../node_modules/react-native/React" React-RCTImage: :path: "../node_modules/react-native/Libraries/Image" React-RCTLinking: @@ -1559,16 +2407,30 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/Libraries/Text" React-RCTVibration: :path: "../node_modules/react-native/Libraries/Vibration" + React-rendererconsistency: + :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency" React-rendererdebug: :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" React-rncore: :path: "../node_modules/react-native/ReactCommon" + React-RuntimeApple: + :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" + React-RuntimeCore: + :path: "../node_modules/react-native/ReactCommon/react/runtime" React-runtimeexecutor: :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-RuntimeHermes: + :path: "../node_modules/react-native/ReactCommon/react/runtime" React-runtimescheduler: :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-timing: + :path: "../node_modules/react-native/ReactCommon/react/timing" React-utils: :path: "../node_modules/react-native/ReactCommon/react/utils" + ReactAppDependencyProvider: + :path: build/generated/ios + ReactCodegen: + :path: build/generated/ios ReactCommon: :path: "../node_modules/react-native/ReactCommon" ReactNativeIncallManager: @@ -1611,112 +2473,127 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: anoncreds: 4b29b0ef841fc1a96910aab8f047c090ee6acb89 aries-askar: 6fce8d0405b8c84e654a694be1954649cf7955a3 - BcscCore: 3b8d5910cba73e271ec5c6654377f1ff6eabc231 - boost: d3f49c53809116a5d38da093a8aa78bf551aed09 + boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 BVLinearGradient: cb006ba232a1f3e4f341bb62c42d1098c284da70 CatCrypto: a477899b6be4954e75be4897e732da098cc0a5a8 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 - FBLazyVector: b46891061bfe0a9b07f601813114c8653a72a45c - FBReactNativeSpec: 9a01850c21d81027fa7b20b9dcc25d9bfae083da - Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d - FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa - FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1 - FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb - FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934 - FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd - FirebaseMessaging: 5e5118a2383b3531e730d974680954c679ca0a13 - fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 - GoogleAppMeasurement: 4c19f031220c72464d460c9daa1fb5d1acce958e - GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a - GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 - hermes-engine: d992945b77c506e5164e6a9a77510c9d57472c59 + DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb + fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6 + FBLazyVector: 23d8c5470c648a635893dc0956c6dbaead54b656 + Firebase: 6a8f201c61eda24e98f1ce2b44b1b9c2caf525cc + FirebaseAnalytics: acfa848bf81e1a4dbf60ef1f0eddd7328fe6673e + FirebaseCore: 2321536f9c423b1f857e047a82b8a42abc6d9e2c + FirebaseCoreExtension: 3a64994969dd05f4bcb7e6896c654eded238e75b + FirebaseCoreInternal: 31ee350d87b30a9349e907f84bf49ef8e6791e5a + FirebaseInstallations: 781e0e37aa0e1c92b44d00e739aba79ad31b2dba + FirebaseMessaging: c7be9357fd8ba33bc45b9a6c3cdff0b466e1e2a4 + fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd + glog: eb93e2f488219332457c3c4eafd2738ddc7e80b8 + GoogleAppMeasurement: 8a82b93a6400c8e6551c0bcd66a9177f2e067aed + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 + GoogleUtilities: 766ace00c6b10d8148408f329d10c4f051931850 + hermes-engine: b2187dbe13edb0db8fcb2a93a69c1987a30d98a4 indy-vdr: aada31078a9ed270dd618fadb4cf69bcdc333d68 JitsiWebRTC: b47805ab5668be38e7ee60e2258f49badfe8e1d0 - libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 Mute: 20135a96076f140cc82bfc8b810e2d6150d8ec7e - nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - RCT-Folly: cd21f1661364f975ae76b3308167ad66b09f53f5 - RCTRequired: 415e56f7c33799a6483e41e4dce607f3daf1e69b - RCTTypeSafety: e984a88e713281c2d8c2309a1a6d2775af0107ae - React: ab885684e73c5f659bad63446a977312fd3d1ecb - React-callinvoker: 50a2d1ce3594637c700401ba306373321231eb71 - React-Codegen: 0ca856c100b98ab436c73601f9b1296a58d26b92 - React-Core: d5166294382484f57e25dfde05ba00596703d51c - React-CoreModules: 459534f8112ee73e94f04f5e58276b3d236efd16 - React-cxxreact: d5716540fd97df323792ef1d227f50515fb3e1a8 - React-debug: cbc88cbcffdca42184a32d073ceb7d9b11122b8d - React-Fabric: 0008b953afdacf3dd5ac38947a36d9c280e3a0a1 - React-FabricImage: 51198a14587c3269e12cf823e81a6f3b642dd136 - React-graphics: 977137c75673c2f31a1515ce48db31a076771112 - React-hermes: 59ff965e45955d66977a23d51fe9235b44a09bd4 - React-ImageManager: 5c8d5e6246c22613a0cb198c51044f4794e8c518 - React-jserrorhandler: 90c29c95fb32abfdb61ab9c8eb425e6af097a0b9 - React-jsi: 36f85df7d83197707e9fd9320d857eac616e6df3 - React-jsiexecutor: a68ea442fd94c7ecf5d9355bde2443f0241531d9 - React-jsinspector: a98428936fb888cc15d857226a26d9ac0a668a0e - React-logger: 6e4873d1f9c54cca30f6c91a6617f8c91b75ba4c - React-Mapbuffer: 57bf49a458398d329dad2bf8bc660e3e35b96989 - react-native-attestation: c7e459cb6585f3757addf8d1d4d8d30bf7d32081 + nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + PromisesObjC: 752c3227f599e3467650e47ea36f433eeb10c273 + RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 + RCTDeprecation: 6ee92578d332db1d4e03267d3ae98bcf8b780863 + RCTRequired: 5b3da0e0f91fddda935574b81748c3e3d3649ee7 + RCTTypeSafety: 870cb072be3d3f310ecec897c3d297a931f8f7e1 + React: 535fa5014fb1743f6654a980acb16dae339e1944 + React-callinvoker: dd1ecd51f8d3c76a551afdf6dab6d51c1ead5501 + React-Core: a3e36c059a195bd213d005db36c9e68957b78632 + React-CoreModules: 46467a2b34b053eb7262104e07bf5d835a9afe77 + React-cxxreact: 500e7b011a14eeefdcf6c0eb982fe4db055c2670 + React-debug: 41315631a01cf5cc3c9498482b97be21c49f8e8d + React-defaultsnativemodule: a06364257949e77dc39bcfd08e2d801c189bb58c + React-domnativemodule: dcda8a2b62bb34ed5db94470a3a72f32a76e1e31 + React-Fabric: dc1d3aa4b6a92e4a703c02ca6c4add312754eb84 + React-FabricComponents: 451f7b72aa80001520a20747b7b1e21350d6fba8 + React-FabricImage: 15c3bfe577a60c492134519219627316fb48af05 + React-featureflags: 08f06c820a37b29ed3ef9dddc6763c086339bc28 + React-featureflagsnativemodule: 3f6b19ac469a5d26e3a52e5198735c1799f1e324 + React-graphics: df8448a604e8fd03325e0f3d760b13e57416871c + React-hermes: 67f3ee00fdbe085e722fd89811073678ba28c10a + React-idlecallbacksnativemodule: 26de008466429c4a6feb772cde37d3eda5c1e045 + React-ImageManager: 52a8c48c4c7c5a8124e8c363693bd2908b01c5f6 + React-jserrorhandler: faa483d54dd358b11e81adcd5e6373da6030ed70 + React-jsi: d5332d79759159a0127348d9b20cc90527dd40e8 + React-jsiexecutor: 72c8df1af2c18736f6685cce4205c480f3783039 + React-jsinspector: e444c5725dbb31aa7ce556d972511f8997b38bc5 + React-jsitracing: 955646960c72c03e6e87df8706cab6bcdf960042 + React-logger: a23563f96a622637d7cce687bdf304929104effd + React-Mapbuffer: 1864935968d15b9b73d8e413d29c780f0ab50038 + React-microtasksnativemodule: 3b784cf40f7c3c9500b9a5f9e4eec5c9bbfbef8f + react-native-attestation: 0bbb1201478f83c05063dc77beb7f99aa7cc525a react-native-config: 644074ab88db883fcfaa584f03520ec29589d7df - react-native-date-picker: 2eca217a8fb09c517f5bb6b23978718c6cec59ec - react-native-document-picker: 4425fea5360a9e3ec5f268681194bf88ae67ec65 + react-native-date-picker: 729d0384b49f516c6712625aa571d55af5cdb1e0 + react-native-document-picker: bfe9c7d72908d2faba56a4765373c6367090ae2e react-native-encrypted-storage: 569d114e329b1c2c2d9f8c84bcdbe4478dda2258 react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba react-native-netinfo: 28c2462c85067fe653615f6f595673bdca93a287 react-native-orientation-locker: ee8bb2177365ca74f51dc1e11218fe544634d523 - react-native-safe-area-context: bf9d9d58f0f6726d4a6257088044c2595017579d - react-native-screenguard: 38cf6d55781c6225f33be32afeb13cb2a0e154ee + react-native-safe-area-context: efd435f89b73d91f37438e5ac2d725f0e7adff95 + react-native-screenguard: 8172a4f514c46fd76fe84c5a599e818fc3b81b87 react-native-splash-screen: 95994222cc95c236bd3cdc59fe45ed5f27969594 react-native-tcp-socket: ae8abcfebc071216302a09d9ed1e375d4e877484 - react-native-video: d74d94fbaeee3c0d8f6570173289f43fe210066f + react-native-video: bb03ea28ed6554fd615a71bb6e8c9bddab201555 react-native-volume-manager: d9d2863a2374420af89c89662333ea6adf506988 react-native-webrtc: 96fdff9e3a942ed88cafe01898da1c93fd628957 - react-native-webview: f802f655c8446404bb0c134da9335a8cf667e8cb + react-native-webview: 5095dd03fc98a529e44a6bb81aed21062b5f879e react-native-zeroconf: eb2e5584308f20f5fc3eb0cea2ceafbbd345b48b - React-nativeconfig: 8fd29a35a3e4e8c37682d976667663d834ba6165 - React-NativeModulesApple: 83d7077877f8eda8e1b6055b3f8f16f7db8463b5 - React-perflogger: 3887a05940ccd34a83457fd153fdeda509b31737 - React-RCTActionSheet: 2f42b4797374b53e93b65c79eaa8a0d292e255ac - React-RCTAnimation: 5639dcd418b798b28e9caacaed18ff5472454837 - React-RCTAppDelegate: 37d3142bfa7cb9f2f8cd41feedc6b50c95986029 - React-RCTBlob: e9f735bb085c6da208dd138bd4bfd294a52e3a86 - React-RCTFabric: 8c1abd00ccb3aff18f67b39f0a37034a30f402f3 - React-RCTImage: cc82df2b50bbdc1a0a0b19bf6fc16dd321eb8f0f - React-RCTLinking: 3d7900f52ecf03bb2522d7b94d8d16cce776294a - React-RCTNetwork: ac25c15ee52eb4aadb510afe68db0d1f949c45fa - React-RCTSettings: 013301fe7304ff06acca5287f6f754c9fa2b63b7 - React-RCTText: ba6997c26241ea0b36ec8f98502a4ed45cab18e4 - React-RCTVibration: b5ba13ed0909d2f2614ed99b067543e6ea0d7c37 - React-rendererdebug: dda7606832e5907ecbdf2093950068a36fd5a267 - React-rncore: 0dd62c0c8f8215747a9b49035410fde76a18876e - React-runtimeexecutor: 2fd27b921f664e66d903ee274dcda55cc0b2cb2e - React-runtimescheduler: 398069b748d97567cc7585cc9a97284ad19d72fa - React-utils: e8549669b504c18929b2e9aa4d87657e530a91a4 - ReactCommon: 9c38e8797dc2ac72edf63cd18cf450d918575666 + React-nativeconfig: f77b4627803bf7886a1f2e96b33b8af34e583cc4 + React-NativeModulesApple: dfa86c79c621f2a9cdb39636570c2e1623b71367 + React-perflogger: 1f83401f01544142b32151ef6c66870455c64994 + React-performancetimeline: 514430bf73208debfb0b9981fdab0e3e67987447 + React-RCTActionSheet: f8f5545f473a87a8ab124046fe58905b82c55322 + React-RCTAnimation: bb5332589ee135a4b3e06f9475659ae73a36f669 + React-RCTAppDelegate: 56493d143af24c5d728880adcf7849b3deb864e4 + React-RCTBlob: 9305f10874660b7d7bd02f6567e1b97c29b5cc43 + React-RCTFabric: c116c07d3d57e7bd03d64e445f43b33cd57a1b51 + React-RCTFBReactNativeSpec: 87fc0066242c08a7b7d03297d5ea803ac0df6575 + React-RCTImage: f099c09decb34b6849518e85aa8cd6318381ed98 + React-RCTLinking: ab70f4b60e21b0abb8c2adc58ae0460cffecdd8f + React-RCTNetwork: ba84704fa893dcc090d5028b932ed049332b9e6f + React-RCTSettings: bad043f6652f2641fccf9654c3f789e970ca63c8 + React-RCTText: bed66ec05d4dedfc48d6db8d3cf60e714b2d010d + React-RCTVibration: 22179961d1aadd7996355785c490c134037de1d9 + React-rendererconsistency: 9f5292176e629370402cbfe4e88c19b3c68e79a3 + React-rendererdebug: 1d63129046b7a8624f0a5d2cb4cc4a1dda41eeaf + React-rncore: 8a77fbb638aab2ef0a3e4e122ddc5310a8299699 + React-RuntimeApple: cf68b82dc184c7f8855aa6bae298b4b24880d549 + React-RuntimeCore: 98ab2e46540d3560712334257b01d6305c0cb422 + React-runtimeexecutor: 2dc71d251ce5630b11d384bc80d7fbb9d9d93623 + React-RuntimeHermes: 7cc49896e48214abee8f2a9bf91e7a91606ff018 + React-runtimescheduler: a51c3e414e288f3ab876b8b6e50e89c805ffd704 + React-timing: 7d80ad4297c57ec4cb49da4a5db1b82f93fedb2a + React-utils: 6b632afea2c4ec4b782497fb61af859a5b1b355f + ReactAppDependencyProvider: 31015410a4a53b9fd0a908ad4d6e3e2b9a25086a + ReactCodegen: eac5d74d85dff515b48a5c36f154bc4128f217e6 + ReactCommon: bf4612cba0fa356b529385029f470d5529dddde4 ReactNativeIncallManager: dccd3e7499caa3bb73d3acfedf4fb0360f1a87d5 RNArgon2: 708e188b7a4d4ec8baf62463927c47abef453a94 - RNCAsyncStorage: 9350c2956f996b3ff1ac7cfdb50901c113a27640 - RNCClipboard: f6679d470d0da2bce2a37b0af7b9e0bf369ecda5 + RNCAsyncStorage: 886aecfc41ffbd3ad8bbf20399008dcdb9825c8d + RNCClipboard: ba9fda8e2c9f003a29f7f66793069c4d0dada955 RNDeviceInfo: d3e91ffb33ee97a7982108476edb68cb3672efa6 - RNFBApp: 827b4dfadf8c039738c1c928474e45b3ec306ba0 - RNFBMessaging: 6465e1ccc5421e9493a5ed8d7d69e4daf8a2de6d + RNFBApp: 4105e54d9ca4a1c10893a032268470f670181110 + RNFBMessaging: 6857871d9dff8f26b0c325fc7d97ba69cb77d213 RNFS: 89de7d7f4c0f6bafa05343c578f61118c8282ed8 - RNGestureHandler: 03a2c31aea5d46f51080f1c1b6659b76a9ac78c9 + RNGestureHandler: 657b9ff1f40ee3ace3de2bcf467f86d9a6874197 RNInAppBrowser: 6d3eb68d471b9834335c664704719b8be1bfdb20 RNKeychain: c497f7844b24577523bb84a6e8af9d217957972f RNLocalize: 8bf466de4c92d4721b254aabe1ff0a1456e7b9f4 - RNPermissions: 6dbd8de5d88b730d746057d5cd868a93888ce994 - RNScreens: e0f79783ce405f4362c29d098b19fe7e241f11a9 - RNSVG: a9e095acf2e207f2ef491870523ed455636cf3b8 - RNVectorIcons: 102cd20472bf0d7cd15443d43cd87f9c97228ac3 - SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a - SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 - VisionCamera: 6ad4b86176f6fea45e90e380d3d530bc5e1abff9 - Yoga: 1f93d5925ea12fb0880b21efe3566677337cf2ed + RNPermissions: 0631a73d8f4ad4456d7b8800c8d229bc25fd69bf + RNScreens: 5a1573ceb1a13b2d0663cbfb42cb4aa8803554eb + RNSVG: 877cd57c2db63dc9f1fd1bbb5e95506ccd481df6 + RNVectorIcons: e3de86373e72222279df103848d78f41c5236806 + SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf + SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 + VisionCamera: b51af005669c6642dd1b4fca434eda4c1778de87 + Yoga: 7d51419602153919f32aec72812e324d495ee49d -PODFILE CHECKSUM: 4a08b54523014fd5431e03183542e6526d90cba5 +PODFILE CHECKSUM: 060c20073a028f4f9dfcc51e2c64b8a5a0f9f416 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/app/ios/PrivacyInfo.xcprivacy b/app/ios/PrivacyInfo.xcprivacy index db45b7c..4250b15 100644 --- a/app/ios/PrivacyInfo.xcprivacy +++ b/app/ios/PrivacyInfo.xcprivacy @@ -9,9 +9,9 @@ NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons + CA92.1 1C8F.1 C56D.1 - CA92.1 diff --git a/app/jestSetup.js b/app/jestSetup.js index afb9fde..6f2e40e 100644 --- a/app/jestSetup.js +++ b/app/jestSetup.js @@ -14,7 +14,8 @@ mockRNDeviceInfo.getBuildNumber = jest.fn(() => '1') jest.mock('react-native-safe-area-context', () => mockSafeAreaContext) jest.mock('@react-native-community/netinfo', () => mockRNCNetInfo) jest.mock('react-native-device-info', () => mockRNDeviceInfo) -jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper') +// moved in RN 0.76: Libraries/Animated/NativeAnimatedHelper → src/private/animated/ +jest.mock('react-native/src/private/animated/NativeAnimatedHelper') jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter') jest.mock('react-native-localize', () => mockRNLocalize) jest.mock('react-native-vision-camera', () => { diff --git a/app/metro.config.js b/app/metro.config.js index 1812ac7..0d45d47 100644 --- a/app/metro.config.js +++ b/app/metro.config.js @@ -12,7 +12,6 @@ const packageDirs = [ fs.realpathSync(path.join(__dirname, 'node_modules', '@bifold/verifier')), fs.realpathSync(path.join(__dirname, 'node_modules', '@bifold/react-native-attestation')), fs.realpathSync(path.join(__dirname, 'node_modules', '@bifold/vrc-contexts')), - fs.realpathSync(path.join(__dirname, 'node_modules', 'react-native-bcsc-core')), ] // In development, resolve these to source for hot reload; CI/production uses built output. diff --git a/app/package.json b/app/package.json index df8104c..5dbcba6 100644 --- a/app/package.json +++ b/app/package.json @@ -69,16 +69,16 @@ "@formatjs/intl-numberformat": "~7.2.6", "@formatjs/intl-pluralrules": "~4.1.6", "@formatjs/intl-relativetimeformat": "~9.3.3", - "@hyperledger/anoncreds-react-native": "0.2.4", - "@hyperledger/aries-askar-react-native": "0.2.3", - "@hyperledger/indy-vdr-react-native": "0.2.2", + "@hyperledger/anoncreds-react-native": "patch:@hyperledger/anoncreds-react-native@npm%3A0.2.4#~/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch", + "@hyperledger/aries-askar-react-native": "patch:@hyperledger/aries-askar-react-native@npm%3A0.2.3#~/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch", + "@hyperledger/indy-vdr-react-native": "patch:@hyperledger/indy-vdr-react-native@npm%3A0.2.2#~/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch", "@hyperledger/indy-vdr-shared": "0.2.2", "@pexip/infinity-api": "~19.1.2", "@react-native-async-storage/async-storage": "~1.22.3", "@react-native-clipboard/clipboard": "~1.16.3", "@react-native-community/netinfo": "~11.3.3", - "@react-native-firebase/app": "~14.12.0", - "@react-native-firebase/messaging": "~14.12.0", + "@react-native-firebase/app": "~21.14.0", + "@react-native-firebase/messaging": "~21.14.0", "@react-navigation/bottom-tabs": "~6.0.9", "@react-navigation/devtools": "~6.0.27", "@react-navigation/native": "~6.0.16", @@ -98,10 +98,9 @@ "query-string": "~7.1.3", "react": "~18.3.1", "react-i18next": "~11.17.1", - "react-native": "0.73.11", + "react-native": "0.77.3", "react-native-animated-pagination-dots": "~0.1.73", "react-native-argon2": "~2.0.1", - "react-native-bcsc-core": "workspace:*", "react-native-bouncy-checkbox": "~3.0.7", "react-native-check-version": "~1.3.0", "react-native-collapsible": "~1.6.2", @@ -112,7 +111,7 @@ "react-native-document-picker": "^9.3.1", "react-native-encrypted-storage": "~4.0.3", "react-native-fs": "~2.20.0", - "react-native-gesture-handler": "~2.18.1", + "react-native-gesture-handler": "~2.22.0", "react-native-get-random-values": "~1.11.0", "react-native-gifted-chat": "*", "react-native-inappbrowser-reborn": "~3.7.0", @@ -124,21 +123,21 @@ "react-native-orientation-locker": "~1.6.0", "react-native-permissions": "~5.4.1", "react-native-qrcode-svg": "~6.2.0", - "react-native-safe-area-context": "~4.8.2", + "react-native-safe-area-context": "~5.1.0", "react-native-scalable-image": "~1.1.0", "react-native-screenguard": "~1.1.0", - "react-native-screens": "~4.4.0", + "react-native-screens": "~4.6.0", "react-native-splash-screen": "~3.3.0", - "react-native-svg": "~15.0.0", + "react-native-svg": "~15.11.1", "react-native-tcp-socket": "~6.0.6", "react-native-toast-message": "~2.1.10", "react-native-uuid": "~2.0.3", "react-native-vector-icons": "~10.0.3", "react-native-video": "~6.16.1", - "react-native-vision-camera": "4.3.2", + "react-native-vision-camera": "4.7.3", "react-native-volume-manager": "~1.10.0", "react-native-webrtc": "~124.0.6", - "react-native-webview": "~13.10.7", + "react-native-webview": "~13.13.1", "react-native-zeroconf": "~0.14.0", "readable-stream": "^4.7.0", "reflect-metadata": "~0.1.14", @@ -148,16 +147,19 @@ "uuid": "~9.0.1" }, "devDependencies": { - "@babel/core": "~7.22.20", - "@babel/preset-env": "~7.22.20", - "@babel/runtime": "~7.23.9", + "@babel/core": "~7.25.2", + "@babel/preset-env": "~7.25.3", + "@babel/runtime": "~7.25.0", "@commitlint/cli": "~11.0.0", "@eslint/js": "~8.57.1", - "@react-native/babel-preset": "~0.73.21", - "@react-native/eslint-config": "~0.73.2", - "@react-native/eslint-plugin": "~0.73.1", - "@react-native/metro-config": "~0.73.5", - "@react-native/typescript-config": "~0.73.1", + "@react-native-community/cli": "15.0.1", + "@react-native-community/cli-platform-android": "15.0.1", + "@react-native-community/cli-platform-ios": "15.0.1", + "@react-native/babel-preset": "0.77.3", + "@react-native/eslint-config": "0.77.3", + "@react-native/eslint-plugin": "0.77.3", + "@react-native/metro-config": "0.77.3", + "@react-native/typescript-config": "0.77.3", "@storybook/addon-actions": "~5.3.21", "@storybook/addon-knobs": "~5.3.21", "@storybook/addon-links": "~5.3.21", @@ -199,9 +201,9 @@ "pod-install": "~0.1.39", "postinstall-postinstall": "^2.1.0", "prettier": "~2.8.8", - "react-dom": "~18.2.0", + "react-dom": "~18.3.1", "react-native-svg-transformer": "~0.14.3", - "react-test-renderer": "~18.2.0", + "react-test-renderer": "~18.3.1", "typescript": "~5.5.4", "typescript-eslint": "~7.18.0" } diff --git a/app/src/Root.tsx b/app/src/Root.tsx index 5b2f7a5..87583a3 100644 --- a/app/src/Root.tsx +++ b/app/src/Root.tsx @@ -1,11 +1,7 @@ -import { RootStack as KeyRingRootStack, useStore } from '@bifold/core' -import { BCState, Mode } from '@/store' -import BCSCRootStack from '@bcsc-theme/navigators/RootStack' +import { RootStack as KeyRingRootStack } from '@bifold/core' const Root: React.FC = () => { - const [store] = useStore() - - return store.mode === Mode.KeyRingSC ? : + return } export default Root diff --git a/app/src/bcsc-theme/__tests__/components/TileButton.test.tsx b/app/src/bcsc-theme/__tests__/components/TileButton.test.tsx deleted file mode 100644 index 57c8aa7..0000000 --- a/app/src/bcsc-theme/__tests__/components/TileButton.test.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { testIdWithKey } from '@bifold/core' -import { fireEvent, render } from '@testing-library/react-native' -import React from 'react' - -import TileButton from '../../components/TileButton' -import { BasicAppContext } from '../../../../__mocks__/helpers/app' - -describe('TileButton Component', () => { - const onPress = jest.fn() - const actionText = 'Action text' - const description = - 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quasi et consectetur iusto error aliquam' - const testIDKey = 'TileButton' - const accessibilityLabel = 'Card' - - beforeEach(() => { - jest.resetAllMocks() - }) - - test('renders correctly', () => { - const tree = render( - - - - ) - expect(tree).toMatchSnapshot() - }) - - test('test ID is present and press handler works', () => { - const { getByTestId } = render( - - - - ) - - const tileButton = getByTestId(testIdWithKey(testIDKey)) - expect(tileButton).toBeDefined() - fireEvent(tileButton, 'press') - expect(onPress).toHaveBeenCalledTimes(1) - }) -}) diff --git a/app/src/bcsc-theme/__tests__/components/__snapshots__/TileButton.test.tsx.snap b/app/src/bcsc-theme/__tests__/components/__snapshots__/TileButton.test.tsx.snap deleted file mode 100644 index 13397a5..0000000 --- a/app/src/bcsc-theme/__tests__/components/__snapshots__/TileButton.test.tsx.snap +++ /dev/null @@ -1,99 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TileButton Component renders correctly 1`] = ` - - - - Action text - - 󱦰 - - - - Lorem ipsum dolor sit amet consectetur adipisicing elit. Quasi et consectetur iusto error aliquam - - - -`; diff --git a/app/src/bcsc-theme/api/client.ts b/app/src/bcsc-theme/api/client.ts deleted file mode 100644 index c0bd92b..0000000 --- a/app/src/bcsc-theme/api/client.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { RemoteLogger } from '@bifold/remote-logs' -import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios' -import { jwtDecode } from 'jwt-decode' -import { getRefreshTokenRequestBody } from 'react-native-bcsc-core' - -import { getDeviceCountFromIdToken } from '../utils/get-device-count' -import { TokenStatusResponseData } from './hooks/useTokens' -import { withAccount } from './hooks/withAccountGuard' - -// Extend AxiosRequestConfig to include skipBearerAuth -declare module 'axios' { - export interface AxiosRequestConfig { - skipBearerAuth?: boolean - } -} - -export interface TokenStatusResponseDataWithDeviceCount extends TokenStatusResponseData { - bcsc_devices_count?: number -} - -interface BCSCConfig { - pairDeviceWithQRCodeSupported: boolean - maximumAccountsPerDevice: number - allowedIdentificationProcesses: string[] - credentialFlowsSupported: string - multipleAccountsSupported: boolean - attestationTimeToLive: number -} - -interface BCSCEndpoints { - attestation: string - issuer: string - authorization: string - userInfo: string - deviceAuthorization: string - jwksURI: string - registration: string - clientMetadata: string - savedServices: string - token: string - credential: string - evidence: string - video: string -} - -class BCSCApiClient { - readonly client: AxiosInstance - readonly logger: RemoteLogger - endpoints: BCSCEndpoints - config: BCSCConfig - baseURL: string - tokens?: TokenStatusResponseData // this token will be used to interact and access data from IAS servers - - constructor(baseURL: string, logger: RemoteLogger) { - this.baseURL = baseURL - this.logger = logger - this.client = axios.create({ - headers: { - 'Content-Type': 'application/json', - }, - }) - - if (this.baseURL) { - this.logger.info(`BCSCApiClient initialized with URL: ${this.baseURL}`) - } else { - this.logger.error('BCSCApiClient initialized with empty URL.') - } - - // fallback config - this.config = { - pairDeviceWithQRCodeSupported: true, - maximumAccountsPerDevice: 0, - allowedIdentificationProcesses: [ - 'IDIM L3 Remote BCSC Photo Identity Verification', - 'IDIM L3 Remote BCSC Non-Photo Identity Verification', - 'IDIM L3 Remote Non-BCSC Identity Verification', - ], - credentialFlowsSupported: 'default_web_flow, bcwallet_initiated, bcsc_initiated', - multipleAccountsSupported: false, - attestationTimeToLive: 60, - } - - // fallback endpoints - this.endpoints = { - attestation: `${this.baseURL}/device/attestations`, - issuer: `${this.baseURL}/device/`, - authorization: `${this.baseURL}/device/authorize`, - userInfo: `${this.baseURL}/device/userinfo`, - deviceAuthorization: `${this.baseURL}/device/devicecode`, - jwksURI: `${this.baseURL}/device/jwk`, - registration: `${this.baseURL}/device/register`, - clientMetadata: `${this.baseURL}/device/clients/metadata`, - savedServices: `${this.baseURL}/device/services`, - token: `${this.baseURL}/device/token`, - credential: `${this.baseURL}/credentials/v1/person`, - evidence: `${this.baseURL}/evidence`, - video: `${this.baseURL}/video`, - } - - // Add interceptors - this.client.interceptors.request.use(this.handleRequest.bind(this)) - this.client.interceptors.response.use(undefined, (error: AxiosError) => { - const errorDetails = { - name: error.name, - message: error.message, - code: error.code, - - request: { - method: error.config?.method?.toUpperCase(), - url: error.config?.url, - baseURL: error.config?.baseURL, - headers: error.config?.headers, - data: error.config?.data, - params: error.config?.params, - }, - - response: error.response - ? { - status: error.response.status, - statusText: error.response.statusText, - headers: error.response.headers, - data: error.response.data, - } - : null, - - isTimeout: error.code === 'ECONNABORTED', - isNetworkError: !error.response && !error.code, - - stack: error.stack, - } - - this.logger.error(`API Error:\n${JSON.stringify(errorDetails, null, 2)}`) - - return Promise.reject(error) - }) - } - - async fetchEndpointsAndConfig(url: string) { - const response = await this.get(`${url}/device/.well-known/openid-configuration`, { skipBearerAuth: true }) - this.config = { - pairDeviceWithQRCodeSupported: response.data['pair_device_with_qrcode_supported'], - maximumAccountsPerDevice: response.data['maximum_accounts_per_device'], - allowedIdentificationProcesses: response.data['allowed_identification_processes'], - credentialFlowsSupported: response.data['credential_flows_supported'], - multipleAccountsSupported: response.data['multiple_accounts_supported'], - attestationTimeToLive: response.data['attestation_time_to_live'], - } - - this.endpoints = { - attestation: response.data['attestation_endpoint'], - issuer: response.data['issuer'], - authorization: response.data['authorization_endpoint'], - userInfo: response.data['userinfo_endpoint'], - deviceAuthorization: response.data['device_authorization_endpoint'], - jwksURI: response.data['jwks_uri'], - registration: response.data['registration_endpoint'], - clientMetadata: response.data['client_metadata_endpoint'], - savedServices: response.data['saved_services_endpoint'], - token: response.data['token_endpoint'], - credential: response.data['credential_endpoint'], - // TODO(bm): request backend team to add evidence and video endpoints to the response - evidence: `${this.baseURL}/evidence`, - video: `${this.baseURL}/video`, - } - } - - async fetchAccessToken(): Promise { - return withAccount(async () => { - if (!this.tokens?.refresh_token || this.isTokenExpired(this.tokens?.refresh_token)) { - // refresh token should be saved when a device is authorized with IAS - throw new Error('TODO: Register if refresh token is expired or not present') - } - - const tokenData = await this.getTokensForRefreshToken(this.tokens.refresh_token) - return tokenData - }) - } - - private isTokenExpired(token?: string): boolean { - let isExpired = true - // if no token is present, return that token is "expired" and fetch a new one - if (token) { - const decodedToken = jwtDecode(token) - const exp = decodedToken.exp ?? 0 - isExpired = Date.now() >= exp * 1000 - } - return isExpired - } - - private async handleRequest(config: InternalAxiosRequestConfig): Promise { - this.logger.info(`Handling request for URL: ${String(config.url)}`) - // skip processing if skipBearerAuth is set in the config - if (config.skipBearerAuth) { - return config - } - - if (!this.tokens || this.isTokenExpired(this.tokens.access_token)) { - this.tokens = await this.fetchAccessToken() - } - - if (this.tokens) { - config.headers.set('Authorization', `Bearer ${this.tokens.access_token}`) - } - - this.logger.debug(`Sending request to ${String(config.url)} with method ${String(config.method)}`, config as any) - - return config - } - - async getTokensForRefreshToken(refreshToken: string): Promise { - return withAccount(async (account) => { - const { issuer, clientID } = account - const tokenBody = await getRefreshTokenRequestBody(issuer, clientID, refreshToken) - const tokenResponse = await this.post(this.endpoints.token, tokenBody, { - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - skipBearerAuth: true, - }) - this.tokens = tokenResponse.data - - const bcsc_devices_count = await getDeviceCountFromIdToken(tokenResponse.data.id_token, this.logger) - - return { ...tokenResponse.data, bcsc_devices_count } - }) - } - - async get(url: string, config?: AxiosRequestConfig): Promise> { - return this.client.get(url, config) - } - - async post(url: string, data?: any, config?: AxiosRequestConfig): Promise> { - return this.client.post(url, data, config) - } - - async put(url: string, data?: any, config?: AxiosRequestConfig): Promise> { - return this.client.put(url, data, config) - } - - async delete(url: string, config?: AxiosRequestConfig): Promise> { - return this.client.delete(url, config) - } -} - -export default BCSCApiClient diff --git a/app/src/bcsc-theme/api/hooks/useApi.tsx b/app/src/bcsc-theme/api/hooks/useApi.tsx deleted file mode 100644 index 6346416..0000000 --- a/app/src/bcsc-theme/api/hooks/useApi.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useBCSCApiClient } from '@/bcsc-theme/hooks/useBCSCApiClient' -import { useMemo } from 'react' -import useAuthorizationApi from './useAuthorizationApi' -import useConfigApi from './useConfigApi' -import useEvidenceApi from './useEvidenceApi' -import useJwksApi from './useJwksApi' -import useMetadataApi from './useMetadataApi' -import usePairingApi from './usePairingApi' -import useRegistrationApi from './useRegistrationApi' -import useTokenApi from './useTokens' -import useUserApi from './useUserApi' -import useVideoCallApi from './useVideoCallApi' - -const useApi = () => { - const apiClient = useBCSCApiClient() - const config = useConfigApi(apiClient) - const pairing = usePairingApi(apiClient) - const registration = useRegistrationApi(apiClient) - const authorization = useAuthorizationApi(apiClient) - const token = useTokenApi(apiClient) - const user = useUserApi(apiClient) - const evidence = useEvidenceApi(apiClient) - const metadata = useMetadataApi(apiClient) - const jwks = useJwksApi(apiClient) - const video = useVideoCallApi(apiClient) - - return useMemo( - () => ({ - config, - pairing, - registration, - authorization, - token, - user, - evidence, - metadata, - jwks, - video, - }), - [config, pairing, registration, authorization, token, user, evidence, metadata, jwks, video] - ) -} - -export default useApi diff --git a/app/src/bcsc-theme/api/hooks/useAuthorizationApi.tsx b/app/src/bcsc-theme/api/hooks/useAuthorizationApi.tsx deleted file mode 100644 index f059061..0000000 --- a/app/src/bcsc-theme/api/hooks/useAuthorizationApi.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { ProvinceCode } from '@/bcsc-theme/utils/address-utils' -import { isAxiosError } from 'axios' -import { useCallback, useMemo } from 'react' -import { createDeviceSignedJWT } from 'react-native-bcsc-core' -import BCSCApiClient from '../client' -import { withAccount } from './withAccountGuard' -import { BCSCCardProcess } from '@/bcsc-theme/types/cards' - -const INVALID_REGISTRATION_REQUEST = 'invalid_registration_request' - -export interface VerifyInPersonResponseData { - process: BCSCCardProcess - user_code: string - device_code: string - verified_email: string - expires_in: number -} - -export interface VerifyUnknownBCSCResponseData { - process: BCSCCardProcess.NonBCSC - user_code: string - evidence_upload_uri: string - device_code: string - verification_options: string - verification_uri: string - expires_in: number -} - -export interface AuthorizeDeviceUnknownBCSCConfig { - firstName: string - lastName: string - birthdate: string - address: { - streetAddress: string - postalCode: string - city: string - province: ProvinceCode - } - gender?: 'male' | 'female' | 'unknown' - middleNames?: string // space delimited names -} - -const useAuthorizationApi = (apiClient: BCSCApiClient) => { - /** - * Authorize a device with a known BCSC card. - * - * TODO: fetch evidence API endpoint from this endpoint - * - * @see `https://citz-cdt.atlassian.net/wiki/spaces/BMS/pages/301615517/5.1.1+Evidence+API` - * @param {string} serial - BCSC serial number - * @param {Date} birthdate - Users birth date - * @returns {*} {VerifyInPersonResponseData | null} - */ - const authorizeDevice = useCallback( - async (serial: string, birthdate: Date): Promise => { - return withAccount(async (account) => { - const body = { - response_type: 'device_code', - client_id: account.clientID, - card_serial_number: serial, - birth_date: birthdate.toISOString().split('T')[0], - scope: 'openid profile address offline_access', - } - - apiClient.logger.info('useAuthorizationApi.authorizeDevice.body', body) - - try { - const { data } = await apiClient.post( - apiClient.endpoints.deviceAuthorization, - body, - { - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - skipBearerAuth: true, - } - ) - - return data - } catch (error) { - /** - * if already registered, return null for workflow convienience - * useful to be able to determine if the request failed or if the device - * has previously been registered - */ - if (isDeviceRegistered(error)) { - return null - } - - throw error - } - }) - }, - [apiClient] - ) - - /** - * Authorize a device with an unknown BCSC card. - * - * Note: This request will return null if called multiple times for the same device. - * First response will return the Verification response, which must be stored and persisted. - * - * @see `https://citz-cdt.atlassian.net/wiki/spaces/BMS/pages/301615517/5.1.1+Evidence+API` - * @param {AuthorizeDeviceUnknownBCSCConfig} config - Config including user information and address - * @returns {*} {VerifyUnknownBCSCResponseData | null} - Returns the response data or null if already registered - */ - const authorizeDeviceWithUnknownBCSC = useCallback( - async (config: AuthorizeDeviceUnknownBCSCConfig): Promise => { - return withAccount(async (account) => { - const body: Record = { - client_id: account.clientID, - response_type: 'device_code', - scope: 'openid profile address offline_access', - id_token_hint: await createDeviceSignedJWT({ - iss: account.clientID, - aud: account.issuer, - sub: account.clientID, - iat: Math.floor(Date.now() / 1000), - exp: Math.floor(Date.now() / 1000) + 60 * 10, // ten minutes - family_name: config.lastName, - given_name: config.firstName, - birthdate: config.birthdate, - address: { - street_address: config.address.streetAddress, - postal_code: config.address.postalCode, - locality: config.address.city, - region: config.address.province, - country: 'CA', - }, - // IAS requests 'unknown' when not specified - gender: config.gender ?? 'unknown', - // Omit middle name if not provided or empty string - middle_name: config.middleNames || undefined, - }), - } - - apiClient.logger.info('useAuthorizationApi.authorizeDeviceWithUnknownBCSC.body', body) - - try { - const { data } = await apiClient.post( - apiClient.endpoints.deviceAuthorization, - body, - { - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - skipBearerAuth: true, - } - ) - - return data - } catch (error) { - /** - * if already registered, return null for workflow convienience - * useful to be able to determine if the request failed or if the device - * has previously been registered - */ - if (isDeviceRegistered(error)) { - return null - } - - throw error - } - }) - }, - [apiClient] - ) - - return useMemo( - () => ({ - authorizeDevice, - authorizeDeviceWithUnknownBCSC, - }), - [authorizeDevice, authorizeDeviceWithUnknownBCSC] - ) -} - -export default useAuthorizationApi - -// Helper functions - -/** - * Checks if an error matches the structure of when a device is registered. - * - * @param {any} error - The error to check - * @returns {*} {boolean} - */ -function isDeviceRegistered(error: any): boolean { - return ( - isAxiosError(error) && - error.response?.status === 400 && - error.response?.data.error === INVALID_REGISTRATION_REQUEST && - // "client is in invalid statue" OR "client is in invalid state" - String(error.response?.data.error_description).includes('client is in invalid') - ) -} diff --git a/app/src/bcsc-theme/api/hooks/useConfigApi.tsx b/app/src/bcsc-theme/api/hooks/useConfigApi.tsx deleted file mode 100644 index 7e3396f..0000000 --- a/app/src/bcsc-theme/api/hooks/useConfigApi.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { useCallback, useMemo } from 'react' -import { Platform } from 'react-native' -import BCSCApiClient from '../client' - -export interface ServerStatusResponseData { - minVersion: string - minVersionMessage: string - supportedVersions: string[] - service: string - status: 'ok' | 'unavailable' - statusMessage?: string - contactLink: string - controlNumber: number -} - -export interface TermsOfUseResponseData { - version: string - date: string - html: string -} - -const useConfigApi = (apiClient: BCSCApiClient) => { - /** - * Fetches the server status from the IAS API. - * - * @returns {*} {Promise} A promise that resolves to the server status data. - */ - const getServerStatus = useCallback(async () => { - // this endpoint is not available through the .well-known/openid-configuration so it needs to be hardcoded - const { data } = await apiClient.get( - `${apiClient.baseURL}/cardtap/v3/status/${Platform.OS}/mobile_card`, - { - skipBearerAuth: true, // this endpoint does not require an access token - } - ) - return data - }, [apiClient]) - - const getTermsOfUse = useCallback(async () => { - // this endpoint is not available through the .well-known/openid-configuration so it needs to be hardcoded - const { data } = await apiClient.get(`${apiClient.baseURL}/cardtap/v3/terms`) - return data - }, [apiClient]) - - return useMemo( - () => ({ - getServerStatus, - getTermsOfUse, - }), - [getServerStatus, getTermsOfUse] - ) -} - -export default useConfigApi diff --git a/app/src/bcsc-theme/api/hooks/useEvidenceApi.tsx b/app/src/bcsc-theme/api/hooks/useEvidenceApi.tsx deleted file mode 100644 index 4b8b668..0000000 --- a/app/src/bcsc-theme/api/hooks/useEvidenceApi.tsx +++ /dev/null @@ -1,384 +0,0 @@ -import { BCState } from '@/store' -import { useStore } from '@bifold/core' -import { useCallback, useMemo } from 'react' -import { createPreVerificationJWT } from 'react-native-bcsc-core' -import BCSCApiClient from '../client' -import { withAccount } from './withAccountGuard' - -export interface VerificationPrompt { - id: number - prompt: string -} - -export interface VerificationPromptUploadPayload { - id: number - prompted_at: number // this provides the index/ order in which the prompt was given. 0 is the first prompt, 1 is the second prompt show ect. -} -export interface VerificationResponseData { - id: string - sha256: string - prompts: VerificationPrompt[] -} - -export interface SendVerificationPayload { - upload_uris: string[] - sha256: string -} - -export interface VerificationStatusResponseData { - id: string - status: 'pending' | 'verified' | 'cancelled' - status_message?: string - expires_in?: string - avg_turnaround_time_message?: string -} - -export interface VerificationPhotoUploadPayload { - label: string - content_type: string - content_length: number - date: number - sha256: string // hashed copy of the photo - filename?: string -} - -export interface VerificationVideoUploadPayload { - content_type: string - content_length: number - date: number // epoch timestamp in seconds - sha256: string // hashed copy of the video - duration: number // video duration in seconds - prompts: VerificationPromptUploadPayload[] - filename?: string -} - -export interface UploadEvidenceResponseData { - label: string - upload_uri: string -} - -export interface EvidenceImageSide { - image_side_name: 'FRONT_SIDE' | 'BACK_SIDE' - image_side_label: string - image_side_tip: string -} - -export interface EvidenceType { - evidence_type: string - has_photo: boolean - group: 'BRITISH COLUMBIA' | 'CANADA, OR OTHER LOCATION IN CANADA' | 'UNITED STATES' | 'OTHER COUNTRIES' - group_sort_order: number - sort_order: number - collection_order: 'FIRST' | 'SECOND' | 'BOTH' - document_reference_input_mask: string // a regex mask for ID document reference input, number only can indicate to use a number only keyboard - document_reference_label: string - document_reference_sample: string - image_sides: EvidenceImageSide[] - evidence_type_label: string -} -export interface EvidenceMetadataResponseData { - processes: { - process: 'IDIM L3 Remote Non-BCSC Identity Verification' | 'IDIM L3 Remote Non-photo BCSC Identity Verification' - evidence_types: EvidenceType[] - }[] -} -export interface EvidenceMetadataPayload { - type: string - number: string - images: VerificationPhotoUploadPayload[] - barcodes?: { - type: string - }[] -} - -const useEvidenceApi = (apiClient: BCSCApiClient) => { - const [store] = useStore() - - const _getDeviceCode = useCallback(() => { - const code = store.bcsc.deviceCode - if (!code) throw new Error('Device code is missing. Re install the app and setup try again.') - return code - }, [store.bcsc.deviceCode]) - - const getEvidenceMetadata = useCallback(async (): Promise => { - const { data } = await apiClient.get(`${apiClient.endpoints.evidence}/metadata`, { - // Evidence endpoints do not require a full access token - skipBearerAuth: true, - }) - return data - }, [apiClient]) - - // This needs ot be called for the process to start - const createVerificationRequest = useCallback(async (): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.post( - `${apiClient.endpoints.evidence}/v1/verifications`, - null, - { - headers: { - Authorization: `Bearer ${token}`, - }, - // Evidence endpoints do not require a full access token - skipBearerAuth: true, - } - ) - return data - }) - }, [_getDeviceCode, apiClient]) - - const uploadPhotoEvidenceMetadata = useCallback( - async (payload: VerificationPhotoUploadPayload): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.post( - `${apiClient.endpoints.evidence}/v1/photos`, - payload, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - const uploadVideoEvidenceMetadata = useCallback( - async (payload: VerificationVideoUploadPayload): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.post( - `${apiClient.endpoints.evidence}/v1/videos`, - payload, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const sendVerificationRequest = useCallback( - async ( - verificationRequestId: string, - payload: SendVerificationPayload - ): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.put( - `${apiClient.endpoints.evidence}/v1/verifications/${verificationRequestId}`, - payload, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const getVerificationRequestPrompts = useCallback( - async (verificationRequestId: string): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.get( - `${apiClient.endpoints.evidence}/v1/verifications/${verificationRequestId}/prompts`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const getVerificationRequestStatus = useCallback( - async (verificationRequestId: string): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.get( - `${apiClient.endpoints.evidence}/v1/verifications/${verificationRequestId}`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - // This is only valid once sendVerificationRequest has been called - // meaning the user has uploaded their photo, video and document evidence - // In the mean time the ID is 'held' for the time being and discarded if the user backs out - const cancelVerificationRequest = useCallback( - async (verificationRequestId: string): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.delete( - `${apiClient.endpoints.evidence}/v1/verifications/${verificationRequestId}`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const createEmailVerification = useCallback( - async (email: string): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.post( - `${apiClient.endpoints.evidence}/v1/emails`, - { email_address: email }, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const sendEmailVerificationCode = useCallback( - async (code: string, emailAddressId: string): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.put( - `${apiClient.endpoints.evidence}/v1/emails/${emailAddressId}`, - { - verification_code: code, - }, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const uploadPhotoEvidenceBinary = useCallback( - async (url: string, binaryData: any): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.put(url, binaryData, { - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'image/jpeg', - Accept: 'image/jpeg', - }, - skipBearerAuth: true, - }) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const uploadVideoEvidenceBinary = useCallback( - async (url: string, binaryData: any): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.put(url, binaryData, { - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'video/mp4', - Accept: 'video/mp4', - }, - skipBearerAuth: true, - }) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const sendEvidenceMetadata = useCallback( - async (payload: EvidenceMetadataPayload): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.post( - `${apiClient.endpoints.evidence}/v1/documents`, - payload, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - return useMemo( - () => ({ - createVerificationRequest, - uploadPhotoEvidenceMetadata, - uploadVideoEvidenceMetadata, - uploadPhotoEvidenceBinary, - uploadVideoEvidenceBinary, - sendVerificationRequest, - getVerificationRequestStatus, - cancelVerificationRequest, - getVerificationRequestPrompts, - createEmailVerification, - sendEmailVerificationCode, - sendEvidenceMetadata, - getEvidenceMetadata, - }), - [ - createVerificationRequest, - uploadPhotoEvidenceMetadata, - uploadVideoEvidenceMetadata, - uploadPhotoEvidenceBinary, - uploadVideoEvidenceBinary, - sendVerificationRequest, - getVerificationRequestStatus, - cancelVerificationRequest, - getVerificationRequestPrompts, - createEmailVerification, - sendEmailVerificationCode, - sendEvidenceMetadata, - getEvidenceMetadata, - ] - ) -} - -export default useEvidenceApi diff --git a/app/src/bcsc-theme/api/hooks/useFactoryReset.tsx b/app/src/bcsc-theme/api/hooks/useFactoryReset.tsx deleted file mode 100644 index 63f3c9d..0000000 --- a/app/src/bcsc-theme/api/hooks/useFactoryReset.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { DispatchAction, TOKENS, useServices, useStore } from '@bifold/core' -import useApi from './useApi' -import * as BcscCore from 'react-native-bcsc-core' -import { BCDispatchAction, BCState } from '@/store' -import { useCallback } from 'react' - -type FactoryResetResult = - | { - success: true - } - | { - success: false - error: Error - } - -/** - * Hook to perform a factory reset of the BCSC account and state. - * This should get the application as close as possible to a fresh install state. - * - * WARNING: This is a destructive action and will result in loss of all user data and settings. - * - * This includes: - * - Deleting the IAS account associated with the current clientID. - * - Removing the local account file. - * - Clearing the BCSC state in the global store. - * - Registering a new account to generate a new clientID and save it locally. - * - Logging out the user by updating the authentication state. - * - * @returns {Function} A function that performs the factory reset when called. - */ -export const useFactoryReset = () => { - const { registration } = useApi() - const [, dispatch] = useStore() - const [logger] = useServices([TOKENS.UTIL_LOGGER]) - - // TODO (MD): Consider adding a loading / status state to indicate progress of the factory reset operation - - /** - * Performs a factory reset of the BCSC account and state. - * - * @returns {Promise} A promise that resolves to the result of the factory reset operation. - */ - const factoryReset = useCallback(async (): Promise => { - try { - const account = await BcscCore.getAccount() - - if (!account) { - throw new Error('Local account not found for factory reset') - } - - // Delete IAS account - logger.info('FactoryReset: Deleting IAS account from server...') - const deleteIASAccount = await registration.deleteRegistration(account.clientID) - - if (!deleteIASAccount.success) { - throw new Error('IAS server account deletion failed') - } - - // Remove local account file - logger.info('FactoryReset: Removing local account file...') - await BcscCore.removeAccount() - - // Reset BCSC state to initial state - logger.info('FactoryReset: Clearing BCSC state...') - dispatch({ type: BCDispatchAction.CLEAR_BCSC }) - - logger.info('FactoryReset: Registering new account...') - await registration.register() - - logger.info('FactoryReset: Logging out user...') - dispatch({ type: DispatchAction.DID_AUTHENTICATE, payload: [false] }) - - // Factory reset complete - logger.info('FactoryReset: BCSC factory reset completed successfully') - return { success: true } - } catch (error) { - const factoryResetError = _formatFactoryResetError(error) - logger.error(`FactoryReset: ${factoryResetError.message}`, factoryResetError) - - return { success: false, error: factoryResetError } - } - }, [registration, dispatch, logger]) - - return factoryReset -} - -/** - * Formats errors that occur during the factory reset process. - * - * @param {unknown} error - The error to format. - * @returns {*} {Error} The formatted error. - */ -function _formatFactoryResetError(error: unknown): Error { - if (error instanceof Error) { - error.message = `FactoryResetError: ${error.message}` - return error - } - - return new Error(`FactoryResetUnknownError: ${JSON.stringify(error, null, 2)}`) -} diff --git a/app/src/bcsc-theme/api/hooks/useJwksApi.tsx b/app/src/bcsc-theme/api/hooks/useJwksApi.tsx deleted file mode 100644 index a223754..0000000 --- a/app/src/bcsc-theme/api/hooks/useJwksApi.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useCallback, useMemo } from 'react' -import BCSCApiClient from '../client' - -export interface JWK { - kty: string - e: string - kid: string - alg: string - n: string -} -export type Keys = JWK[] - -export type JWKResponseData = { - keys: Keys -} - -const useJwksApi = (apiClient: BCSCApiClient) => { - const getJwks = useCallback(async (): Promise => { - const { - data: { keys }, - } = await apiClient.get(apiClient.endpoints.jwksURI, { - skipBearerAuth: true, // this endpoint does not require an access token - }) - return keys - }, [apiClient]) - - const getFirstJwk = useCallback(async (): Promise => { - const keys = await getJwks() - return keys.length > 0 ? keys[0] : null - }, [getJwks]) - - return useMemo( - () => ({ - getJwks, - getFirstJwk, - }), - [getJwks, getFirstJwk] - ) -} - -export default useJwksApi diff --git a/app/src/bcsc-theme/api/hooks/useMetadataApi.tsx b/app/src/bcsc-theme/api/hooks/useMetadataApi.tsx deleted file mode 100644 index 99329c9..0000000 --- a/app/src/bcsc-theme/api/hooks/useMetadataApi.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useCallback, useMemo } from 'react' -import BCSCApiClient from '../client' - -export type Clients = ClientMetadata[] - -export type MetadataResponseData = { - clients: Clients -} - -/** - * Client metadata as returned by the IAS Client Metadata endpoint. - * - * @see https://citz-cdt.atlassian.net/wiki/spaces/BMS/pages/301574688/5.1+System+Interfaces#IAS-Client-Metadata-endpoint - */ -export interface ClientMetadata { - client_ref_id: string - client_name: string - client_uri: string - application_type: string - claims_description: string - suppress_confirmation_info: boolean - suppress_bookmark_prompt: boolean - allowed_identification_processes: string[] - bc_address: boolean - initiate_login_uri?: string - client_description?: string - policy_uri?: string - service_listing_sort_order?: number -} - -const useMetadataApi = (apiClient: BCSCApiClient) => { - /** - * Fetches the client metadata from the IAS Client Metadata endpoint. - * - * @return {*} {Promise} A promise that resolves to an array of client metadata objects. - */ - const getClientMetadata = useCallback(async (): Promise => { - const { - data: { clients }, - } = await apiClient.get(apiClient.endpoints.clientMetadata) - return clients - }, [apiClient]) - - /** - * Fetches the client metadata for the BCSC application specifically. - * - * @return {*} {Promise} A promise that resolves to the BCSC client metadata object, or null if not found. - */ - const getBCSCClientMetadata = useCallback(async (): Promise => { - const clients = await getClientMetadata() - const bcscClient = clients.find((client) => client.client_uri === `${apiClient.baseURL}/account/`) - - if (!bcscClient) { - throw new Error('BCSC client metadata not found') - } - - return bcscClient - }, [apiClient, getClientMetadata]) - - return useMemo( - () => ({ - getClientMetadata, - getBCSCClientMetadata, - }), - [getClientMetadata, getBCSCClientMetadata] - ) -} - -export default useMetadataApi diff --git a/app/src/bcsc-theme/api/hooks/usePairingApi.tsx b/app/src/bcsc-theme/api/hooks/usePairingApi.tsx deleted file mode 100644 index 089f182..0000000 --- a/app/src/bcsc-theme/api/hooks/usePairingApi.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { getNotificationTokens } from '@/bcsc-theme/utils/push-notification-tokens' -import { useCallback, useMemo } from 'react' -import { signPairingCode } from 'react-native-bcsc-core' -import BCSCApiClient from '../client' -import { withAccount } from './withAccountGuard' - -// There is no actual data response (just a 200) from the pairing code login endpoint, so we -// define a minimal response for DX and and TypeScript -export interface PairingCodeLoginResponseData { - success: boolean -} - -const usePairingApi = (apiClient: BCSCApiClient) => { - const loginByPairingCode = useCallback( - async (code: string) => { - return withAccount(async (account) => { - const { issuer, clientID } = account - const { fcmDeviceToken, apnsToken } = await getNotificationTokens() - const signedCode = await signPairingCode(code, issuer, clientID, fcmDeviceToken, apnsToken) - await apiClient.post( - // this endpoint is not available through the .well-known/openid-configuration so it needs to be hardcoded - `${apiClient.baseURL}/cardtap/v3/mobile/assertion`, - { assertion: signedCode }, - { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } - ) - return { success: true } - }) - }, - [apiClient] - ) - - return useMemo( - () => ({ - loginByPairingCode, - }), - [loginByPairingCode] - ) -} - -export default usePairingApi diff --git a/app/src/bcsc-theme/api/hooks/useRegistrationApi.tsx b/app/src/bcsc-theme/api/hooks/useRegistrationApi.tsx deleted file mode 100644 index 8247798..0000000 --- a/app/src/bcsc-theme/api/hooks/useRegistrationApi.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { useCallback, useMemo } from 'react' -import { AccountSecurityMethod, getAccount, getDynamicClientRegistrationBody, setAccount } from 'react-native-bcsc-core' - -import { getNotificationTokens } from '@/bcsc-theme/utils/push-notification-tokens' -import { BCDispatchAction, BCState } from '@/store' -import { useStore } from '@bifold/core' -import BCSCApiClient from '../client' - -export interface RegistrationResponseData { - client_id: string - client_id_issued_at: number - registration_access_token: string - registration_client_uri: string - redirect_uris: string[] - client_name: string - token_endpoint_auth_method: string - scope: string - grant_types: string[] - response_types: string[] - jwks: { - keys: Array<{ - kty: string - e: string - kid: string - alg: string - n: string - }> - } - request_object_signing_alg: string - userinfo_signed_response_alg: string - userinfo_encrypted_response_alg: string - userinfo_encrypted_response_enc: string - id_token_signed_response_alg: string - id_token_encrypted_response_alg: string - id_token_encrypted_response_enc: string - token_endpoint_auth_signing_alg: string - default_max_age: number - require_auth_time: boolean - default_acr_values: string[] -} - -// The registration API is a bit of a special case because it gets called during initialization, -// so its params are adjusted to account for an api client that may not be ready yet -const useRegistrationApi = (apiClient: BCSCApiClient | null, clientIsReady: boolean = true) => { - const [store, dispatch] = useStore() - - const register = useCallback(async () => { - if (!clientIsReady || !apiClient) { - throw new Error('BCSC client not ready for registration') - } - - const account = await getAccount() - // If an account already exists, we don't need to register again - if (account) return - - const { fcmDeviceToken, apnsToken } = await getNotificationTokens() - const body = await getDynamicClientRegistrationBody(fcmDeviceToken, apnsToken) - const { data } = await apiClient.post(apiClient.endpoints.registration, body, { - headers: { 'Content-Type': 'application/json' }, - skipBearerAuth: true, - }) - - dispatch({ - type: BCDispatchAction.UPDATE_REGISTRATION_ACCESS_TOKEN, - payload: [{ registrationAccessToken: data.registration_access_token }], - }) - - await setAccount({ - clientID: data.client_id, - issuer: apiClient.endpoints.issuer, - securityMethod: AccountSecurityMethod.PinNoDeviceAuth, - }) - return data - }, [clientIsReady, apiClient, dispatch]) - - const updateRegistration = useCallback( - async (clientId: string) => { - if (!clientIsReady || !apiClient) { - throw new Error('BCSC client not ready for registration update') - } - - const { fcmDeviceToken, apnsToken } = await getNotificationTokens() - const body = await getDynamicClientRegistrationBody(fcmDeviceToken, apnsToken) - const { data } = await apiClient.put( - `${apiClient.endpoints.registration}/${clientId}`, - body, - { headers: { 'Content-Type': 'application/json' } } - ) - return data - }, - [clientIsReady, apiClient] - ) - - const deleteRegistration = useCallback( - async (clientId: string) => { - if (!clientIsReady || !apiClient) { - throw new Error('BCSC client not ready for registration deletion') - } - - const registrationAccessToken = store.bcsc.registrationAccessToken - - const { status } = await apiClient.delete(`${apiClient.endpoints.registration}/${clientId}`, { - skipBearerAuth: true, - headers: { - Authorization: `Bearer ${registrationAccessToken}`, - }, - }) - - // 200 level status codes indicate success - return { success: status > 199 && status < 300 } - }, - [clientIsReady, apiClient, store.bcsc.registrationAccessToken] - ) - - return useMemo( - () => ({ - register, - updateRegistration, - deleteRegistration, - }), - [register, updateRegistration, deleteRegistration] - ) -} - -export default useRegistrationApi diff --git a/app/src/bcsc-theme/api/hooks/useTokens.tsx b/app/src/bcsc-theme/api/hooks/useTokens.tsx deleted file mode 100644 index 942a5b0..0000000 --- a/app/src/bcsc-theme/api/hooks/useTokens.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { getDeviceCountFromIdToken } from '@/bcsc-theme/utils/get-device-count' -import { useCallback, useMemo } from 'react' -import { getDeviceCodeRequestBody } from 'react-native-bcsc-core' -import BCSCApiClient, { TokenStatusResponseDataWithDeviceCount } from '../client' -import { withAccount } from './withAccountGuard' - -export interface TokenStatusResponseData { - access_token: string - expires_in: number - id_token: string - refresh_token: string - scope: string - token_type: string -} - -export interface BcscJwtPayload { - bcsc_devices_count?: number - // Add other BCSC-specific claims here as needed -} - -const useTokenApi = (apiClient: BCSCApiClient) => { - const checkDeviceCodeStatus = useCallback( - async (deviceCode: string, confirmationCode: string) => { - return withAccount(async (account) => { - const { clientID, issuer } = account - const body = await getDeviceCodeRequestBody(deviceCode, clientID, issuer, confirmationCode) - const { data } = await apiClient.post(apiClient.endpoints.token, body, { - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - skipBearerAuth: true, - }) - apiClient.tokens = data - - const bcsc_devices_count = await getDeviceCountFromIdToken(data.id_token, apiClient.logger) - return { ...data, bcsc_devices_count } - }) - }, - [apiClient] - ) - - return useMemo( - () => ({ - checkDeviceCodeStatus, - }), - [checkDeviceCodeStatus] - ) -} - -export default useTokenApi diff --git a/app/src/bcsc-theme/api/hooks/useUserApi.tsx b/app/src/bcsc-theme/api/hooks/useUserApi.tsx deleted file mode 100644 index 565d851..0000000 --- a/app/src/bcsc-theme/api/hooks/useUserApi.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { useCallback, useMemo } from 'react' -import { decodePayload } from 'react-native-bcsc-core' -import BCSCApiClient from '../client' -import { withAccount } from './withAccountGuard' - -export interface UserInfoResponseData { - identity_assurance_level: string - credential_reference: string - sub: string - transaction_identifier: string - given_name: string - family_name: string - display_name: string - birthdate: string - gender: string - address: { formatted: string } - picture: string - card_type: any - card_expiry: string -} - -const useUserApi = (apiClient: BCSCApiClient) => { - const getUserInfo = useCallback(async (): Promise => { - return withAccount(async () => { - const response = await apiClient.get(apiClient.endpoints.userInfo) - const userInfoString = await decodePayload(String(response.data)) - return JSON.parse(userInfoString) - }) - }, [apiClient]) - - const getPicture = useCallback( - async (pictureUrl: string): Promise => { - return withAccount(async () => { - const response = await apiClient.get(pictureUrl, { - responseType: 'arraybuffer', // get raw binary data - }) - - // convert to base64 - const base64String = btoa( - new Uint8Array(response.data).reduce((data, byte) => data + String.fromCharCode(byte), '') - ) - - // return as uri - return `data:image/jpeg;base64,${base64String}` - }) - }, - [apiClient] - ) - - return useMemo( - () => ({ - getUserInfo, - getPicture, - }), - [getUserInfo, getPicture] - ) -} - -export default useUserApi diff --git a/app/src/bcsc-theme/api/hooks/useVideoCallApi.tsx b/app/src/bcsc-theme/api/hooks/useVideoCallApi.tsx deleted file mode 100644 index 0f1c178..0000000 --- a/app/src/bcsc-theme/api/hooks/useVideoCallApi.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { BCState } from '@/store' -import { useStore } from '@bifold/core' -import { useCallback, useMemo } from 'react' -import { createPreVerificationJWT } from 'react-native-bcsc-core' -import BCSCApiClient from '../client' -import { withAccount } from './withAccountGuard' - -type SessionStatusType = 'session_granted' | 'session_not_granted' | 'session_failed' | 'session_ended' -type CallStatusType = - | 'call_ringing' - | 'call_media_pending' - | 'call_in_call' - | 'call_ended' - | 'call_error' - | 'call_dropped' - | 'call_reconnected' - -export interface VideoSession { - client_id: string - device_code: string - session_id: string - destination_host: string - room_name: string - room_alias: string - guest_pin: string - queue_position: number - status: SessionStatusType - status_date: number // seconds from epoch - created_date: number // seconds from epoch -} - -export interface VideoCall { - session_id: string - call_id: string - client_call_id: string - status: CallStatusType - status_date: number // seconds from epoch -} - -export interface VideoDestination { - max_active_sessions?: number - max_inactive_seconds?: number - number_of_agents?: number - destination_name: string - destination_priority: number - destination_host?: string -} - -export type VideoDestinations = VideoDestination[] - -export interface ServicePeriod { - start_day: string // e.g. "MONDAY" - end_day: string // e.g. "MONDAY" - start_time: string // e.g. "05:00" - end_time: string // e.g. "23:59" -} - -export interface ServiceHours { - time_zone: string - regular_service_periods: ServicePeriod[] - service_unavailable_periods: ServicePeriod[] -} - -const useVideoCallApi = (apiClient: BCSCApiClient) => { - const [store] = useStore() - - const _getDeviceCode = useCallback(() => { - const code = store.bcsc.deviceCode - if (!code) throw new Error('Device code is missing. Re install the app and try again.') - return code - }, [store.bcsc.deviceCode]) - - const createVideoSession = useCallback(async (): Promise => { - return withAccount(async (account) => { - const deviceCode = _getDeviceCode() - const body = { client_id: account.clientID, device_code: deviceCode } - const token = await createPreVerificationJWT(deviceCode, account.clientID) - const { data } = await apiClient.post(`${apiClient.endpoints.video}/v2/sessions/`, body, { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - }) - return data - }) - }, [_getDeviceCode, apiClient]) - - const updateVideoSessionStatus = useCallback( - async (sessionId: string, status: SessionStatusType): Promise => { - return withAccount(async (account) => { - const body = { status } - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.put( - `${apiClient.endpoints.video}/v2/sessions/${sessionId}`, - body, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const createVideoCall = useCallback( - async (sessionId: string, clientCallId: string, status: CallStatusType = 'call_ringing'): Promise => { - return withAccount(async (account) => { - const body = { - session_id: sessionId, - status: status, - client_call_id: clientCallId, - } - - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.post( - `${apiClient.endpoints.video}/v2/sessions/${sessionId}/calls/`, - body, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const updateVideoCallStatus = useCallback( - async (sessionId: string, clientCallId: string, status: CallStatusType): Promise => { - return withAccount(async (account) => { - const body = { status, client_call_id: clientCallId } - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.put( - `${apiClient.endpoints.video}/v2/sessions/${sessionId}/calls/${clientCallId}`, - body, - { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - } - ) - return data - }) - }, - [_getDeviceCode, apiClient] - ) - - const endVideoSession = useCallback( - async (sessionId: string): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - await apiClient.delete(`${apiClient.endpoints.video}/v2/sessions/${sessionId}`, { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - }) - }) - }, - [_getDeviceCode, apiClient] - ) - - const getVideoDestinations = useCallback(async (): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.get(`${apiClient.endpoints.video}/v2/destinations`, { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - }) - return data - }) - }, [_getDeviceCode, apiClient]) - - const getServiceHours = useCallback(async (): Promise => { - return withAccount(async (account) => { - const token = await createPreVerificationJWT(_getDeviceCode(), account.clientID) - const { data } = await apiClient.get(`${apiClient.endpoints.video}/v2/service_hours`, { - headers: { - Authorization: `Bearer ${token}`, - }, - skipBearerAuth: true, - }) - return data - }) - }, [_getDeviceCode, apiClient]) - - return useMemo( - () => ({ - createVideoSession, - updateVideoSessionStatus, - createVideoCall, - updateVideoCallStatus, - endVideoSession, - getVideoDestinations, - getServiceHours, - }), - [ - createVideoSession, - updateVideoSessionStatus, - createVideoCall, - updateVideoCallStatus, - endVideoSession, - getVideoDestinations, - getServiceHours, - ] - ) -} - -export default useVideoCallApi diff --git a/app/src/bcsc-theme/api/hooks/withAccountGuard.ts b/app/src/bcsc-theme/api/hooks/withAccountGuard.ts deleted file mode 100644 index ca6fd64..0000000 --- a/app/src/bcsc-theme/api/hooks/withAccountGuard.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { getAccount } from 'react-native-bcsc-core' - -/** - * This is a wrapper function to centralize checking for an account before executing a function. - * - * @param fn Function that `withAccount` will wrap, which requires an account to be present. - * @returns The executed function with the account passed as an argument. - */ -export const withAccount = async (fn: (account: any) => Promise): Promise => { - const account = await getAccount() - if (!account) { - throw new Error('No account found. Please register first.') - } - - return fn(account) -} diff --git a/app/src/bcsc-theme/api/workflow/key-rotation.workflow.ts b/app/src/bcsc-theme/api/workflow/key-rotation.workflow.ts deleted file mode 100644 index 842a14d..0000000 --- a/app/src/bcsc-theme/api/workflow/key-rotation.workflow.ts +++ /dev/null @@ -1,13 +0,0 @@ -export async function checkKeyStatus() { - // keys can be rotated for the following reasons: - // - 90 days have passed - // - key is not valid -} -export async function rotateKeys() { - // get current keys - // get new keys - // end date old keys - // save new keys to device - // save new keys to server - // check new keys work -} diff --git a/app/src/bcsc-theme/components/AppBanner.tsx b/app/src/bcsc-theme/components/AppBanner.tsx deleted file mode 100644 index e351f7b..0000000 --- a/app/src/bcsc-theme/components/AppBanner.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { ThemedText, testIdWithKey, useTheme } from '@bifold/core' -import React, { useEffect, useState } from 'react' -import { StyleSheet, TouchableOpacity, View } from 'react-native' -import Icon from 'react-native-vector-icons/MaterialCommunityIcons' -export interface AppBannerSectionProps { - title: string - type: 'error' | 'warning' | 'info' | 'success' - dismissible?: boolean - onDismiss?: () => void -} - -interface AppBannerProps { - messages: AppBannerSectionProps[] -} - -export const AppBanner: React.FC = ({ messages }) => { - const [bannerMessages, setBannerMessages] = useState(messages) - - const dismissBanner = (index: number) => { - setBannerMessages((prevMessages) => prevMessages.filter((_, i) => i !== index)) - } - - useEffect(() => { - setBannerMessages(messages) - }, [messages]) - - if (!bannerMessages || bannerMessages.length == 0) { - return null - } - - return ( - - {bannerMessages.map((message, index) => ( - dismissBanner(index)} - key={`${message.title}-${message.type}`} - dismissible={message.dismissible} - /> - ))} - - ) -} - -export const AppBannerSection: React.FC = ({ title, type, onDismiss, dismissible = true }) => { - const { Spacing, ColorPalette } = useTheme() - const styles = StyleSheet.create({ - container: { - backgroundColor: ColorPalette.brand.primary, - flexDirection: 'row', - alignItems: 'center', - flexWrap: 'wrap', - padding: Spacing.md, - flexShrink: 1, - }, - icon: { - marginRight: Spacing.md, - }, - }) - - const iconName = (type: string): string => { - switch (type) { - case 'error': - return 'alert-circle' - case 'warning': - return 'alert' - case 'info': - return 'information' - case 'success': - return 'check-circle' - default: - return 'information' - } - } - - const bannerColor = (type: string): string => { - switch (type) { - case 'error': - return '#CE3E39' - case 'warning': - return '#F8BB47' - case 'info': - return '#2E5DD7' - case 'success': - return '#42814A' - default: - return '#2E5DD7' - } - } - - // If more details are needed we might need to push the banner down to accommodate the extra information - return ( - { - if (dismissible && onDismiss) { - onDismiss() - } - }} - > - - - {title} - - - ) -} diff --git a/app/src/bcsc-theme/components/CodeScanningCamera.tsx b/app/src/bcsc-theme/components/CodeScanningCamera.tsx deleted file mode 100644 index 541f69f..0000000 --- a/app/src/bcsc-theme/components/CodeScanningCamera.tsx +++ /dev/null @@ -1,223 +0,0 @@ -import { QRScannerTorch, useTheme } from '@bifold/core' -import React, { useEffect, useRef, useState } from 'react' -import { ColorValue, StyleSheet, View, ViewStyle, useWindowDimensions } from 'react-native' -import { - Camera, - Code, - CodeScannerFrame, - CodeType, - useCameraDevice, - useCameraPermission, - useCodeScanner, -} from 'react-native-vision-camera' - -const overlayTint: ColorValue = 'rgba(0, 0, 0, 0.4)' - -export interface CodeScanningCameraProps { - codeTypes: CodeType[] - - /** - * Callback function called when a code is successfully scanned - * @param codes Array of scanned codes - * @param frame The camera frame information - */ - onCodeScanned: (codes: Code[], frame: CodeScannerFrame) => void - - /** - * Custom style for the camera container - */ - style?: ViewStyle - - /** - * Should camera permission be requested - * @default true - */ - autoRequestPermission?: boolean - - /** - * Which camera to use - * @default 'back' - */ - cameraType?: 'front' | 'back' -} - -const CodeScanningCamera: React.FC = ({ - codeTypes, - onCodeScanned, - style, - autoRequestPermission = true, - cameraType = 'back', -}) => { - const { ColorPalette } = useTheme() - const camera = useRef(null) - const [torchEnabled, setTorchEnabled] = useState(false) - const { width } = useWindowDimensions() - - const { hasPermission, requestPermission } = useCameraPermission() - const device = useCameraDevice(cameraType) - useEffect(() => { - if (!hasPermission) { - requestPermission() - } - }, [hasPermission, requestPermission]) - - const scanSize = Math.min(width - 80, 250) - - const getScanAreaDimensions = () => { - // if we want to use a different sized - // scan area for different code types, - // this can be adjusted to return different width/height - // depending on codetypes passed - - // the current value roughly matches the shape - // of either code on a dl/ combined card - const scanWidth = scanSize * 1.3 - const scanHeight = scanWidth / 5 - - return { - width: scanWidth, - height: scanHeight, - } - } - - const scanAreaDimensions = getScanAreaDimensions() - - const codeScanner = useCodeScanner({ - codeTypes, - onCodeScanned: (codes, frame) => { - if (codes.length > 0) { - onCodeScanned(codes, frame) - } - }, - }) - - useEffect(() => { - if (autoRequestPermission && !hasPermission) { - requestPermission() - } - }, [hasPermission, requestPermission, autoRequestPermission]) - - const toggleTorch = () => { - setTorchEnabled((prev) => !prev) - } - - const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: ColorPalette.brand.primaryBackground, - position: 'relative', - }, - camera: { - flex: 1, - }, - overlayContainer: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: 0, - justifyContent: 'center', - alignItems: 'center', - }, - overlayTop: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: '50%', - marginBottom: scanAreaDimensions.height / 2, - backgroundColor: overlayTint, - }, - overlayBottom: { - position: 'absolute', - top: '50%', - marginTop: scanAreaDimensions.height / 2, - left: 0, - right: 0, - bottom: 0, - backgroundColor: overlayTint, - }, - overlayLeft: { - position: 'absolute', - top: '50%', - marginTop: -scanAreaDimensions.height / 2, - left: 0, - right: '50%', - marginRight: scanAreaDimensions.width / 2, - height: scanAreaDimensions.height, - backgroundColor: overlayTint, - }, - overlayRight: { - position: 'absolute', - top: '50%', - marginTop: -scanAreaDimensions.height / 2, - right: 0, - left: '50%', - marginLeft: scanAreaDimensions.width / 2, - height: scanAreaDimensions.height, - backgroundColor: overlayTint, - }, - overlayOpening: { - position: 'absolute', - top: '50%', - left: '50%', - width: scanAreaDimensions.width, - height: scanAreaDimensions.height, - marginTop: -scanAreaDimensions.height / 2, - marginLeft: -scanAreaDimensions.width / 2, - borderColor: 'rgba(255, 255, 255, 0.8)', - borderWidth: 2, - }, - torchContainer: { - position: 'absolute', - bottom: 0, - right: 24, - zIndex: 10, - }, - }) - - if (!device || !hasPermission) { - // return placeholder view - return ( - - - - - - - - - - - - - ) - } - - return ( - - - {/* scan area cutout */} - - - - - - - - {/* reuse qrscannertorch from bifold */} - - - - - ) -} - -export default CodeScanningCamera diff --git a/app/src/bcsc-theme/components/HelpHeaderButton.tsx b/app/src/bcsc-theme/components/HelpHeaderButton.tsx deleted file mode 100644 index c379034..0000000 --- a/app/src/bcsc-theme/components/HelpHeaderButton.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { HelpCentreUrl } from '@/constants' -import { ButtonLocation, IconButton, testIdWithKey, TOKENS, useServices } from '@bifold/core' -import { useTranslation } from 'react-i18next' -import { BCSCScreens } from '../types/navigators' -import { useNavigation } from '@react-navigation/native' -import React, { useCallback } from 'react' -import { StackNavigationProp } from '@react-navigation/stack' - -type HelpHeaderButtonUrlProps = { - /** - * The URL of the Help Centre page to navigate to, opens in a webview. - * - * @type {HelpCentreUrl} - */ - helpCentreUrl: HelpCentreUrl - helpAction?: never -} - -type HelpHeaderButtonActionProps = { - /** - * Function to call when the help button is pressed. - * - * @returns {*} {void} - */ - helpAction: () => void - helpCentreUrl?: never -} - -type HelpHeaderButtonProps = HelpHeaderButtonUrlProps | HelpHeaderButtonActionProps - -/** - * Creates a Help Header Button component that can either navigate to a Help Centre URL or execute a custom action. - * - * Note: This is a curried function to avoid re-rendering in navigation stacks. - * - * @param {HelpHeaderButtonProps} helpHeaderProps - The properties for the Help Header Button. - * @returns {*} {React.FC} A React functional component that renders the Help Header Button. - */ -const createHelpHeaderButton = (helpHeaderProps: HelpHeaderButtonProps) => { - // Declared so that it has a display name for debugging purposes - const HeaderRight = () => { - const { t } = useTranslation() - const [logger] = useServices([TOKENS.UTIL_LOGGER]) - const navigation = useNavigation>() - - /** - * Handles navigation to the Help Centre webview. - * - * @param {string} helpCentreUrl - The URL of the Help Centre page to navigate to. - * @returns {*} {Promise} - */ - const handleHelpCentreNavigation = useCallback( - async (helpCentreUrl: HelpCentreUrl) => { - try { - navigation.navigate(BCSCScreens.WebView, { - url: helpCentreUrl, - title: t('HelpCentre.Title'), - }) - } catch (error) { - logger.error(`Error navigating to Help Center webview: ${error}`) - } - }, - [navigation, logger, t] - ) - - return ( - { - // If helpCentreUrl is provided, navigate to the Help Centre webview - if (helpHeaderProps.helpCentreUrl) { - handleHelpCentreNavigation(helpHeaderProps.helpCentreUrl) - return - } - - // Otherwise, execute the custom help action - helpHeaderProps.helpAction() - }} - /> - ) - } - return HeaderRight -} - -export default createHelpHeaderButton diff --git a/app/src/bcsc-theme/components/InputWithValidation.tsx b/app/src/bcsc-theme/components/InputWithValidation.tsx deleted file mode 100644 index a5c118f..0000000 --- a/app/src/bcsc-theme/components/InputWithValidation.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { testIdWithKey, useTheme } from '@bifold/core' -import { ThemedText } from '@bifold/core' -import { StyleProp, TextInput, TextStyle, View } from 'react-native' - -// NOTE (MD): This is a first pass at this component, I assume eventually we will need to modify this to -// accept number inputs as well. - -type InputWithValidationProps = { - id: string // unique input identifier - value: string - onChange: (value: string) => void - label: string - subtext?: string - error?: string - labelProps?: StyleProp - inputProps?: StyleProp - subtextProps?: StyleProp - errorProps?: StyleProp -} - -/** - * An input component which includes a label, input, subtext and error props. - * - * Note: This also includes the equivalent styling props for each section for customization. - * - * @param {InputWithValidationProps} props - Input props - * @returns {*} {JSX.Element} - */ -export const InputWithValidation: React.FC = (props: InputWithValidationProps) => { - const { Inputs, ColorPalette } = useTheme() - - return ( - - - {props.label} - - - { - props.onChange(e.nativeEvent.text) - }} - testID={testIdWithKey(`${props.id}-input`)} - /> - - {props.error ? ( - - {props.error} - - ) : null} - - {props.subtext && !props.error ? ( - - {props.subtext} - - ) : null} - - ) -} diff --git a/app/src/bcsc-theme/components/MaskedCamera.tsx b/app/src/bcsc-theme/components/MaskedCamera.tsx deleted file mode 100644 index 85368b4..0000000 --- a/app/src/bcsc-theme/components/MaskedCamera.tsx +++ /dev/null @@ -1,185 +0,0 @@ -import { MaskType, SVGOverlay, ThemedText, TOKENS, useServices, useTheme } from '@bifold/core' -import { useEffect, useRef, useState } from 'react' -import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native' -import { SafeAreaView } from 'react-native-safe-area-context' -import Icon from 'react-native-vector-icons/MaterialCommunityIcons' -import { Camera, useCameraDevice, useCameraPermission } from 'react-native-vision-camera' - -type MaskedCameraProps = { - navigation: any - cameraFace: 'front' | 'back' - cameraInstructions?: string - cameraLabel?: string - maskType?: MaskType - maskLineColor?: string - onPhotoTaken: (path: string) => void -} - -const MaskedCamera = ({ - navigation, - cameraInstructions, - cameraLabel, - maskLineColor, - maskType, - cameraFace = 'back', - onPhotoTaken, -}: MaskedCameraProps) => { - const device = useCameraDevice(cameraFace) - - const { Spacing, ColorPalette } = useTheme() - const { hasPermission, requestPermission } = useCameraPermission() - const [isActive, setIsActive] = useState(false) - const [torchOn, setTorchOn] = useState(false) - const cameraRef = useRef(null) - const [logger] = useServices([TOKENS.UTIL_LOGGER]) - const hasTorch = device?.hasTorch ?? false - - const styles = StyleSheet.create({ - container: { - flex: 1, - position: 'relative', - }, - camera: { - flex: 1, - }, - controlsContainer: { - flex: 1, - position: 'absolute', - bottom: 30, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: Spacing.lg, - }, - instructionText: { - backgroundColor: 'transparent', - position: 'absolute', - fontWeight: 'normal', - top: Spacing.lg, - left: 0, - right: 0, - zIndex: 5, - paddingHorizontal: Spacing.md, - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - captureButton: { - width: 70, - height: 70, - borderRadius: 35, - backgroundColor: 'white', - justifyContent: 'center', - alignItems: 'center', - }, - captureButtonInner: { - width: 64, - height: 64, - borderRadius: 30, - borderWidth: 2, - }, - }) - - useEffect(() => { - const checkPermissions = async () => { - if (!hasPermission) { - const permission = await requestPermission() - if (!permission) { - Alert.alert('Camera Permission Required', 'Please enable camera permission to take a photo.', [ - { text: 'OK', onPress: () => navigation.goBack() }, - ]) - return - } - } - } - - checkPermissions() - }, [hasPermission, requestPermission, navigation]) - - const toggleTorch = () => setTorchOn((prev: boolean) => !prev) - - if (!hasPermission) { - return ( - - - Camera permission required - - - ) - } - - if (!device) { - return ( - - - {`No ${device} camera available`} - - - ) - } - - const handleCancel = () => { - navigation.goBack() - } - const onError = (error: any) => { - logger.error(`Camera error: ${error}`) - Alert.alert('Camera Error', 'An error occurred while using the camera. Please try again.') - } - - const takePhoto = async () => { - try { - if (cameraRef.current && isActive) { - const photo = await cameraRef.current.takePhoto({ - flash: 'off', - }) - - onPhotoTaken(photo.path) - logger.info(`Photo taken and saved temporarily: ${photo.path}`) - } - } catch (error) { - logger.error(`Error taking photo: ${error}`) - Alert.alert('Error', 'Failed to take photo. Please try again.') - } - } - - return ( - - setIsActive(true)} - onError={onError} - torch={torchOn ? 'on' : 'off'} - /> - - - - {cameraLabel} - - - {cameraInstructions} - - - - - Cancel - - - - - {hasTorch ? ( - - - - ) : ( - - )} - - - ) -} - -export default MaskedCamera diff --git a/app/src/bcsc-theme/components/PhotoReview.tsx b/app/src/bcsc-theme/components/PhotoReview.tsx deleted file mode 100644 index 613099a..0000000 --- a/app/src/bcsc-theme/components/PhotoReview.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Button, ButtonType, testIdWithKey, useAnimatedComponents, useTheme } from '@bifold/core' -import React, { useState } from 'react' -import { Image, StyleSheet, View } from 'react-native' - -type PhotoReviewProps = { - photoPath: string - onAccept: () => Promise - onRetake: () => void -} - -const PhotoReview: React.FC = ({ photoPath, onAccept, onRetake }) => { - const { ColorPalette, Spacing } = useTheme() - const [loading, setLoading] = useState(false) - const { ButtonLoading } = useAnimatedComponents() - - const styles = StyleSheet.create({ - contentContainer: { - flexGrow: 1, - }, - controlsContainer: { - position: 'absolute', - bottom: 0, - left: 0, - right: 0, - padding: Spacing.md, - backgroundColor: ColorPalette.notification.popupOverlay, - }, - secondButton: { - marginTop: Spacing.sm, - }, - }) - - const handleAccept = async () => { - try { - setLoading(true) - await onAccept() - } finally { - setLoading(false) - } - } - return ( - - - - - - - - - - ) -} - -export default ManualPairing diff --git a/app/src/bcsc-theme/features/pairing/PairingConfirmation.tsx b/app/src/bcsc-theme/features/pairing/PairingConfirmation.tsx deleted file mode 100644 index ba2378e..0000000 --- a/app/src/bcsc-theme/features/pairing/PairingConfirmation.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { BCSCRootStackParams, BCSCScreens, BCSCStacks } from '@/bcsc-theme/types/navigators' -import { useTheme, ThemedText, Button, ButtonType, testIdWithKey } from '@bifold/core' -import { StackScreenProps } from '@react-navigation/stack' -import React from 'react' -import { StyleSheet, View } from 'react-native' -import { SafeAreaView } from 'react-native-safe-area-context' -import ServiceBookmarkButton from './components/ServiceBookmarkButton' -import { useTranslation } from 'react-i18next' -import { CommonActions } from '@react-navigation/native' - -type ManualPairingProps = StackScreenProps - -const ManualPairing: React.FC = ({ navigation, route }) => { - const { Spacing } = useTheme() - const { t } = useTranslation() - const { serviceName, serviceId } = route.params - - const styles = StyleSheet.create({ - container: { - flex: 1, - padding: Spacing.md, - justifyContent: 'space-between', - }, - contentContainer: { - flex: 1, - }, - controlsContainer: { - marginTop: 'auto', - }, - }) - - const onClose = () => { - navigation.dispatch( - CommonActions.reset({ - index: 0, - routes: [{ name: BCSCStacks.TabStack }], - }) - ) - } - - return ( - - - {"You're done in this app"} - - Go back to the device you started on to continue logging in to {serviceName}. - - - - - - - - ) -} - -export default EnterBirthdateScreen diff --git a/app/src/bcsc-theme/features/verify/IdentitySelectionScreen.tsx b/app/src/bcsc-theme/features/verify/IdentitySelectionScreen.tsx deleted file mode 100644 index 0a6cd0a..0000000 --- a/app/src/bcsc-theme/features/verify/IdentitySelectionScreen.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { ThemedText, useStore, useTheme } from '@bifold/core' -import { useCallback, useMemo } from 'react' -import { useTranslation } from 'react-i18next' -import { Image, Pressable, ScrollView, StyleSheet, View, useWindowDimensions } from 'react-native' -import { SafeAreaView } from 'react-native-safe-area-context' -import Icon from 'react-native-vector-icons/MaterialCommunityIcons' - -import { BCSCScreens, BCSCVerifyIdentityStackParams } from '@/bcsc-theme/types/navigators' -import { BCDispatchAction, BCState } from '@/store' -import ComboCardImage from '@assets/img/combo_card.png' -import NoPhotoCardImage from '@assets/img/no_photo_card.png' -import PhotoCardImage from '@assets/img/photo_card.png' -import { StackNavigationProp } from '@react-navigation/stack' -import TileButton, { TileButtonProps } from '../../components/TileButton' -import { BCSCCardType } from '../../types/cards' - -const COMBO_CARD = Image.resolveAssetSource(ComboCardImage).uri -const PHOTO_CARD = Image.resolveAssetSource(PhotoCardImage).uri -const NO_PHOTO_CARD = Image.resolveAssetSource(NoPhotoCardImage).uri - -type IdentitySelectionScreenProps = { - navigation: StackNavigationProp -} - -const IdentitySelectionScreen: React.FC = ({ - navigation, -}: IdentitySelectionScreenProps) => { - const { t } = useTranslation() - const { ColorPalette, Spacing } = useTheme() - const [, dispatch] = useStore() - const { width } = useWindowDimensions() - - const styles = StyleSheet.create({ - scrollView: { - flex: 1, - paddingHorizontal: Spacing.md, - backgroundColor: ColorPalette.brand.primaryBackground, - }, - heading: { - marginTop: Spacing.md, - marginBottom: Spacing.sm, - }, - description: { - marginBottom: Spacing.md, - }, - pageBreakSlot: { - position: 'relative', - flex: 1, - height: 8, - marginTop: 8, - }, - pageBreak: { - position: 'absolute', - width, - height: 8, - backgroundColor: ColorPalette.brand.secondaryBackground, - left: -Spacing.md, - }, - checkButton: { - marginVertical: Spacing.md, - flexWrap: 'wrap', - flex: 1, - }, - checkButtonText: { - color: ColorPalette.brand.primary, - }, - }) - - const onPressCombinedCard = useCallback(() => { - dispatch({ type: BCDispatchAction.UPDATE_CARD_TYPE, payload: [BCSCCardType.Combined] }) - navigation.navigate(BCSCScreens.SerialInstructions) - }, [dispatch, navigation]) - - const onPressPhotoCard = useCallback(() => { - dispatch({ type: BCDispatchAction.UPDATE_CARD_TYPE, payload: [BCSCCardType.Photo] }) - navigation.navigate(BCSCScreens.SerialInstructions) - }, [dispatch, navigation]) - - const onPressNoPhotoCard = useCallback(() => { - dispatch({ type: BCDispatchAction.UPDATE_CARD_TYPE, payload: [BCSCCardType.NonPhoto] }) - navigation.navigate(BCSCScreens.SerialInstructions) - }, [dispatch, navigation]) - - const onCheckForServicesCard = useCallback(() => { - // TODO: Implement - }, []) - - const onPressOtherID = useCallback(() => { - dispatch({ type: BCDispatchAction.UPDATE_CARD_TYPE, payload: [BCSCCardType.Other] }) - navigation.navigate(BCSCScreens.DualIdentificationRequired) - }, [dispatch, navigation]) - - const cardButtons = useMemo(() => { - return ( - [ - { - onPress: onPressCombinedCard, - testIDKey: 'CombinedCard', - accessibilityLabel: t('Unified.ChooseYourID.CombinedCard'), - actionText: t('Unified.ChooseYourID.CombinedCardActionText'), - description: t('Unified.ChooseYourID.CombinedCardDescription'), - imgSrc: { uri: COMBO_CARD }, - style: { marginBottom: Spacing.md }, - }, - { - onPress: onPressPhotoCard, - testIDKey: 'PhotoCard', - accessibilityLabel: t('Unified.ChooseYourID.PhotoCard'), - actionText: t('Unified.ChooseYourID.PhotoCardActionText'), - description: t('Unified.ChooseYourID.PhotoCardDescription'), - imgSrc: { uri: PHOTO_CARD }, - style: { marginBottom: Spacing.md }, - }, - { - onPress: onPressNoPhotoCard, - testIDKey: 'NoPhotoCard', - accessibilityLabel: t('Unified.ChooseYourID.NoPhotoCard'), - actionText: t('Unified.ChooseYourID.NoPhotoCardActionText'), - description: t('Unified.ChooseYourID.NoPhotoCardDescription'), - imgSrc: { uri: NO_PHOTO_CARD }, - style: { marginBottom: Spacing.md }, - }, - ] as TileButtonProps[] - ).map((props, i) => ) - }, [onPressCombinedCard, onPressPhotoCard, onPressNoPhotoCard, t, Spacing]) - - return ( - - - - {t('Unified.ChooseYourID.WhatCardDoYou')} - - {t('Unified.ChooseYourID.SomePeopleStillCallIt')} - {cardButtons} - - - - - {t('Unified.ChooseYourID.DontHaveOne')} - - {t('Unified.ChooseYourID.CheckBefore')} - - - {t('Unified.ChooseYourID.CheckIfIHave') + ' '} - - - - - - - ) -} - -export default IdentitySelectionScreen diff --git a/app/src/bcsc-theme/features/verify/ManualSerialScreen.tsx b/app/src/bcsc-theme/features/verify/ManualSerialScreen.tsx deleted file mode 100644 index 819737e..0000000 --- a/app/src/bcsc-theme/features/verify/ManualSerialScreen.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { - Button, - ButtonType, - KeyboardView, - LimitedTextInput, - testIdWithKey, - ThemedText, - useStore, - useTheme, -} from '@bifold/core' -import React, { useCallback, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { Image, StyleSheet, useWindowDimensions, View } from 'react-native' - -import { BCDispatchAction, BCState } from '@/store' -import { StackNavigationProp } from '@react-navigation/stack' -import { BCSCScreens, BCSCVerifyIdentityStackParams } from '@/bcsc-theme/types/navigators' -import SerialHighlightImage from '@assets/img/highlight_serial_barcode.png' - -const SERIAL_HIGHLIGHT_IMAGE = Image.resolveAssetSource(SerialHighlightImage).uri - -const twoThirds = 0.67 -const maxSerialNumberLength = 15 - -type ErrorState = { - visible: boolean - description: string -} - -type ManualSerialScreenProps = { - navigation: StackNavigationProp -} - -const ManualSerialScreen: React.FC = ({ navigation }: ManualSerialScreenProps) => { - const { t } = useTranslation() - const { ColorPalette, Spacing } = useTheme() - const [store, dispatch] = useStore() - const [serial, setSerial] = useState(store.bcsc.serial ?? '') - const { width } = useWindowDimensions() - const [errorState, setErrorState] = useState({ - visible: false, - description: '', - }) - - const styles = StyleSheet.create({ - screenContainer: { - flex: 1, - backgroundColor: ColorPalette.brand.primaryBackground, - padding: Spacing.md, - justifyContent: 'space-between', - }, - contentContainer: { - flexDirection: 'column', - }, - image: { - width: width - Spacing.md * 2, - height: (width - Spacing.md * 2) * twoThirds, - marginBottom: Spacing.md, - }, - error: { - color: ColorPalette.semantic.error, - marginBottom: Spacing.sm, - }, - - // below used as helpful label for view, no properties needed atp - controlsContainer: {}, - - buttonContainer: { - width: '100%', - }, - }) - - const handleChangeText = useCallback((text: string) => { - setSerial(text.replace(/\s/g, '')) - }, []) - - const onContinuePressed = useCallback(() => { - if (serial.length < 1) { - setErrorState({ - description: t('Unified.ManualSerial.EmptySerialError'), - visible: true, - }) - return - } - - if (serial.length > maxSerialNumberLength) { - setErrorState({ - description: t('Unified.ManualSerial.CharCountError'), - visible: true, - }) - return - } - - dispatch({ type: BCDispatchAction.UPDATE_SERIAL, payload: [serial] }) - navigation.navigate(BCSCScreens.EnterBirthdate) - }, [serial, t, dispatch, navigation]) - - return ( - - - - - - {errorState.visible ? ( - - {errorState.description} - - ) : null} - {t('Unified.ManualSerial.InputSubText')} - - - - - - - - - - {cardType !== BCSCCardType.Other ? ( - - - - - Card serial number: {store.bcsc.serial ?? store.bcsc.additionalEvidenceData[0]?.documentNumber ?? 'N/A'} - - - - ) -} -export default VerifyInPersonScreen diff --git a/app/src/bcsc-theme/features/verify/live-call/BeforeYouCallScreen.tsx b/app/src/bcsc-theme/features/verify/live-call/BeforeYouCallScreen.tsx deleted file mode 100644 index f39125f..0000000 --- a/app/src/bcsc-theme/features/verify/live-call/BeforeYouCallScreen.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { BCSCScreens, BCSCVerifyIdentityStackParams } from '@bcsc-theme/types/navigators' -import { Button, ButtonType, testIdWithKey, ThemedText, useTheme } from '@bifold/core' -import { useNetInfo } from '@react-native-community/netinfo' -import { RouteProp } from '@react-navigation/native' -import { StackNavigationProp } from '@react-navigation/stack' -import { useMemo } from 'react' -import { useTranslation } from 'react-i18next' -import { ScrollView, StyleSheet, View } from 'react-native' -import { SafeAreaView } from 'react-native-safe-area-context' - -type BeforeYouCallScreenProps = { - navigation: StackNavigationProp - route: RouteProp -} - -const BeforeYouCallScreen = ({ navigation, route }: BeforeYouCallScreenProps) => { - const { ColorPalette, Spacing } = useTheme() - const { type: networkType, isConnected } = useNetInfo() - const { t } = useTranslation() - const { formattedHours } = route.params || {} - - // Use the passed formatted hours or fallback to default - const hoursText = formattedHours || 'Monday to Friday\n7:30am - 5:00pm Pacific Time' - const isCellular = useMemo(() => networkType === 'cellular' && isConnected === true, [networkType, isConnected]) - - const styles = StyleSheet.create({ - pageContainer: { - flex: 1, - justifyContent: 'space-between', - backgroundColor: ColorPalette.brand.primaryBackground, - padding: Spacing.md, - }, - contentContainer: { - flexGrow: 1, - }, - controlsContainer: { - gap: Spacing.sm, - marginTop: Spacing.md, - }, - }) - - const onPressContinue = async () => { - navigation.navigate(BCSCScreens.TakePhoto, { - forLiveCall: true, - deviceSide: 'front', - cameraInstructions: '', - cameraLabel: '', - }) - } - - const onPressAssistance = () => { - // TODO (bm): webview or external link here presumeably - } - - return ( - - - - {t('Unified.VideoCall.BeforeYouCallTitle')} - - {t('Unified.VideoCall.WiFiRecommended')} - - {isCellular ? t('Unified.VideoCall.CellularNetworkWarning') : ''} - {t('Unified.VideoCall.StandardDataCharges')} - - - - {t('Unified.VideoCall.FindPrivatePlace')} - - {t('Unified.VideoCall.MakeSureOnlyYou')} - - - {t('Unified.VideoCall.HoursOfService')} - - {hoursText} - - {t('Unified.VideoCall.ContactCentrePrivacy')} - - {t(`Unified.VideoCall.PrivacyNotice`)} - {t(`Unified.VideoCall.PrivacyContactInfo`)} - - - - - {t('Unified.VideoCall.VerifyNotComplete.TroubleshootingTips')} - - - - - - - ) -} - -export default InformationRequiredScreen diff --git a/app/src/bcsc-theme/features/verify/send-video/PendingReviewScreen.tsx b/app/src/bcsc-theme/features/verify/send-video/PendingReviewScreen.tsx deleted file mode 100644 index 1450687..0000000 --- a/app/src/bcsc-theme/features/verify/send-video/PendingReviewScreen.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { BCSCScreens, BCSCVerifyIdentityStackParams } from '@/bcsc-theme/types/navigators' -import { Button, ButtonType, testIdWithKey, ThemedText, useTheme } from '@bifold/core' -import { StackNavigationProp } from '@react-navigation/stack' -import { StyleSheet, View } from 'react-native' -import { SafeAreaView } from 'react-native-safe-area-context' - -type PendingReviewScreenProps = { - navigation: StackNavigationProp -} - -const PendingReviewScreen = ({ navigation }: PendingReviewScreenProps) => { - const { ColorPalette, Spacing } = useTheme() - - const styles = StyleSheet.create({ - pageContainer: { - flex: 1, - justifyContent: 'space-between', - backgroundColor: ColorPalette.brand.primaryBackground, - padding: Spacing.md, - }, - contentContainer: { - flex: 1, - }, - bulletContainer: { - flexDirection: 'row', - marginBottom: Spacing.md, - }, - bullet: { - marginRight: Spacing.xs, - }, - controlsContainer: { - marginTop: 'auto', - }, - }) - - return ( - - - {`Request pending review`} - {`We review requests:`} - - {'\u2022'} - Monday to Friday, 9am to 5pm - - - {'\u2022'} - In the order they're received - - - Usually, we review requests within 2 business days. During busy periods, it may take longer. - - - After it's reviewed, you will get an email if your provided your email. - - Do not resend your video. If you do, your request will go to the back of the queue. - - - - -