diff --git a/.cursorignore b/.cursorignore index a0bf475fc..fd484e738 100644 --- a/.cursorignore +++ b/.cursorignore @@ -244,7 +244,6 @@ app/src/assets/animations/*.json app/src/assets/fonts/ # Yarn configuration -.yarnrc.yml **/.yarn/ # Certificate generation config diff --git a/.github/workflows/mobile-e2e.yml b/.github/workflows/mobile-e2e.yml index a976ff56a..2bdb5de48 100644 --- a/.github/workflows/mobile-e2e.yml +++ b/.github/workflows/mobile-e2e.yml @@ -107,7 +107,7 @@ jobs: - name: Build dependencies (outside emulator) run: | echo "Building dependencies..." - yarn workspace @selfxyz/mobile-app run build:deps --silent || { echo "❌ Dependency build failed"; exit 1; } + yarn workspace @selfxyz/mobile-app run build:deps || { echo "❌ Dependency build failed"; exit 1; } echo "✅ Dependencies built successfully" - name: Clone android-passport-reader uses: ./.github/actions/clone-android-passport-reader @@ -293,7 +293,7 @@ jobs: - name: Build dependencies (outside main flow) run: | echo "Building dependencies..." - yarn workspace @selfxyz/mobile-app run build:deps --silent || { echo "❌ Dependency build failed"; exit 1; } + yarn workspace @selfxyz/mobile-app run build:deps || { echo "❌ Dependency build failed"; exit 1; } echo "✅ Dependencies built successfully" - name: Install iOS dependencies run: | diff --git a/.github/workflows/mobile-sdk-demo-ci.yml b/.github/workflows/mobile-sdk-demo-ci.yml index c53e6da9a..601622861 100644 --- a/.github/workflows/mobile-sdk-demo-ci.yml +++ b/.github/workflows/mobile-sdk-demo-ci.yml @@ -3,7 +3,7 @@ name: Mobile SDK Demo CI on: pull_request: paths: - - "packages/mobile-sdk-alpha/demo-app/**" + - "packages/mobile-sdk-demo/**" - ".github/workflows/mobile-sdk-demo-ci.yml" - ".github/actions/**" @@ -18,9 +18,14 @@ jobs: node-version-file: .nvmrc - name: Install Dependencies uses: ./.github/actions/yarn-install + - name: Build dependencies (topological) + shell: bash + run: | + # Build demo app and all its transitive workspace deps in the correct order + yarn workspaces foreach -R -t --from mobile-sdk-demo run build - name: Run demo app tests run: | - yarn workspace demo-app test + yarn workspace mobile-sdk-demo test - name: Build demo app run: | - yarn workspace demo-app build + yarn build:demo diff --git a/.gitignore b/.gitignore index e41461e97..77a53455a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ showcase output/* *.tsbuildinfo .yarnrc.yml +.giga/tasks/* package-lock.json # CI-generated tarballs (don't commit these!) diff --git a/.yarnrc.yml b/.yarnrc.yml index 334e9d608..8ca323607 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,4 +1,5 @@ nodeLinker: node-modules +nmHoistingLimits: workspaces enableGlobalCache: true enableScripts: true checksumBehavior: "update" diff --git a/app/Gemfile.lock b/app/Gemfile.lock index 511c88750..f85fa2570 100644 --- a/app/Gemfile.lock +++ b/app/Gemfile.lock @@ -25,8 +25,8 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.4.0) - aws-partitions (1.1161.0) - aws-sdk-core (3.232.0) + aws-partitions (1.1166.0) + aws-sdk-core (3.233.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) @@ -34,10 +34,10 @@ GEM bigdecimal jmespath (~> 1, >= 1.6.1) logger - aws-sdk-kms (1.112.0) + aws-sdk-kms (1.113.0) aws-sdk-core (~> 3, >= 3.231.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.199.0) + aws-sdk-s3 (1.199.1) aws-sdk-core (~> 3, >= 3.231.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -225,7 +225,7 @@ GEM i18n (1.14.7) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.13.2) + json (2.15.0) jwt (2.10.2) base64 logger (1.7.0) diff --git a/app/declarations.d.ts b/app/declarations.d.ts index c5f8149be..c62b3c171 100644 --- a/app/declarations.d.ts +++ b/app/declarations.d.ts @@ -19,3 +19,5 @@ declare module '*.svg' { const content: React.FC; export default content; } + +declare module 'react-native-svg-circle-country-flags'; diff --git a/app/ios/Podfile b/app/ios/Podfile index f859c85c2..8aa6f7023 100755 --- a/app/ios/Podfile +++ b/app/ios/Podfile @@ -27,16 +27,16 @@ if linkage != nil end def using_https_git_auth? - begin - # backticks run command in shell and capture stdout, 2>&1 captures stderr as well - auth_data = `gh auth status 2>&1` - auth_data.include?('Logged in to github.com account') && - auth_data.include?('Git operations protocol: https') - rescue => e - puts 'gh auth status failed, assuming no HTTPS auth -- will try SSH' - false - end + begin + # backticks run command in shell and capture stdout, 2>&1 captures stderr as well + auth_data = `gh auth status 2>&1` + auth_data.include?("Logged in to github.com account") && + auth_data.include?("Git operations protocol: https") + rescue => e + puts "gh auth status failed, assuming no HTTPS auth -- will try SSH" + false end +end target "Self" do config = use_native_modules! @@ -72,7 +72,7 @@ target "Self" do pod "lottie-ios" pod "SwiftQRScanner", :git => "https://github.com/vinodiOS/SwiftQRScanner" pod "Mixpanel-swift", "~> 5.0.0" - pod "RNReactNativeHapticFeedback", :path => "../../node_modules/react-native-haptic-feedback", :modular_headers => true + # RNReactNativeHapticFeedback is handled by autolinking use_react_native!( :path => config[:reactNativePath], @@ -85,7 +85,6 @@ target "Self" do pod "Firebase", :modular_headers => true pod "FirebaseCore", :modular_headers => true pod "FirebaseCoreInternal", :modular_headers => true - pod "FirebaseAnalytics", :modular_headers => true pod "GoogleUtilities", :modular_headers => true pod "FirebaseMessaging" @@ -165,7 +164,7 @@ target "Self" do if File.exist?(qkCutoutView) # Ensure the file is writable system("chmod u+w #{qkCutoutView}") - + text = File.read(qkCutoutView) # Only modify if the line exists and is not already commented if text.include?("addBorderAroundCutout()") && !text.include?("// addBorderAroundCutout()") diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index 198b79c00..b8e7323ed 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -2125,109 +2125,108 @@ PODS: - Yoga (0.0.0) DEPENDENCIES: - - boost (from `../../node_modules/react-native/third-party-podspecs/boost.podspec`) - - 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`) + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - 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`) - Firebase - - FirebaseAnalytics - FirebaseCore - FirebaseCoreInternal - FirebaseMessaging - - fmt (from `../../node_modules/react-native/third-party-podspecs/fmt.podspec`) - - glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`) + - 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`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - lottie-ios - - lottie-react-native (from `../../node_modules/lottie-react-native`) + - lottie-react-native (from `../node_modules/lottie-react-native`) - Mixpanel-swift (~> 5.0.0) - - "mobile-sdk-alpha (from `../../node_modules/@selfxyz/mobile-sdk-alpha`)" + - "mobile-sdk-alpha (from `../node_modules/@selfxyz/mobile-sdk-alpha`)" - "NFCPassportReader (from `git@github.com:selfxyz/NFCPassportReader.git`, commit `9eff7c4e3a9037fdc1e03301584e0d5dcf14d76b`)" - QKMRZScanner - - 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`) - - 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-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-app-auth (from `../../node_modules/react-native-app-auth`) - - react-native-biometrics (from `../../node_modules/react-native-biometrics`) - - "react-native-blur (from `../../node_modules/@react-native-community/blur`)" - - react-native-cloud-storage (from `../../node_modules/react-native-cloud-storage`) - - react-native-get-random-values (from `../../node_modules/react-native-get-random-values`) - - "react-native-netinfo (from `../../node_modules/@react-native-community/netinfo`)" - - react-native-nfc-manager (from `../../node_modules/react-native-nfc-manager`) - - react-native-safe-area-context (from `../../node_modules/react-native-safe-area-context`) - - react-native-sqlite-storage (from `../../node_modules/react-native-sqlite-storage`) - - 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-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`) + - 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`) + - 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-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-app-auth (from `../node_modules/react-native-app-auth`) + - react-native-biometrics (from `../node_modules/react-native-biometrics`) + - "react-native-blur (from `../node_modules/@react-native-community/blur`)" + - react-native-cloud-storage (from `../node_modules/react-native-cloud-storage`) + - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) + - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" + - react-native-nfc-manager (from `../node_modules/react-native-nfc-manager`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - react-native-sqlite-storage (from `../node_modules/react-native-sqlite-storage`) + - 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-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`) - ReactCodegen (from `build/generated/ios`) - - ReactCommon/turbomodule/core (from `../../node_modules/react-native/ReactCommon`) - - "RNCAsyncStorage (from `../../node_modules/@react-native-async-storage/async-storage`)" - - "RNCClipboard (from `../../node_modules/@react-native-clipboard/clipboard`)" - - RNDeviceInfo (from `../../node_modules/react-native-device-info`) - - "RNFBApp (from `../../node_modules/@react-native-firebase/app`)" - - "RNFBMessaging (from `../../node_modules/@react-native-firebase/messaging`)" - - "RNFBRemoteConfig (from `../../node_modules/@react-native-firebase/remote-config`)" - - RNGestureHandler (from `../../node_modules/react-native-gesture-handler`) - - RNKeychain (from `../../node_modules/react-native-keychain`) - - RNLocalize (from `../../node_modules/react-native-localize`) - - RNReactNativeHapticFeedback (from `../../node_modules/react-native-haptic-feedback`) - - RNScreens (from `../../node_modules/react-native-screens`) - - "RNSentry (from `../../node_modules/@sentry/react-native`)" - - RNSVG (from `../../node_modules/react-native-svg`) - - "segment-analytics-react-native (from `../../node_modules/@segment/analytics-react-native`)" - - "sovran-react-native (from `../../node_modules/@segment/sovran-react-native`)" + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" + - "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)" + - RNDeviceInfo (from `../node_modules/react-native-device-info`) + - "RNFBApp (from `../node_modules/@react-native-firebase/app`)" + - "RNFBMessaging (from `../node_modules/@react-native-firebase/messaging`)" + - "RNFBRemoteConfig (from `../node_modules/@react-native-firebase/remote-config`)" + - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) + - RNKeychain (from `../node_modules/react-native-keychain`) + - RNLocalize (from `../node_modules/react-native-localize`) + - RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`) + - RNScreens (from `../node_modules/react-native-screens`) + - "RNSentry (from `../node_modules/@sentry/react-native`)" + - RNSVG (from `../node_modules/react-native-svg`) + - "segment-analytics-react-native (from `../node_modules/@segment/analytics-react-native`)" + - "sovran-react-native (from `../node_modules/@segment/sovran-react-native`)" - SwiftQRScanner (from `https://github.com/vinodiOS/SwiftQRScanner`) - - Yoga (from `../../node_modules/react-native/ReactCommon/yoga`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: trunk: @@ -2259,191 +2258,191 @@ SPEC REPOS: EXTERNAL SOURCES: boost: - :podspec: "../../node_modules/react-native/third-party-podspecs/boost.podspec" + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" DoubleConversion: - :podspec: "../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" fast_float: - :podspec: "../../node_modules/react-native/third-party-podspecs/fast_float.podspec" + :podspec: "../node_modules/react-native/third-party-podspecs/fast_float.podspec" FBLazyVector: - :path: "../../node_modules/react-native/Libraries/FBLazyVector" + :path: "../node_modules/react-native/Libraries/FBLazyVector" fmt: - :podspec: "../../node_modules/react-native/third-party-podspecs/fmt.podspec" + :podspec: "../node_modules/react-native/third-party-podspecs/fmt.podspec" glog: - :podspec: "../../node_modules/react-native/third-party-podspecs/glog.podspec" + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: - :podspec: "../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" :tag: hermes-2024-11-12-RNv0.76.2-5b4aa20c719830dcf5684832b89a6edb95ac3d64 lottie-react-native: - :path: "../../node_modules/lottie-react-native" + :path: "../node_modules/lottie-react-native" mobile-sdk-alpha: - :path: "../../node_modules/@selfxyz/mobile-sdk-alpha" + :path: "../node_modules/@selfxyz/mobile-sdk-alpha" NFCPassportReader: :commit: 9eff7c4e3a9037fdc1e03301584e0d5dcf14d76b :git: "git@github.com:selfxyz/NFCPassportReader.git" RCT-Folly: - :podspec: "../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTDeprecation: - :path: "../../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" + :path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" RCTRequired: - :path: "../../node_modules/react-native/Libraries/Required" + :path: "../node_modules/react-native/Libraries/Required" RCTTypeSafety: - :path: "../../node_modules/react-native/Libraries/TypeSafety" + :path: "../node_modules/react-native/Libraries/TypeSafety" React: - :path: "../../node_modules/react-native/" + :path: "../node_modules/react-native/" React-callinvoker: - :path: "../../node_modules/react-native/ReactCommon/callinvoker" + :path: "../node_modules/react-native/ReactCommon/callinvoker" React-Core: - :path: "../../node_modules/react-native/" + :path: "../node_modules/react-native/" React-CoreModules: - :path: "../../node_modules/react-native/React/CoreModules" + :path: "../node_modules/react-native/React/CoreModules" React-cxxreact: - :path: "../../node_modules/react-native/ReactCommon/cxxreact" + :path: "../node_modules/react-native/ReactCommon/cxxreact" React-debug: - :path: "../../node_modules/react-native/ReactCommon/react/debug" + :path: "../node_modules/react-native/ReactCommon/react/debug" React-defaultsnativemodule: - :path: "../../node_modules/react-native/ReactCommon/react/nativemodule/defaults" + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults" React-domnativemodule: - :path: "../../node_modules/react-native/ReactCommon/react/nativemodule/dom" + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom" React-Fabric: - :path: "../../node_modules/react-native/ReactCommon" + :path: "../node_modules/react-native/ReactCommon" React-FabricComponents: - :path: "../../node_modules/react-native/ReactCommon" + :path: "../node_modules/react-native/ReactCommon" React-FabricImage: - :path: "../../node_modules/react-native/ReactCommon" + :path: "../node_modules/react-native/ReactCommon" React-featureflags: - :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" + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags" React-graphics: - :path: "../../node_modules/react-native/ReactCommon/react/renderer/graphics" + :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" React-hermes: - :path: "../../node_modules/react-native/ReactCommon/hermes" + :path: "../node_modules/react-native/ReactCommon/hermes" React-idlecallbacksnativemodule: - :path: "../../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" React-ImageManager: - :path: "../../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" + :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" React-jserrorhandler: - :path: "../../node_modules/react-native/ReactCommon/jserrorhandler" + :path: "../node_modules/react-native/ReactCommon/jserrorhandler" React-jsi: - :path: "../../node_modules/react-native/ReactCommon/jsi" + :path: "../node_modules/react-native/ReactCommon/jsi" React-jsiexecutor: - :path: "../../node_modules/react-native/ReactCommon/jsiexecutor" + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" React-jsinspector: - :path: "../../node_modules/react-native/ReactCommon/jsinspector-modern" + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" React-jsitracing: - :path: "../../node_modules/react-native/ReactCommon/hermes/executor/" + :path: "../node_modules/react-native/ReactCommon/hermes/executor/" React-logger: - :path: "../../node_modules/react-native/ReactCommon/logger" + :path: "../node_modules/react-native/ReactCommon/logger" React-Mapbuffer: - :path: "../../node_modules/react-native/ReactCommon" + :path: "../node_modules/react-native/ReactCommon" React-microtasksnativemodule: - :path: "../../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" react-native-app-auth: - :path: "../../node_modules/react-native-app-auth" + :path: "../node_modules/react-native-app-auth" react-native-biometrics: - :path: "../../node_modules/react-native-biometrics" + :path: "../node_modules/react-native-biometrics" react-native-blur: - :path: "../../node_modules/@react-native-community/blur" + :path: "../node_modules/@react-native-community/blur" react-native-cloud-storage: - :path: "../../node_modules/react-native-cloud-storage" + :path: "../node_modules/react-native-cloud-storage" react-native-get-random-values: - :path: "../../node_modules/react-native-get-random-values" + :path: "../node_modules/react-native-get-random-values" react-native-netinfo: - :path: "../../node_modules/@react-native-community/netinfo" + :path: "../node_modules/@react-native-community/netinfo" react-native-nfc-manager: - :path: "../../node_modules/react-native-nfc-manager" + :path: "../node_modules/react-native-nfc-manager" react-native-safe-area-context: - :path: "../../node_modules/react-native-safe-area-context" + :path: "../node_modules/react-native-safe-area-context" react-native-sqlite-storage: - :path: "../../node_modules/react-native-sqlite-storage" + :path: "../node_modules/react-native-sqlite-storage" React-nativeconfig: - :path: "../../node_modules/react-native/ReactCommon" + :path: "../node_modules/react-native/ReactCommon" React-NativeModulesApple: - :path: "../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" React-perflogger: - :path: "../../node_modules/react-native/ReactCommon/reactperflogger" + :path: "../node_modules/react-native/ReactCommon/reactperflogger" React-performancetimeline: - :path: "../../node_modules/react-native/ReactCommon/react/performance/timeline" + :path: "../node_modules/react-native/ReactCommon/react/performance/timeline" React-RCTActionSheet: - :path: "../../node_modules/react-native/Libraries/ActionSheetIOS" + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" React-RCTAnimation: - :path: "../../node_modules/react-native/Libraries/NativeAnimation" + :path: "../node_modules/react-native/Libraries/NativeAnimation" React-RCTAppDelegate: - :path: "../../node_modules/react-native/Libraries/AppDelegate" + :path: "../node_modules/react-native/Libraries/AppDelegate" React-RCTBlob: - :path: "../../node_modules/react-native/Libraries/Blob" + :path: "../node_modules/react-native/Libraries/Blob" React-RCTFabric: - :path: "../../node_modules/react-native/React" + :path: "../node_modules/react-native/React" React-RCTImage: - :path: "../../node_modules/react-native/Libraries/Image" + :path: "../node_modules/react-native/Libraries/Image" React-RCTLinking: - :path: "../../node_modules/react-native/Libraries/LinkingIOS" + :path: "../node_modules/react-native/Libraries/LinkingIOS" React-RCTNetwork: - :path: "../../node_modules/react-native/Libraries/Network" + :path: "../node_modules/react-native/Libraries/Network" React-RCTSettings: - :path: "../../node_modules/react-native/Libraries/Settings" + :path: "../node_modules/react-native/Libraries/Settings" React-RCTText: - :path: "../../node_modules/react-native/Libraries/Text" + :path: "../node_modules/react-native/Libraries/Text" React-RCTVibration: - :path: "../../node_modules/react-native/Libraries/Vibration" + :path: "../node_modules/react-native/Libraries/Vibration" React-rendererconsistency: - :path: "../../node_modules/react-native/ReactCommon/react/renderer/consistency" + :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency" React-rendererdebug: - :path: "../../node_modules/react-native/ReactCommon/react/renderer/debug" + :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" React-rncore: - :path: "../../node_modules/react-native/ReactCommon" + :path: "../node_modules/react-native/ReactCommon" React-RuntimeApple: - :path: "../../node_modules/react-native/ReactCommon/react/runtime/platform/ios" + :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" React-RuntimeCore: - :path: "../../node_modules/react-native/ReactCommon/react/runtime" + :path: "../node_modules/react-native/ReactCommon/react/runtime" React-runtimeexecutor: - :path: "../../node_modules/react-native/ReactCommon/runtimeexecutor" + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" React-RuntimeHermes: - :path: "../../node_modules/react-native/ReactCommon/react/runtime" + :path: "../node_modules/react-native/ReactCommon/react/runtime" React-runtimescheduler: - :path: "../../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" React-timing: - :path: "../../node_modules/react-native/ReactCommon/react/timing" + :path: "../node_modules/react-native/ReactCommon/react/timing" React-utils: - :path: "../../node_modules/react-native/ReactCommon/react/utils" + :path: "../node_modules/react-native/ReactCommon/react/utils" ReactCodegen: :path: build/generated/ios ReactCommon: - :path: "../../node_modules/react-native/ReactCommon" + :path: "../node_modules/react-native/ReactCommon" RNCAsyncStorage: - :path: "../../node_modules/@react-native-async-storage/async-storage" + :path: "../node_modules/@react-native-async-storage/async-storage" RNCClipboard: - :path: "../../node_modules/@react-native-clipboard/clipboard" + :path: "../node_modules/@react-native-clipboard/clipboard" RNDeviceInfo: - :path: "../../node_modules/react-native-device-info" + :path: "../node_modules/react-native-device-info" RNFBApp: - :path: "../../node_modules/@react-native-firebase/app" + :path: "../node_modules/@react-native-firebase/app" RNFBMessaging: - :path: "../../node_modules/@react-native-firebase/messaging" + :path: "../node_modules/@react-native-firebase/messaging" RNFBRemoteConfig: - :path: "../../node_modules/@react-native-firebase/remote-config" + :path: "../node_modules/@react-native-firebase/remote-config" RNGestureHandler: - :path: "../../node_modules/react-native-gesture-handler" + :path: "../node_modules/react-native-gesture-handler" RNKeychain: - :path: "../../node_modules/react-native-keychain" + :path: "../node_modules/react-native-keychain" RNLocalize: - :path: "../../node_modules/react-native-localize" + :path: "../node_modules/react-native-localize" RNReactNativeHapticFeedback: - :path: "../../node_modules/react-native-haptic-feedback" + :path: "../node_modules/react-native-haptic-feedback" RNScreens: - :path: "../../node_modules/react-native-screens" + :path: "../node_modules/react-native-screens" RNSentry: - :path: "../../node_modules/@sentry/react-native" + :path: "../node_modules/@sentry/react-native" RNSVG: - :path: "../../node_modules/react-native-svg" + :path: "../node_modules/react-native-svg" segment-analytics-react-native: - :path: "../../node_modules/@segment/analytics-react-native" + :path: "../node_modules/@segment/analytics-react-native" sovran-react-native: - :path: "../../node_modules/@segment/sovran-react-native" + :path: "../node_modules/@segment/sovran-react-native" SwiftQRScanner: :git: https://github.com/vinodiOS/SwiftQRScanner Yoga: - :path: "../../node_modules/react-native/ReactCommon/yoga" + :path: "../node_modules/react-native/ReactCommon/yoga" CHECKOUT OPTIONS: NFCPassportReader: @@ -2549,7 +2548,7 @@ SPEC CHECKSUMS: React-runtimescheduler: a352af9ab3939273ee0e02650cfc1c8ee6e4d0c9 React-timing: a693c531e5627dcc200fc7286cbbebf73d73469d React-utils: 59c5bbbc0e72be22c9d6eceb40afadf9be872819 - ReactCodegen: 1ab18f5b89b9922f298e9216c7347d26ef5b6408 + ReactCodegen: 049be6309e06c1027544819670913680f2029b8e ReactCommon: b2eb96a61b826ff327a773a74357b302cf6da678 RNCAsyncStorage: 0003b916f1a69fe2d20b7910e0d08da3d32c7bd6 RNCClipboard: a4827e134e4774e97fa86f7f986694dd89320f13 @@ -2572,6 +2571,6 @@ SPEC CHECKSUMS: SwiftyTesseract: 1f3d96668ae92dc2208d9842c8a59bea9fad2cbb Yoga: 1259c7a8cbaccf7b4c3ddf8ee36ca11be9dee407 -PODFILE CHECKSUM: 73185dc21f929943e88451fb856faed1b6a0c8fd +PODFILE CHECKSUM: b5f11f935be22fce84c5395aaa203b50427a79aa COCOAPODS: 1.16.2 diff --git a/app/ios/Self.xcodeproj/project.pbxproj b/app/ios/Self.xcodeproj/project.pbxproj index f539ba306..8b14b73cb 100644 --- a/app/ios/Self.xcodeproj/project.pbxproj +++ b/app/ios/Self.xcodeproj/project.pbxproj @@ -24,10 +24,10 @@ 1686F0E02C500FBD00841CDE /* QRScannerBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1686F0DF2C500FBD00841CDE /* QRScannerBridge.m */; }; 16E6646E2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */; }; 16E884A52C5BD764003B7125 /* passport.json in Resources */ = {isa = PBXBuildFile; fileRef = 16E884A42C5BD764003B7125 /* passport.json */; }; - 55C24BC923F6E713F2A4F406 /* Pods_Self.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2256518ADB2DF783582D66DF /* Pods_Self.framework */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 905B70052A72767900AFA232 /* PassportReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 905B70042A72767900AFA232 /* PassportReader.swift */; }; 905B70072A72774000AFA232 /* PassportReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 905B70062A72774000AFA232 /* PassportReader.m */; }; + 97E31F23A5A11A2C115FE2BB /* Pods_Self.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0823092D57FC544FD63682A /* Pods_Self.framework */; }; AE6147EC2DC95A8D00445C0F /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = AE6147EB2DC95A8D00445C0F /* GoogleService-Info.plist */; }; B49D2B112E28AA7900946F64 /* IBMPlexMono-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = B49D2B102E28AA7900946F64 /* IBMPlexMono-Regular.otf */; }; BF1044812DD53540009B3688 /* LiveMRZScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1044802DD53540009B3688 /* LiveMRZScannerView.swift */; }; @@ -65,15 +65,13 @@ 169349842CC694DA00166F21 /* OpenPassportDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = OpenPassportDebug.entitlements; path = OpenPassport/OpenPassportDebug.entitlements; sourceTree = ""; }; 16E6646D2B8D292500FDD6A0 /* QKMRZScannerViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QKMRZScannerViewRepresentable.swift; sourceTree = ""; }; 16E884A42C5BD764003B7125 /* passport.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = passport.json; sourceTree = ""; }; - 2256518ADB2DF783582D66DF /* Pods_Self.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Self.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 55F05768F4B86745D6908F70 /* Pods-Self.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Self.debug.xcconfig"; path = "Target Support Files/Pods-Self/Pods-Self.debug.xcconfig"; sourceTree = ""; }; 7E5C3CEF7EDA4871B3D0EBE1 /* Advercase-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Advercase-Regular.otf"; path = "../src/assets/fonts/Advercase-Regular.otf"; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = OpenPassport/LaunchScreen.storyboard; sourceTree = ""; }; + 823EAA08DBB5F61225E922CA /* Pods-Self.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Self.release.xcconfig"; path = "Target Support Files/Pods-Self/Pods-Self.release.xcconfig"; sourceTree = ""; }; 905B70042A72767900AFA232 /* PassportReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassportReader.swift; sourceTree = ""; }; 905B70062A72774000AFA232 /* PassportReader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PassportReader.m; sourceTree = ""; }; 905B70082A729CD400AFA232 /* OpenPassport.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = OpenPassport.entitlements; path = OpenPassport/OpenPassport.entitlements; sourceTree = ""; }; 9BF744D9A73A4BAC96EC569A /* DINOT-Medium.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "DINOT-Medium.otf"; path = "../src/assets/fonts/DINOT-Medium.otf"; sourceTree = ""; }; - AC3CAAD43E2B9ECF07DACA0B /* Pods-Self.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Self.release.xcconfig"; path = "Target Support Files/Pods-Self/Pods-Self.release.xcconfig"; sourceTree = ""; }; AE6147EB2DC95A8D00445C0F /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "GoogleService-Info.plist"; sourceTree = ""; }; B49D2B102E28AA7900946F64 /* IBMPlexMono-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "IBMPlexMono-Regular.otf"; path = "../src/assets/fonts/IBMPlexMono-Regular.otf"; sourceTree = SOURCE_ROOT; }; BF1044802DD53540009B3688 /* LiveMRZScannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveMRZScannerView.swift; sourceTree = ""; }; @@ -82,7 +80,9 @@ BF6F0D542E38ED81008EA85C /* SelfAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelfAnalytics.swift; sourceTree = ""; }; BFBA0C762E339D2B00E82A52 /* NativeLoggerBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeLoggerBridge.swift; sourceTree = ""; }; BFBA0C782E33A01F00E82A52 /* NativeLoggerBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NativeLoggerBridge.m; sourceTree = ""; }; + C0823092D57FC544FD63682A /* Pods_Self.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Self.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E56E082698598B41447667BB /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = OpenPassport/PrivacyInfo.xcprivacy; sourceTree = ""; }; + E67B3FF985359E36919C9E20 /* Pods-Self.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Self.debug.xcconfig"; path = "Target Support Files/Pods-Self/Pods-Self.debug.xcconfig"; sourceTree = ""; }; E9F9A99A2D57FE2900E1362E /* PassportOCRViewManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PassportOCRViewManager.m; sourceTree = ""; }; E9F9A99B2D57FE2900E1362E /* PassportOCRViewManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassportOCRViewManager.swift; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; @@ -94,7 +94,7 @@ buildActionMask = 2147483647; files = ( 1608339F2D5CF89D00056417 /* AudioToolbox.framework in Frameworks */, - 55C24BC923F6E713F2A4F406 /* Pods_Self.framework in Frameworks */, + 97E31F23A5A11A2C115FE2BB /* Pods_Self.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -146,7 +146,7 @@ children = ( 1608339E2D5CF89D00056417 /* AudioToolbox.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 2256518ADB2DF783582D66DF /* Pods_Self.framework */, + C0823092D57FC544FD63682A /* Pods_Self.framework */, ); name = Frameworks; sourceTree = ""; @@ -194,8 +194,8 @@ BBD78D7AC51CEA395F1C20DB /* Pods */ = { isa = PBXGroup; children = ( - 55F05768F4B86745D6908F70 /* Pods-Self.debug.xcconfig */, - AC3CAAD43E2B9ECF07DACA0B /* Pods-Self.release.xcconfig */, + E67B3FF985359E36919C9E20 /* Pods-Self.debug.xcconfig */, + 823EAA08DBB5F61225E922CA /* Pods-Self.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -207,15 +207,15 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Self" */; buildPhases = ( - 2FCD11E7A379F3FBFB096963 /* [CP] Check Pods Manifest.lock */, + 3B4EFEB78A7250232578EEBD /* [CP] Check Pods Manifest.lock */, FD10A7F022414F080027D42C /* Start Packager */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 7EA8B5D35C013E0BEB505C3F /* [CP] Embed Pods Frameworks */, - 03955A0A8B5264C6E4546CCD /* [CP] Copy Pods Resources */, - 674D4E1D44AD675789D32C9F /* [CP-User] [RNFB] Core Configuration */, + E88323604DFAAA92032925C9 /* [CP] Embed Pods Frameworks */, + 12530D65E915E2C915FB4D42 /* [CP] Copy Pods Resources */, + ED88188A58B7D0764449DC88 /* [CP-User] [RNFB] Core Configuration */, ); buildRules = ( ); @@ -294,7 +294,7 @@ shellPath = /bin/sh; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; - 03955A0A8B5264C6E4546CCD /* [CP] Copy Pods Resources */ = { + 12530D65E915E2C915FB4D42 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -311,7 +311,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Self/Pods-Self-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 2FCD11E7A379F3FBFB096963 /* [CP] Check Pods Manifest.lock */ = { + 3B4EFEB78A7250232578EEBD /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -333,20 +333,7 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 674D4E1D44AD675789D32C9F /* [CP-User] [RNFB] Core Configuration */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", - ); - name = "[CP-User] [RNFB] Core Configuration"; - 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#\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"; - }; - 7EA8B5D35C013E0BEB505C3F /* [CP] Embed Pods Frameworks */ = { + E88323604DFAAA92032925C9 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -363,6 +350,19 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Self/Pods-Self-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + ED88188A58B7D0764449DC88 /* [CP-User] [RNFB] Core Configuration */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", + ); + name = "[CP-User] [RNFB] Core Configuration"; + 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#\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"; + }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -420,7 +420,7 @@ /* Begin XCBuildConfiguration section */ 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 55F05768F4B86745D6908F70 /* Pods-Self.debug.xcconfig */; + baseConfigurationReference = E67B3FF985359E36919C9E20 /* Pods-Self.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -563,7 +563,7 @@ }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AC3CAAD43E2B9ECF07DACA0B /* Pods-Self.release.xcconfig */; + baseConfigurationReference = 823EAA08DBB5F61225E922CA /* Pods-Self.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -789,8 +789,11 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; - REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native"; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; USE_HERMES = true; @@ -879,8 +882,11 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = "$(inherited) "; - REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native"; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; USE_HERMES = true; diff --git a/app/jest.config.cjs b/app/jest.config.cjs index 2bfd94433..872a0ae00 100644 --- a/app/jest.config.cjs +++ b/app/jest.config.cjs @@ -22,9 +22,13 @@ module.exports = { '^@selfxyz/mobile-sdk-alpha/(.*)$': '/../packages/mobile-sdk-alpha/dist/cjs/$1.cjs', // Fix snarkjs resolution for @anon-aadhaar/core - '^snarkjs$': '/../node_modules/snarkjs/build/main.cjs', + '^snarkjs$': '/../circuits/node_modules/snarkjs/build/main.cjs', // Fix ffjavascript resolution for snarkjs dependencies - '^ffjavascript$': '/../node_modules/ffjavascript/build/main.cjs', + '^ffjavascript$': + '/../circuits/node_modules/ffjavascript/build/main.cjs', + // Fix @anon-aadhaar/core resolution + '^@anon-aadhaar/core$': + '/../common/node_modules/@anon-aadhaar/core/dist/index.js', }, globals: { 'ts-jest': { diff --git a/app/jest.setup.js b/app/jest.setup.js index 75c606686..36d1c068b 100644 --- a/app/jest.setup.js +++ b/app/jest.setup.js @@ -13,6 +13,305 @@ jest.mock( { virtual: true }, ); +// Mock React Native bridge config for mobile-sdk-alpha components +global.__fbBatchedBridgeConfig = { + messageQueue: { + SPY_MODE: false, + }, + remoteModuleConfig: [], +}; + +// Set up global React Native test environment +global.__DEV__ = true; + +// Mock TurboModuleRegistry to provide required native modules for BOTH main app and mobile-sdk-alpha +jest.mock('react-native/Libraries/TurboModule/TurboModuleRegistry', () => ({ + getEnforcing: jest.fn(name => { + if (name === 'PlatformConstants') { + return { + getConstants: () => ({ + reactNativeVersion: { major: 0, minor: 76, patch: 9 }, + forceTouchAvailable: false, + osVersion: '14.0', + systemName: 'iOS', + interfaceIdiom: 'phone', + Dimensions: { + window: { width: 375, height: 667, scale: 2 }, + screen: { width: 375, height: 667, scale: 2 }, + }, + }), + }; + } + if (name === 'SettingsManager') { + return { + getConstants: () => ({}), + }; + } + if (name === 'DeviceInfo') { + return { + getConstants: () => ({ + Dimensions: { + window: { width: 375, height: 667, scale: 2 }, + screen: { width: 375, height: 667, scale: 2 }, + }, + }), + }; + } + return { + getConstants: () => ({}), + }; + }), + get: jest.fn(() => null), +})); + +// Mock the mobile-sdk-alpha's React Native instance separately +jest.mock( + '../packages/mobile-sdk-alpha/node_modules/react-native/Libraries/TurboModule/TurboModuleRegistry', + () => ({ + getEnforcing: jest.fn(name => { + if (name === 'PlatformConstants') { + return { + getConstants: () => ({ + reactNativeVersion: { major: 0, minor: 76, patch: 9 }, + forceTouchAvailable: false, + osVersion: '14.0', + systemName: 'iOS', + interfaceIdiom: 'phone', + Dimensions: { + window: { width: 375, height: 667, scale: 2 }, + screen: { width: 375, height: 667, scale: 2 }, + }, + }), + }; + } + return { + getConstants: () => ({}), + }; + }), + get: jest.fn(() => null), + }), + { virtual: true }, +); + +// Mock mobile-sdk-alpha's Dimensions module +jest.mock( + '../packages/mobile-sdk-alpha/node_modules/react-native/Libraries/Utilities/Dimensions', + () => ({ + getConstants: jest.fn(() => ({ + window: { width: 375, height: 667, scale: 2 }, + screen: { width: 375, height: 667, scale: 2 }, + })), + set: jest.fn(), + get: jest.fn(() => ({ + window: { width: 375, height: 667, scale: 2 }, + screen: { width: 375, height: 667, scale: 2 }, + })), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + }), + { virtual: true }, +); + +// Mock mobile-sdk-alpha's PixelRatio module +jest.mock( + '../packages/mobile-sdk-alpha/node_modules/react-native/Libraries/Utilities/PixelRatio', + () => ({ + get: jest.fn(() => 2), + getFontScale: jest.fn(() => 1), + getPixelSizeForLayoutSize: jest.fn(layoutSize => layoutSize * 2), + roundToNearestPixel: jest.fn(layoutSize => Math.round(layoutSize * 2) / 2), + startDetecting: jest.fn(), + }), + { virtual: true }, +); + +// Mock mobile-sdk-alpha's StyleSheet module directly +jest.mock( + '../packages/mobile-sdk-alpha/node_modules/react-native/Libraries/StyleSheet/StyleSheet', + () => ({ + create: jest.fn(styles => styles), + flatten: jest.fn(style => style), + hairlineWidth: 1, + absoluteFillObject: { + position: 'absolute', + left: 0, + right: 0, + top: 0, + bottom: 0, + }, + roundToNearestPixel: jest.fn(layoutSize => Math.round(layoutSize * 2) / 2), + }), + { virtual: true }, +); + +// Mock NativeDeviceInfo specs for both main app and mobile-sdk-alpha +jest.mock('react-native/src/private/specs/modules/NativeDeviceInfo', () => ({ + getConstants: jest.fn(() => ({ + Dimensions: { + window: { width: 375, height: 667, scale: 2 }, + screen: { width: 375, height: 667, scale: 2 }, + }, + })), +})); + +// Mock react-native-gesture-handler to prevent getConstants errors +jest.mock('react-native-gesture-handler', () => { + const RN = jest.requireActual('react-native'); + return { + ...jest.requireActual('react-native-gesture-handler/jestSetup'), + GestureHandlerRootView: ({ children }) => children, + ScrollView: RN.ScrollView, + TouchableOpacity: RN.TouchableOpacity, + TouchableHighlight: RN.TouchableHighlight, + FlatList: RN.FlatList, + }; +}); + +// Mock NativeEventEmitter to prevent null argument errors +jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter', () => { + return class MockNativeEventEmitter { + constructor(nativeModule) { + // Accept any nativeModule argument (including null/undefined) + this.nativeModule = nativeModule; + } + + addListener = jest.fn(); + removeListener = jest.fn(); + removeAllListeners = jest.fn(); + emit = jest.fn(); + }; +}); + +// Mock problematic mobile-sdk-alpha components that use React Native StyleSheet +jest.mock('@selfxyz/mobile-sdk-alpha', () => ({ + NFCScannerScreen: jest.fn(() => null), + SelfClientProvider: jest.fn(({ children }) => children), + useSelfClient: jest.fn(() => { + // Create a consistent mock instance for memoization testing + if (!global.mockSelfClientInstance) { + global.mockSelfClientInstance = { + // Mock selfClient object with common methods + connect: jest.fn(), + disconnect: jest.fn(), + isConnected: false, + extractMRZInfo: jest.fn(mrzString => { + // Mock extractMRZInfo with realistic behavior + if (!mrzString || typeof mrzString !== 'string') { + throw new Error('Invalid MRZ string provided'); + } + + // Valid MRZ example from the test + if (mrzString.includes('L898902C3')) { + return { + documentNumber: 'L898902C3', + validation: { + overall: true, + }, + // Add other expected MRZ fields + firstName: 'ANNA', + lastName: 'ERIKSSON', + nationality: 'UTO', + dateOfBirth: '740812', + sex: 'F', + expirationDate: '120415', + }; + } + + // For malformed/invalid MRZ strings, throw an error + throw new Error('Invalid MRZ format'); + }), + trackEvent: jest.fn(), + }; + } + return global.mockSelfClientInstance; + }), + createSelfClient: jest.fn(() => ({ + // Mock createSelfClient return value + connect: jest.fn(), + disconnect: jest.fn(), + isConnected: false, + extractMRZInfo: jest.fn(mrzString => { + // Mock extractMRZInfo with realistic behavior + if (!mrzString || typeof mrzString !== 'string') { + throw new Error('Invalid MRZ string provided'); + } + + // Valid MRZ example from the test + if (mrzString.includes('L898902C3')) { + return { + documentNumber: 'L898902C3', + validation: { + overall: true, + }, + // Add other expected MRZ fields + firstName: 'ANNA', + lastName: 'ERIKSSON', + nationality: 'UTO', + dateOfBirth: '740812', + sex: 'F', + expirationDate: '120415', + }; + } + + // For malformed/invalid MRZ strings, throw an error + throw new Error('Invalid MRZ format'); + }), + trackEvent: jest.fn(), + })), + createListenersMap: jest.fn(() => ({ + // Mock createListenersMap return value + map: new Map(), + addListener: jest.fn(), + removeListener: jest.fn(), + })), + isPassportDataValid: jest.fn((data, callbacks) => { + // Mock validation function with realistic behavior + if (!data || !data.passportMetadata) { + // Call appropriate callbacks for missing data + if (callbacks?.onPassportMetadataNull) { + callbacks.onPassportMetadataNull(); + } + return false; + } + // Return true for valid data, false for invalid + return data.valid !== false; + }), + SdkEvents: { + // Mock SDK events object + PROVING_PASSPORT_DATA_NOT_FOUND: 'PROVING_PASSPORT_DATA_NOT_FOUND', + PROVING_STARTED: 'PROVING_STARTED', + PROVING_COMPLETED: 'PROVING_COMPLETED', + PROVING_FAILED: 'PROVING_FAILED', + // Add other events as needed + }, + // Add other components and hooks as needed +})); + +// Mock Sentry to prevent NativeModule.getConstants errors +jest.mock('@sentry/react-native', () => ({ + addBreadcrumb: jest.fn(), + captureException: jest.fn(), + captureFeedback: jest.fn(), + captureMessage: jest.fn(), + setContext: jest.fn(), + setExtra: jest.fn(), + setTag: jest.fn(), + setUser: jest.fn(), + init: jest.fn(), + wrap: jest.fn(component => component), + withScope: jest.fn(callback => { + // Mock scope object + const scope = { + setLevel: jest.fn(), + setTag: jest.fn(), + setExtra: jest.fn(), + setContext: jest.fn(), + setUser: jest.fn(), + }; + callback(scope); + }), +})); + jest.mock('@env', () => ({ ENABLE_DEBUG_LOGS: 'false', MIXPANEL_NFC_PROJECT_TOKEN: 'test-token', diff --git a/app/metro.config.cjs b/app/metro.config.cjs index 9927d8bc4..df687f52a 100644 --- a/app/metro.config.cjs +++ b/app/metro.config.cjs @@ -4,205 +4,34 @@ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); const path = require('node:path'); +const findYarnWorkspaceRoot = require('find-yarn-workspace-root'); const defaultConfig = getDefaultConfig(__dirname); const { assetExts, sourceExts } = defaultConfig.resolver; -const monorepoRoot = path.resolve(__dirname, '../'); -const commonPath = path.join(__dirname, '/../common'); -const sdkAlphaPath = path.join(__dirname, '/../packages/mobile-sdk-alpha'); -const trueMonorepoNodeModules = path.resolve(__dirname, '../node_modules'); -const extraNodeModules = { - stream: require.resolve('stream-browserify'), - buffer: require.resolve('buffer'), - util: require.resolve('util'), - assert: require.resolve('assert'), - '@babel/runtime': path.join(trueMonorepoNodeModules, '@babel/runtime'), - // Pin React and React Native to monorepo root - react: path.join(trueMonorepoNodeModules, 'react'), - 'react-native': path.join(trueMonorepoNodeModules, 'react-native'), - '@': path.join(__dirname, 'src'), - '@selfxyz/common': path.resolve(commonPath, 'dist'), - '@selfxyz/mobile-sdk-alpha': path.resolve(sdkAlphaPath, 'dist'), - '@selfxyz/mobile-sdk-alpha/constants/analytics': path.resolve( - sdkAlphaPath, - 'dist/esm/constants/analytics.js', - ), - '@selfxyz/mobile-sdk-alpha/stores': path.resolve( - sdkAlphaPath, - 'dist/esm/stores.js', - ), - // Main exports - '@selfxyz/common/utils': path.resolve( - commonPath, - 'dist/esm/src/utils/index.js', - ), - '@selfxyz/common/types': path.resolve( - commonPath, - 'dist/esm/src/types/index.js', - ), - '@selfxyz/common/constants': path.resolve( - commonPath, - 'dist/esm/src/constants/index.js', - ), - // Constants subpaths - '@selfxyz/common/constants/countries': path.resolve( - commonPath, - 'dist/esm/src/constants/countries.js', - ), - '@selfxyz/common/constants/vkey': path.resolve( - commonPath, - 'dist/esm/src/constants/vkey.js', - ), - '@selfxyz/common/constants/skiPem': path.resolve( - commonPath, - 'dist/esm/src/constants/skiPem.js', - ), - '@selfxyz/common/constants/mockCerts': path.resolve( - commonPath, - 'dist/esm/src/constants/mockCertificates.js', - ), - '@selfxyz/common/constants/hashes': path.resolve( - commonPath, - 'dist/esm/src/constants/sampleDataHashes.js', - ), - // Utils subpaths - '@selfxyz/common/utils/hash': path.resolve( - commonPath, - 'dist/esm/src/utils/hash.js', - ), - '@selfxyz/common/utils/attest': path.resolve( - commonPath, - 'dist/esm/src/utils/attest.js', - ), - '@selfxyz/common/utils/bytes': path.resolve( - commonPath, - 'dist/esm/src/utils/bytes.js', - ), - '@selfxyz/common/utils/trees': path.resolve( - commonPath, - 'dist/esm/src/utils/trees.js', - ), - '@selfxyz/common/utils/scope': path.resolve( - commonPath, - 'dist/esm/src/utils/scope.js', - ), - '@selfxyz/common/utils/proving': path.resolve( - commonPath, - 'dist/esm/src/utils/proving.js', - ), - '@selfxyz/common/utils/appType': path.resolve( - commonPath, - 'dist/esm/src/utils/appType.js', - ), - '@selfxyz/common/utils/date': path.resolve( - commonPath, - 'dist/esm/src/utils/date.js', - ), - '@selfxyz/common/utils/arrays': path.resolve( - commonPath, - 'dist/esm/src/utils/arrays.js', - ), - '@selfxyz/common/utils/passports': path.resolve( - commonPath, - 'dist/esm/src/utils/passports/index.js', - ), - '@selfxyz/common/utils/passportFormat': path.resolve( - commonPath, - 'dist/esm/src/utils/passports/format.js', - ), - '@selfxyz/common/utils/passports/validate': path.resolve( - commonPath, - 'dist/esm/src/utils/passports/validate.js', - ), - '@selfxyz/common/utils/passportMock': path.resolve( - commonPath, - 'dist/esm/src/utils/passports/mock.js', - ), - '@selfxyz/common/utils/passportDg1': path.resolve( - commonPath, - 'dist/esm/src/utils/passports/dg1.js', - ), - '@selfxyz/common/utils/certificates': path.resolve( - commonPath, - 'dist/esm/src/utils/certificate_parsing/index.js', - ), - '@selfxyz/common/utils/elliptic': path.resolve( - commonPath, - 'dist/esm/src/utils/certificate_parsing/elliptic.js', - ), - '@selfxyz/common/utils/curves': path.resolve( - commonPath, - 'dist/esm/src/utils/certificate_parsing/curves.js', - ), - '@selfxyz/common/utils/oids': path.resolve( - commonPath, - 'dist/esm/src/utils/certificate_parsing/oids.js', - ), - '@selfxyz/common/utils/circuits': path.resolve( - commonPath, - 'dist/esm/src/utils/circuits/index.js', - ), - '@selfxyz/common/utils/circuitNames': path.resolve( - commonPath, - 'dist/esm/src/utils/circuits/circuitsName.js', - ), - '@selfxyz/common/utils/circuitFormat': path.resolve( - commonPath, - 'dist/esm/src/utils/circuits/formatOutputs.js', - ), - '@selfxyz/common/utils/uuid': path.resolve( - commonPath, - 'dist/esm/src/utils/circuits/uuid.js', - ), - '@selfxyz/common/utils/contracts': path.resolve( - commonPath, - 'dist/esm/src/utils/contracts/index.js', - ), - '@selfxyz/common/utils/sanctions': path.resolve( - commonPath, - 'dist/esm/src/utils/contracts/forbiddenCountries.js', - ), - '@selfxyz/common/utils/csca': path.resolve( - commonPath, - 'dist/esm/src/utils/csca.js', - ), - '@selfxyz/common/utils/ofac': path.resolve( - commonPath, - 'dist/esm/src/utils/ofac.js', - ), - // Types subpaths - '@selfxyz/common/types/passport': path.resolve( - commonPath, - 'dist/esm/src/types/passport.js', - ), - '@selfxyz/common/types/app': path.resolve( - commonPath, - 'dist/esm/src/types/app.js', - ), - '@selfxyz/common/types/certificates': path.resolve( - commonPath, - 'dist/esm/src/types/certificates.js', - ), - '@selfxyz/common/types/circuits': path.resolve( - commonPath, - 'dist/esm/src/types/circuits.js', - ), -}; -const watchFolders = [ - path.resolve(commonPath), - trueMonorepoNodeModules, - path.join(__dirname, 'src'), - path.resolve(sdkAlphaPath), -]; +const projectRoot = __dirname; +const workspaceRoot = + findYarnWorkspaceRoot(__dirname) || path.resolve(__dirname, '..'); /** - * Metro configuration - * https://facebook.github.io/metro/docs/configuration + * Modern Metro configuration using native workspace capabilities + * Eliminates need for manual symlink management through: + * - enableGlobalPackages: Automatic workspace package discovery + * - unstable_enablePackageExports: Native subpath import support + * - unstable_enableSymlinks: Optional symlink resolution * * @type {import('metro-config').MetroConfig} */ const config = { + projectRoot, + + watchFolders: [ + workspaceRoot, // Watch entire workspace root for changes + path.resolve(workspaceRoot, 'common'), + path.resolve(workspaceRoot, 'packages/mobile-sdk-alpha'), + path.resolve(projectRoot, 'node_modules'), // Watch app's node_modules for custom resolved modules + ], + transformer: { babelTransformerPath: require.resolve( 'react-native-svg-transformer/react-native', @@ -210,27 +39,247 @@ const config = { disableImportExportTransform: true, inlineRequires: true, }, + resolver: { - extraNodeModules, + // Prevent Haste module naming collisions from duplicate package.json files + blockList: [ + // Ignore built package.json files to prevent Haste collisions + /.*\/dist\/package\.json$/, + /.*\/dist\/esm\/package\.json$/, + /.*\/dist\/cjs\/package\.json$/, + /.*\/build\/package\.json$/, + // Prevent duplicate React/React Native - block workspace root versions and use app's versions + // Use precise regex patterns to avoid blocking packages like react-native-get-random-values + new RegExp( + `^${workspaceRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/node_modules/react(/|$)`, + ), + new RegExp( + `^${workspaceRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/node_modules/react-dom(/|$)`, + ), + new RegExp( + `^${workspaceRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/node_modules/react-native(/|$)`, + ), + new RegExp( + `^${workspaceRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/node_modules/scheduler(/|$)`, + ), + new RegExp('packages/mobile-sdk-alpha/node_modules/react(/|$)'), + new RegExp('packages/mobile-sdk-alpha/node_modules/react-dom(/|$)'), + new RegExp('packages/mobile-sdk-alpha/node_modules/react-native(/|$)'), + new RegExp('packages/mobile-sdk-alpha/node_modules/scheduler(/|$)'), + new RegExp('packages/mobile-sdk-demo/node_modules/react(/|$)'), + new RegExp('packages/mobile-sdk-demo/node_modules/react-dom(/|$)'), + new RegExp('packages/mobile-sdk-demo/node_modules/react-native(/|$)'), + new RegExp('packages/mobile-sdk-demo/node_modules/scheduler(/|$)'), + ], + // Enable automatic workspace package resolution + enableGlobalPackages: true, + + // Handle subpath exports (@selfxyz/common/constants) + unstable_enablePackageExports: true, + + // Enable native symlink support (optional, for compatibility) + unstable_enableSymlinks: true, + + // Define search order for node modules - prioritize app's modules for React consistency nodeModulesPaths: [ - path.resolve(__dirname, 'node_modules'), // App's own node_modules - path.resolve(monorepoRoot, 'node_modules'), // Monorepo root node_modules - trueMonorepoNodeModules, - // Add paths to other package workspaces if needed + path.resolve(projectRoot, 'node_modules'), // App's own node_modules FIRST + path.resolve(workspaceRoot, 'node_modules'), // Workspace root node_modules SECOND ], + + // Essential polyfills for React Native + extraNodeModules: { + stream: require.resolve('stream-browserify'), + buffer: require.resolve('buffer'), + util: require.resolve('util'), + assert: require.resolve('assert'), + events: require.resolve('events'), + // App-specific alias + '@': path.join(__dirname, 'src'), + }, + + // Support package exports with conditions + unstable_conditionNames: ['react-native', 'import', 'require'], + + // SVG support assetExts: assetExts.filter(ext => ext !== 'svg'), sourceExts: [...sourceExts, 'svg'], - // Custom resolver to handle Node.js modules elegantly + // Custom resolver to handle both .js imports in TypeScript and Node.js modules resolveRequest: (context, moduleName, platform) => { - // Handle problematic Node.js modules that don't work in React Native + // Handle React Native gesture handler that needs app-level resolution + const appLevelModules = { + 'react-native-gesture-handler': + 'react-native-gesture-handler/lib/commonjs/index.js', + }; + + if (appLevelModules[moduleName]) { + try { + return { + type: 'sourceFile', + filePath: require.resolve(appLevelModules[moduleName], { + paths: [projectRoot], + }), + }; + } catch (error) { + console.warn(`Failed to resolve ${moduleName}:`, error); + // Fall back to default resolution + return context.resolveRequest(context, moduleName, platform); + } + } + + // React modules now resolve naturally through nodeModulesPaths (app's node_modules first) + + // Force SDK to use built ESM to avoid duplicate React and source transpilation issues + if (moduleName === '@selfxyz/mobile-sdk-alpha') { + return { + type: 'sourceFile', + filePath: path.resolve( + workspaceRoot, + 'packages/mobile-sdk-alpha/dist/esm/index.js', + ), + }; + } + // For relative imports in common source files that end with .js + if ( + context.originModulePath?.includes('/common/src/') && + moduleName.endsWith('.js') + ) { + const tsModuleName = moduleName.replace(/\.js$/, '.ts'); + return context.resolveRequest(context, tsModuleName, platform); + } + + // Handle problematic package exports and Node.js modules + + // Fix @tamagui/config v2-native export resolution + if (moduleName === '@tamagui/config/v2-native') { + try { + return { + type: 'sourceFile', + filePath: require.resolve('@tamagui/config/dist/esm/v2-native.js'), + }; + } catch { + // Fallback to main export if specific file doesn't exist + return { + type: 'sourceFile', + filePath: require.resolve('@tamagui/config'), + }; + } + } + + // Fix @noble/hashes subpath export resolution + if (moduleName.startsWith('@noble/hashes/')) { + try { + // Extract the subpath (e.g., 'crypto.js', 'sha256', 'hmac') + const subpath = moduleName.replace('@noble/hashes/', ''); + const basePath = require.resolve('@noble/hashes'); + + // For .js files, look in the package directory + if (subpath.endsWith('.js')) { + const subpathFile = path.join(path.dirname(basePath), subpath); + return { + type: 'sourceFile', + filePath: subpathFile, + }; + } else { + // For other imports like 'sha256', 'hmac', etc., try the main directory + const subpathFile = path.join( + path.dirname(basePath), + `${subpath}.js`, + ); + return { + type: 'sourceFile', + filePath: subpathFile, + }; + } + } catch { + // Fallback to main package if subpath doesn't exist + return { + type: 'sourceFile', + filePath: require.resolve('@noble/hashes'), + }; + } + } + + // Fix snarkjs and ffjavascript platform exports for Android + if (platform === 'android') { + // Handle snarkjs and its nested dependencies that have platform export issues + if ( + moduleName.includes('/snarkjs') && + (moduleName.endsWith('/snarkjs') || + moduleName.includes('/snarkjs/node_modules')) + ) { + try { + // Try to resolve the main package file + const packagePath = moduleName.split('/node_modules/').pop(); + const resolved = require.resolve(packagePath || 'snarkjs'); + return { + type: 'sourceFile', + filePath: resolved, + }; + } catch { + // Fallback to basic snarkjs resolution + try { + return { + type: 'sourceFile', + filePath: require.resolve('snarkjs'), + }; + } catch { + // Continue to next check + } + } + } + + // Handle ffjavascript from any nested location + if ( + moduleName.includes('/ffjavascript') && + moduleName.endsWith('/ffjavascript') + ) { + try { + // Try to resolve ffjavascript from the specific nested location first + const resolved = require.resolve(moduleName); + return { + type: 'sourceFile', + filePath: resolved, + }; + } catch { + // Fallback to resolving ffjavascript from the closest available location + try { + const resolved = require.resolve('ffjavascript'); + return { + type: 'sourceFile', + filePath: resolved, + }; + } catch { + // Continue to next check + } + } + } + + // Handle direct package imports for known problematic packages + const platformProblematicPackages = ['snarkjs', 'ffjavascript']; + for (const pkg of platformProblematicPackages) { + if (moduleName === pkg || moduleName.startsWith(`${pkg}/`)) { + try { + return { + type: 'sourceFile', + filePath: require.resolve(pkg), + }; + } catch { + // Continue to next check + continue; + } + } + } + } + const nodeModuleRedirects = { - crypto: require.resolve('crypto-browserify'), + crypto: path.resolve(__dirname, '../common/src/polyfills/crypto.ts'), fs: false, // Disable filesystem access os: false, // Disable OS-specific modules readline: false, // Disable readline module constants: require.resolve('constants-browserify'), path: require.resolve('path-browserify'), + 'web-worker': false, // Disable web workers (not available in React Native) }; if ( @@ -247,11 +296,36 @@ const config = { }; } + // Handle optional peer dependencies by returning empty modules + const optionalPeerDependencies = [ + 'react-native-reanimated', + '@react-native-masked-view/masked-view', + '@react-native-firebase/analytics', + ]; + + if (optionalPeerDependencies.includes(moduleName)) { + // Return empty module for optional peer dependencies + return { type: 'empty' }; + } + // Fall back to default Metro resolver for all other modules - return context.resolveRequest(context, moduleName, platform); + try { + return context.resolveRequest(context, moduleName, platform); + } catch (error) { + // Check if this is one of our expected optional dependencies + if (optionalPeerDependencies.some(dep => moduleName.includes(dep))) { + return { type: 'empty' }; + } + + // If default resolution fails, log and re-throw + console.warn( + `Metro resolver failed for module "${moduleName}":`, + error.message, + ); + throw error; + } }, }, - watchFolders, }; module.exports = mergeConfig(defaultConfig, config); diff --git a/app/package.json b/app/package.json index 492c2d68a..c3d55bdb3 100644 --- a/app/package.json +++ b/app/package.json @@ -69,15 +69,20 @@ "web:build": "yarn build:deps && vite build", "web:preview": "vite preview" }, + "resolutions": { + "punycode": "npm:punycode.js@2.3.1" + }, "overrides": { - "punycode": "npm:punycode.js@^2.3.1" + "punycode": "npm:punycode.js@2.3.1" }, "dependencies": { "@babel/runtime": "^7.28.3", "@ethersproject/shims": "^5.7.0", "@noble/hashes": "^1.5.0", + "@openpassport/zk-kit-imt": "^0.0.5", "@openpassport/zk-kit-lean-imt": "^0.0.6", "@openpassport/zk-kit-smt": "^0.0.1", + "@peculiar/x509": "^1.13.0", "@react-native-async-storage/async-storage": "^2.2.0", "@react-native-clipboard/clipboard": "1.16.3", "@react-native-community/blur": "^4.4.1", @@ -94,11 +99,12 @@ "@selfxyz/mobile-sdk-alpha": "workspace:^", "@sentry/react": "^9.32.0", "@sentry/react-native": "7.0.1", - "@tamagui/animations-css": "^1.129.3", - "@tamagui/animations-react-native": "^1.129.3", + "@stablelib/cbor": "^2.0.1", + "@tamagui/animations-css": "1.126.14", + "@tamagui/animations-react-native": "1.126.14", "@tamagui/config": "1.126.14", "@tamagui/lucide-icons": "1.126.14", - "@tamagui/toast": "^1.127.2", + "@tamagui/toast": "1.126.14", "@xstate/react": "^5.0.3", "add": "^2.0.6", "asn1js": "^3.0.6", @@ -107,12 +113,17 @@ "elliptic": "^6.6.1", "ethers": "^6.11.0", "expo-modules-core": "^2.2.1", + "hash.js": "^1.1.7", + "i18n-iso-countries": "^7.14.0", + "js-sha1": "^0.7.0", + "js-sha256": "^0.11.1", "js-sha512": "^0.9.0", "lottie-react": "^2.4.1", "lottie-react-native": "7.2.2", "node-forge": "^1.3.1", "pkijs": "^3.2.5", "poseidon-lite": "^0.2.0", + "prop-types": "^15.8.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-native": "0.76.9", @@ -148,6 +159,7 @@ "devDependencies": { "@babel/core": "^7.28.3", "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/preset-env": "^7.28.3", "@react-native-community/cli": "^16.0.3", "@react-native/babel-preset": "0.76.9", "@react-native/eslint-config": "0.76.9", @@ -175,8 +187,8 @@ "@typescript-eslint/parser": "^8.39.0", "@vitejs/plugin-react-swc": "^3.10.2", "babel-plugin-module-resolver": "^5.0.2", + "buffer": "^6.0.3", "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.12.1", "dompurify": "^3.2.6", "eslint": "^8.57.0", "eslint-config-prettier": "10.1.8", diff --git a/app/scripts/tests/alias-imports.test.cjs b/app/scripts/tests/aliasImports.test.cjs similarity index 100% rename from app/scripts/tests/alias-imports.test.cjs rename to app/scripts/tests/aliasImports.test.cjs diff --git a/app/scripts/tests/bundle-analyze-ci.test.cjs b/app/scripts/tests/bundleAnalyzeCi.test.cjs similarity index 100% rename from app/scripts/tests/bundle-analyze-ci.test.cjs rename to app/scripts/tests/bundleAnalyzeCi.test.cjs diff --git a/app/scripts/tests/cleanup-ios-build.test.cjs b/app/scripts/tests/cleanupIosBuild.test.cjs similarity index 100% rename from app/scripts/tests/cleanup-ios-build.test.cjs rename to app/scripts/tests/cleanupIosBuild.test.cjs diff --git a/app/scripts/tests/mobile-deploy-confirm.test.cjs b/app/scripts/tests/mobileDeployConfirm.test.cjs similarity index 100% rename from app/scripts/tests/mobile-deploy-confirm.test.cjs rename to app/scripts/tests/mobileDeployConfirm.test.cjs diff --git a/app/scripts/tests/mobile-deploy-confirm-module.test.cjs b/app/scripts/tests/mobileDeployConfirmModule.test.cjs similarity index 100% rename from app/scripts/tests/mobile-deploy-confirm-module.test.cjs rename to app/scripts/tests/mobileDeployConfirmModule.test.cjs diff --git a/app/scripts/tests/tree-shaking.test.cjs b/app/scripts/tests/treeShaking.test.cjs similarity index 100% rename from app/scripts/tests/tree-shaking.test.cjs rename to app/scripts/tests/treeShaking.test.cjs diff --git a/app/src/components/homeScreen/idCard.tsx b/app/src/components/homeScreen/idCard.tsx index a997124e1..cea58cb35 100644 --- a/app/src/components/homeScreen/idCard.tsx +++ b/app/src/components/homeScreen/idCard.tsx @@ -6,16 +6,13 @@ import type { FC } from 'react'; import { Dimensions } from 'react-native'; import { Separator, Text, XStack, YStack } from 'tamagui'; -import { - AadhaarData, - isAadhaarDocument, - isMRZDocument, - PassportData, -} from '@selfxyz/common'; +import type { AadhaarData } from '@selfxyz/common'; import { attributeToPosition, attributeToPosition_ID, } from '@selfxyz/common/constants'; +import type { PassportData } from '@selfxyz/common/types/passport'; +import { isAadhaarDocument, isMRZDocument } from '@selfxyz/common/utils/types'; import { SvgXml } from '@/components/homeScreen/SvgXmlWrapper'; import AadhaarIcon from '@/images/icons/aadhaar.svg'; diff --git a/app/src/hooks/useMockDataForm.ts b/app/src/hooks/useMockDataForm.ts index 12cd9c5f1..62c52788f 100644 --- a/app/src/hooks/useMockDataForm.ts +++ b/app/src/hooks/useMockDataForm.ts @@ -14,12 +14,12 @@ export const useMockDataForm = () => { const [selectedDocumentType, setSelectedDocumentType] = useState< 'mock_passport' | 'mock_id_card' | 'mock_aadhaar' >('mock_passport'); - const [isInOfacList, setIsInOfacList] = useState(true); + const [isInOfacList, setIsInOfacList] = useState(false); const resetFormValues = () => { setAge(21); setExpiryYears(5); - setIsInOfacList(true); + setIsInOfacList(false); setSelectedDocumentType('mock_passport'); setSelectedAlgorithm('sha256 rsa 65537 2048'); setSelectedCountry('USA'); diff --git a/app/src/mocks/nfcScanner.ts b/app/src/mocks/nfcScanner.ts new file mode 100644 index 000000000..03ba23b01 --- /dev/null +++ b/app/src/mocks/nfcScanner.ts @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +// Web mock for NFC scanner functionality +// NFC passport scanning is not supported on web browsers + +export const parseScanResponse = (_response: unknown) => { + throw new Error('NFC passport scanning is not supported on web browsers'); +}; + +export const scan = async (_inputs: unknown) => { + throw new Error('NFC passport scanning is not supported on web browsers'); +}; diff --git a/app/src/providers/passportDataProvider.tsx b/app/src/providers/passportDataProvider.tsx index a6c14ed9c..c6ad74890 100644 --- a/app/src/providers/passportDataProvider.tsx +++ b/app/src/providers/passportDataProvider.tsx @@ -44,17 +44,16 @@ import type { PropsWithChildren } from 'react'; import React, { createContext, useCallback, useContext, useMemo } from 'react'; import Keychain from 'react-native-keychain'; -import { isMRZDocument } from '@selfxyz/common'; import type { PublicKeyDetailsECDSA, PublicKeyDetailsRSA, -} from '@selfxyz/common/utils'; +} from '@selfxyz/common/types/certificates'; import { brutforceSignatureAlgorithmDsc, calculateContentHash, inferDocumentCategory, - parseCertificateSimple, } from '@selfxyz/common/utils'; +import { parseCertificateSimple } from '@selfxyz/common/utils/certificate_parsing/parseCertificateSimple'; import type { AadhaarData, DocumentCatalog, @@ -62,6 +61,7 @@ import type { IDDocument, PassportData, } from '@selfxyz/common/utils/types'; +import { isMRZDocument } from '@selfxyz/common/utils/types'; import type { DocumentsAdapter, SelfClient } from '@selfxyz/mobile-sdk-alpha'; import { getAllDocuments, useSelfClient } from '@selfxyz/mobile-sdk-alpha'; diff --git a/app/src/screens/document/DocumentNFCScanScreen.tsx b/app/src/screens/document/DocumentNFCScanScreen.tsx index c1bf062a8..316667499 100644 --- a/app/src/screens/document/DocumentNFCScanScreen.tsx +++ b/app/src/screens/document/DocumentNFCScanScreen.tsx @@ -628,9 +628,7 @@ const DocumentNFCScanScreen: React.FC = () => { width="$8" alignSelf="center" borderRadius={1000} - source={{ - uri: NFC_IMAGE, - }} + source={NFC_IMAGE} margin={20} /> diff --git a/app/src/screens/document/DocumentNFCScanScreen.web.tsx b/app/src/screens/document/DocumentNFCScanScreen.web.tsx index da73b9165..1a6afeadb 100644 --- a/app/src/screens/document/DocumentNFCScanScreen.web.tsx +++ b/app/src/screens/document/DocumentNFCScanScreen.web.tsx @@ -55,9 +55,7 @@ const DocumentNFCScanScreen: React.FC = () => { width="$8" alignSelf="center" borderRadius={1000} - source={{ - uri: NFC_IMAGE, - }} + source={NFC_IMAGE} margin={20} /> diff --git a/app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx b/app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx index 58acf4eef..70f1d51f5 100644 --- a/app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx +++ b/app/src/screens/document/aadhaar/AadhaarUploadScreen.tsx @@ -259,7 +259,7 @@ const AadhaarUploadScreen: React.FC = () => { paddingVertical={20} > { const isFocused = useIsFocused(); const [doneScanningQR, setDoneScanningQR] = useState(false); const navigateToProve = useHapticNavigation('Prove'); - const navigateToHome = useHapticNavigation('Home'); - const onCancelPress = useCallback(() => { - navigateToHome(); - }, [navigateToHome]); // This resets to the default state when we navigate back to this screen useFocusEffect( diff --git a/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx b/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx index da3822ae5..1831bbb9e 100644 --- a/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx +++ b/app/src/screens/recovery/AccountRecoveryChoiceScreen.tsx @@ -66,8 +66,13 @@ const AccountRecoveryChoiceScreen: React.FC = () => { return useProtocolStore.getState()[docCategory].commitment_tree; }, getAltCSCA(docCategory) { - if (passportData.documentCategory === 'aadhaar') { - return useProtocolStore.getState().aadhaar.public_keys; + if (docCategory === 'aadhaar') { + const publicKeys = + useProtocolStore.getState().aadhaar.public_keys; + // Convert string[] to Record format expected by AlternativeCSCA + return publicKeys + ? Object.fromEntries(publicKeys.map(key => [key, key])) + : {}; } return useProtocolStore.getState()[docCategory].alternative_csca; }, diff --git a/app/src/screens/recovery/RecoverWithPhraseScreen.tsx b/app/src/screens/recovery/RecoverWithPhraseScreen.tsx index 0c94719ab..1e651b4e7 100644 --- a/app/src/screens/recovery/RecoverWithPhraseScreen.tsx +++ b/app/src/screens/recovery/RecoverWithPhraseScreen.tsx @@ -72,7 +72,11 @@ const RecoverWithPhraseScreen: React.FC = () => { }, getAltCSCA(docCategory) { if (docCategory === 'aadhaar') { - return useProtocolStore.getState()[docCategory].public_keys; + const publicKeys = useProtocolStore.getState().aadhaar.public_keys; + // Convert string[] to Record format expected by AlternativeCSCA + return publicKeys + ? Object.fromEntries(publicKeys.map(key => [key, key])) + : {}; } return useProtocolStore.getState()[docCategory].alternative_csca; }, diff --git a/app/src/screens/system/Loading.tsx b/app/src/screens/system/Loading.tsx index e5ceac9c6..397ae3d17 100644 --- a/app/src/screens/system/Loading.tsx +++ b/app/src/screens/system/Loading.tsx @@ -10,12 +10,10 @@ import { Text, YStack } from 'tamagui'; import type { StaticScreenProps } from '@react-navigation/native'; import { useIsFocused } from '@react-navigation/native'; -import { IDDocument } from '@selfxyz/common/dist/esm/src/utils/types'; -import type { PassportData } from '@selfxyz/common/types'; +import { IDDocument } from '@selfxyz/common/utils/types'; import failAnimation from '@/assets/animations/loading/fail.json'; import proveLoadingAnimation from '@/assets/animations/loading/prove.json'; -import successAnimation from '@/assets/animations/loading/success.json'; import CloseWarningIcon from '@/images/icons/close-warning.svg'; import { loadPassportDataAndSecret } from '@/providers/passportDataProvider'; import { black, slate400, white, zinc500, zinc900 } from '@/utils/colors'; diff --git a/app/src/stores/database.ts b/app/src/stores/database.ts index e782fc7d1..55d94008c 100644 --- a/app/src/stores/database.ts +++ b/app/src/stores/database.ts @@ -4,12 +4,8 @@ import SQLite from 'react-native-sqlite-storage'; -import type { - ProofDB, - ProofDBResult, - ProofHistory, -} from '@/stores/proof-types'; -import { ProofStatus } from '@/stores/proof-types'; +import type { ProofDB, ProofDBResult, ProofHistory } from '@/stores/proofTypes'; +import { ProofStatus } from '@/stores/proofTypes'; const PAGE_SIZE = 20; const DB_NAME = 'proof_history.db'; diff --git a/app/src/stores/database.web.ts b/app/src/stores/database.web.ts index 99c8a672c..21b7717a4 100644 --- a/app/src/stores/database.web.ts +++ b/app/src/stores/database.web.ts @@ -2,12 +2,8 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import type { - ProofDB, - ProofDBResult, - ProofHistory, -} from '@/stores/proof-types'; -import { ProofStatus } from '@/stores/proof-types'; +import type { ProofDB, ProofDBResult, ProofHistory } from '@/stores/proofTypes'; +import { ProofStatus } from '@/stores/proofTypes'; export const DB_NAME = 'proof_history_db'; const STORE_NAME = 'proof_history'; diff --git a/app/src/stores/proofHistoryStore.ts b/app/src/stores/proofHistoryStore.ts index 89ea31d11..48d25116d 100644 --- a/app/src/stores/proofHistoryStore.ts +++ b/app/src/stores/proofHistoryStore.ts @@ -8,8 +8,8 @@ import { create } from 'zustand'; import { WS_DB_RELAYER } from '@selfxyz/common/constants'; import { database } from '@/stores/database'; -import type { ProofHistory } from '@/stores/proof-types'; -import { ProofStatus } from '@/stores/proof-types'; +import type { ProofHistory } from '@/stores/proofTypes'; +import { ProofStatus } from '@/stores/proofTypes'; interface ProofHistoryState { proofHistory: ProofHistory[]; diff --git a/app/src/stores/proof-types.ts b/app/src/stores/proofTypes.ts similarity index 100% rename from app/src/stores/proof-types.ts rename to app/src/stores/proofTypes.ts diff --git a/app/src/types/country-iso-3-to-2.d.ts b/app/src/types/countryIso3To2.d.ts similarity index 100% rename from app/src/types/country-iso-3-to-2.d.ts rename to app/src/types/countryIso3To2.d.ts diff --git a/packages/mobile-sdk-alpha/demo-app/src/ProveQRCode.tsx b/app/src/types/elliptic.d.ts similarity index 63% rename from packages/mobile-sdk-alpha/demo-app/src/ProveQRCode.tsx rename to app/src/types/elliptic.d.ts index 25baf9b3a..b746be8d6 100644 --- a/packages/mobile-sdk-alpha/demo-app/src/ProveQRCode.tsx +++ b/app/src/types/elliptic.d.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -export default function ProveQRCode() { - // TODO: implement QR code proof - return null; +declare module 'elliptic' { + const elliptic: any; + export = elliptic; } diff --git a/app/src/types/png.d.ts b/app/src/types/png.d.ts index 031ff0ecb..85881324c 100644 --- a/app/src/types/png.d.ts +++ b/app/src/types/png.d.ts @@ -3,6 +3,8 @@ // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. declare module '*.png' { - const content: any; - export default content; + import type { ImageSourcePropType } from 'react-native'; + + const pngContent: ImageSourcePropType; + export default pngContent; } diff --git a/app/src/types/react-native-passport-reader.d.ts b/app/src/types/reactNativePassportReader.d.ts similarity index 100% rename from app/src/types/react-native-passport-reader.d.ts rename to app/src/types/reactNativePassportReader.d.ts diff --git a/app/src/types/svg.d.ts b/app/src/types/svg.d.ts index 765c05aaa..2cf977a93 100644 --- a/app/src/types/svg.d.ts +++ b/app/src/types/svg.d.ts @@ -6,6 +6,6 @@ declare module '*.svg' { import type React from 'react'; import type { SvgProps } from 'react-native-svg'; - const content: React.FC; - export default content; + const svgContent: React.FC; + export default svgContent; } diff --git a/app/src/utils/proving/provingMachine.ts b/app/src/utils/proving/provingMachine.ts index 674f3f765..3eccbe366 100644 --- a/app/src/utils/proving/provingMachine.ts +++ b/app/src/utils/proving/provingMachine.ts @@ -136,6 +136,11 @@ const _generateCircuitInputs = async ( circuitTypeWithDocumentExtension = `${circuitType}${document === 'passport' ? '' : '_id'}`; break; case 'dsc': + if (document === 'aadhaar') { + throw new Error( + 'DSC circuit type is not supported for Aadhaar documents', + ); + } ({ inputs, circuitName, endpointType, endpoint } = generateTEEInputsDSC( passportData as PassportData, protocolStore[document].csca_tree as string[][], @@ -1014,7 +1019,7 @@ export const useProvingStore = create((set, get) => { step: 'protocol_store_fetch', document, }); - await useProtocolStore.getState()[document].fetch_all(env!); + await useProtocolStore.getState().aadhaar.fetch_all(env!); break; } logProofEvent('info', 'Data fetch succeeded', context, { @@ -1114,10 +1119,17 @@ export const useProvingStore = create((set, get) => { secret as string, { getCommitmentTree, - getAltCSCA: (docType: DocumentCategory) => - docType === 'aadhaar' - ? useProtocolStore.getState().aadhaar.public_keys - : useProtocolStore.getState()[docType].alternative_csca, + getAltCSCA: (docType: DocumentCategory) => { + if (docType === 'aadhaar') { + const publicKeys = + useProtocolStore.getState().aadhaar.public_keys; + // Convert string[] to Record format expected by AlternativeCSCA + return publicKeys + ? Object.fromEntries(publicKeys.map(key => [key, key])) + : {}; + } + return useProtocolStore.getState()[docType].alternative_csca; + }, }, ); logProofEvent( diff --git a/app/tests/src/stores/database.test.ts b/app/tests/src/stores/database.test.ts index 268478de1..680c23b8c 100644 --- a/app/tests/src/stores/database.test.ts +++ b/app/tests/src/stores/database.test.ts @@ -5,7 +5,7 @@ import SQLite from 'react-native-sqlite-storage'; import { database } from '@/stores/database'; -import { ProofStatus } from '@/stores/proof-types'; +import { ProofStatus } from '@/stores/proofTypes'; // Mock react-native-sqlite-storage jest.mock('react-native-sqlite-storage', () => ({ diff --git a/app/tests/src/stores/proofHistoryStore.test.ts b/app/tests/src/stores/proofHistoryStore.test.ts index c4793204d..10d2c46d0 100644 --- a/app/tests/src/stores/proofHistoryStore.test.ts +++ b/app/tests/src/stores/proofHistoryStore.test.ts @@ -6,8 +6,8 @@ import { io } from 'socket.io-client'; import { act } from '@testing-library/react-native'; import { database } from '@/stores/database'; -import { ProofStatus } from '@/stores/proof-types'; import { useProofHistoryStore } from '@/stores/proofHistoryStore'; +import { ProofStatus } from '@/stores/proofTypes'; // Mock socket.io-client jest.mock('socket.io-client', () => ({ diff --git a/app/tests/utils/proving/provingMachine.startFetchingData.test.ts b/app/tests/utils/proving/provingMachine.startFetchingData.test.ts index 6dd4c4dac..8a230046c 100644 --- a/app/tests/utils/proving/provingMachine.startFetchingData.test.ts +++ b/app/tests/utils/proving/provingMachine.startFetchingData.test.ts @@ -39,18 +39,46 @@ jest.mock('@/providers/authProvider', () => ({ // app/tests/utils/proving/provingMachine.startFetchingData.test.ts -jest.mock('@selfxyz/mobile-sdk-alpha', () => { - const actual = jest.requireActual('@selfxyz/mobile-sdk-alpha'); +jest.mock('@selfxyz/mobile-sdk-alpha', () => ({ + __esModule: true, + // Mock only the specific functions needed by this test + loadSelectedDocument: jest.fn().mockResolvedValue({ + data: { + documentCategory: 'passport', + mock: false, + dsc_parsed: { authorityKeyIdentifier: 'key' }, + }, + }), +})); + +// Mock the stores import separately with state management +jest.mock('@selfxyz/mobile-sdk-alpha/stores', () => { + const mockProtocolStoreState = {}; + const mockSelfAppStoreState = { selfApp: {}, handleProofResult: jest.fn() }; + return { - __esModule: true, - ...actual, - loadSelectedDocument: jest.fn().mockResolvedValue({ - data: { - documentCategory: 'passport', - mock: false, - dsc_parsed: { authorityKeyIdentifier: 'key' }, + useProtocolStore: Object.assign( + jest.fn(() => mockProtocolStoreState), + { + // Add Zustand store methods with state management + setState: jest.fn(updates => + Object.assign(mockProtocolStoreState, updates), + ), + getState: jest.fn(() => mockProtocolStoreState), + subscribe: jest.fn(() => jest.fn()), + }, + ), + useSelfAppStore: Object.assign( + jest.fn(() => mockSelfAppStoreState), + { + // Add Zustand store methods with state management + setState: jest.fn(updates => + Object.assign(mockSelfAppStoreState, updates), + ), + getState: jest.fn(() => mockSelfAppStoreState), + subscribe: jest.fn(() => jest.fn()), }, - }), + ), }; }); diff --git a/app/tests/utils/proving/provingMachine.test.ts b/app/tests/utils/proving/provingMachine.test.ts index 76afb7023..54cf078f3 100644 --- a/app/tests/utils/proving/provingMachine.test.ts +++ b/app/tests/utils/proving/provingMachine.test.ts @@ -16,15 +16,21 @@ jest.mock('@/navigation', () => ({ }, })); -jest.mock('@selfxyz/mobile-sdk-alpha', () => { - const actual = jest.requireActual('@selfxyz/mobile-sdk-alpha'); - - return { - ...actual, - loadSelectedDocument: jest.fn().mockResolvedValue(null), - hasAnyValidRegisteredDocument: jest.fn().mockResolvedValue(true), - }; -}); +jest.mock('@selfxyz/mobile-sdk-alpha', () => ({ + // Mock only the exports needed by this test + SdkEvents: { + DOCUMENT_SELECTED: 'DOCUMENT_SELECTED', + DOCUMENT_LOADED: 'DOCUMENT_LOADED', + REGISTRATION_COMPLETED: 'REGISTRATION_COMPLETED', + PROVING_PASSPORT_DATA_NOT_FOUND: 'PROVING_PASSPORT_DATA_NOT_FOUND', + PROVING_PASSPORT_NOT_SUPPORTED: 'PROVING_PASSPORT_NOT_SUPPORTED', + PROVING_ACCOUNT_RECOVERY_REQUIRED: 'PROVING_ACCOUNT_RECOVERY_REQUIRED', + PROVING_ACCOUNT_VERIFIED_SUCCESS: 'PROVING_ACCOUNT_VERIFIED_SUCCESS', + PROVING_REGISTER_ERROR_OR_FAILURE: 'PROVING_REGISTER_ERROR_OR_FAILURE', + }, + loadSelectedDocument: jest.fn().mockResolvedValue(null), + hasAnyValidRegisteredDocument: jest.fn().mockResolvedValue(true), +})); describe('provingMachine registration completion', () => { beforeEach(() => { diff --git a/app/tsconfig.json b/app/tsconfig.json index b4651bb3a..38ac62482 100644 --- a/app/tsconfig.json +++ b/app/tsconfig.json @@ -3,23 +3,17 @@ "compilerOptions": { "lib": ["dom", "esnext"], "module": "esnext", + "baseUrl": ".", "resolveJsonModule": true, "esModuleInterop": true, + "skipLibCheck": true, + "skipDefaultLibCheck": false, "paths": { "@env": ["./env.ts"], - "@selfxyz/common": ["../common"], - "@selfxyz/common/*": ["../common/*"], - "@selfxyz/common/utils/passports/*": ["../common/utils/passports/*"], "@selfxyz/mobile-sdk-alpha": [ "../packages/mobile-sdk-alpha/src", "../packages/mobile-sdk-alpha/dist" ], - "@selfxyz/mobile-sdk-alpha/constants/analytics": [ - "../packages/mobile-sdk-alpha/dist/esm/constants/analytics.js" - ], - "@selfxyz/mobile-sdk-alpha/stores": [ - "../packages/mobile-sdk-alpha/dist/esm/stores.js" - ], "@/*": ["./src/*"] } }, diff --git a/app/vite.config.ts b/app/vite.config.ts index 243279557..1494b0833 100644 --- a/app/vite.config.ts +++ b/app/vite.config.ts @@ -50,10 +50,30 @@ export default defineConfig({ __dirname, 'src/mocks/react-native-passport-reader.ts', ), - crypto: 'crypto-browserify', + '@/utils/nfcScanner': resolve(__dirname, 'src/mocks/nfcScanner.ts'), + crypto: resolve(__dirname, '../common/src/polyfills/crypto.ts'), + buffer: 'buffer', + + // Fix @noble/hashes subpath exports for web builds + '@noble/hashes/crypto.js': '@noble/hashes/crypto', }, }, plugins: [ + { + name: 'fix-buffer-externalization', + transform(code, id) { + // Fix the mobile-sdk-alpha chunk that references Buffer + if (id.includes('mobile-sdk-alpha') && code.includes('from "buffer"')) { + // Keep the import so the polyfill is bundled, and set global assignment + const fixedCode = code.replace( + /import\s+\{\s*Buffer\s*\}\s+from\s+['"]buffer['"]/g, + "import { Buffer } from 'buffer';\nif (typeof globalThis.Buffer === 'undefined') { globalThis.Buffer = Buffer; }", + ); + return { code: fixedCode, map: null }; + } + return null; + }, + }, react(), svgr({ include: '**/*.svg', @@ -85,6 +105,7 @@ export default defineConfig({ global: 'globalThis', }, optimizeDeps: { + include: ['buffer'], exclude: ['fs', 'path', 'child_process', '@zk-email/helpers'], esbuildOptions: { // Optimize minification @@ -93,7 +114,6 @@ export default defineConfig({ minifyWhitespace: true, }, }, - build: { emptyOutDir: true, outDir: resolve(__dirname, 'web/dist'), @@ -103,7 +123,7 @@ export default defineConfig({ cssMinify: true, cssCodeSplit: true, rollupOptions: { - external: ['fs', 'child_process'], + external: ['fs', 'child_process', '@zk-email/helpers'], output: { // Optimize chunk size and minification compact: true, diff --git a/app/web/index.html b/app/web/index.html index 82d06b41d..5b3bddcc5 100644 --- a/app/web/index.html +++ b/app/web/index.html @@ -5,6 +5,22 @@ Self App + +
diff --git a/packages/mobile-sdk-alpha/demo-app/babel.config.js b/babel.config.js similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/babel.config.js rename to babel.config.js diff --git a/common/index.ts b/common/index.ts index a7174d797..0546c71d9 100644 --- a/common/index.ts +++ b/common/index.ts @@ -2,8 +2,13 @@ export type { AadhaarData, CertificateData, + DeployedCircuits, + DocumentCatalog, DocumentCategory, + DocumentMetadata, + IDDocument, IdDocInput, + OfacTree, PassportData, PassportMetadata, PublicKeyDetailsECDSA, @@ -57,6 +62,7 @@ export { bigIntToString, brutforceSignatureAlgorithmDsc, buildSMT, + calculateContentHash, calculateUserIdentifierHash, findStartPubKeyIndex, formatEndpoint, @@ -74,10 +80,13 @@ export { getCircuitNameFromPassportData, getLeafCscaTree, getLeafDscTree, + fetchOfacTrees, getSKIPEM, + generateTEEInputsDiscloseStateless, getSolidityPackedUserContextData, getUniversalLink, hashEndpointWithScope, + inferDocumentCategory, initElliptic, initPassportDataParsing, parseCertificateSimple, @@ -85,6 +94,15 @@ export { stringToBigInt, } from './src/utils/index.js'; +// Crypto polyfill for cross-platform compatibility +export { + createHash, + createHmac, + default as cryptoPolyfill, + pbkdf2Sync, + randomBytes, +} from './src/polyfills/crypto.js'; + export { createSelector } from './src/utils/aadhaar/constants.js'; // Hash utilities diff --git a/common/package.json b/common/package.json index d67130bb7..17a884401 100644 --- a/common/package.json +++ b/common/package.json @@ -661,6 +661,7 @@ }, "dependencies": { "@anon-aadhaar/core": "npm:@selfxyz/anon-aadhaar-core@^0.0.1", + "@noble/hashes": "^1.5.0", "@openpassport/zk-kit-imt": "^0.0.5", "@openpassport/zk-kit-lean-imt": "^0.0.6", "@openpassport/zk-kit-smt": "^0.0.1", diff --git a/common/src/polyfills/crypto.ts b/common/src/polyfills/crypto.ts new file mode 100644 index 000000000..ceea9fc57 --- /dev/null +++ b/common/src/polyfills/crypto.ts @@ -0,0 +1,177 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +/** + * Crypto polyfill using @noble/hashes for web builds + * This replaces crypto-browserify with a more modern and secure implementation + */ + +import { hmac } from '@noble/hashes/hmac'; +import { md5 as nobleMd5 } from '@noble/hashes/legacy'; +import { pbkdf2 as noblePbkdf2 } from '@noble/hashes/pbkdf2'; +import { sha1 as nobleSha1 } from '@noble/hashes/sha1'; +import { sha256 as nobleSha256 } from '@noble/hashes/sha256'; +import { sha512 as nobleSha512 } from '@noble/hashes/sha512'; + +// Create hash instances that mimic Node.js crypto API +function createHash(algorithm: string) { + const alg = algorithm.toLowerCase(); + + let hasher: any; + + switch (alg) { + case 'sha1': + hasher = nobleSha1.create(); + break; + case 'sha256': + hasher = nobleSha256.create(); + break; + case 'sha512': + hasher = nobleSha512.create(); + break; + case 'md5': + hasher = nobleMd5.create(); + break; + default: + throw new Error(`Unsupported hash algorithm: ${algorithm}`); + } + + let finalized = false; + + return { + update(data: string | Uint8Array) { + if (finalized) { + throw new Error('Cannot update after calling digest(). Hash instance has been finalized.'); + } + if (typeof data === 'string') { + hasher.update(new TextEncoder().encode(data)); + } else { + hasher.update(data); + } + return this; + }, + digest(encoding?: BufferEncoding) { + if (finalized) { + throw new Error('Digest already called. Hash instance has been finalized.'); + } + finalized = true; + const result = hasher.digest(); + + if (encoding === 'hex') { + return Array.from(result) + .map((b: number) => b.toString(16).padStart(2, '0')) + .join(''); + } + return typeof Buffer !== 'undefined' ? Buffer.from(result) : result; + }, + }; +} + +function createHmac(algorithm: string, key: string | Uint8Array) { + const alg = algorithm.toLowerCase(); + + let hashFn: any; + + switch (alg) { + case 'sha1': + hashFn = nobleSha1; + break; + case 'sha256': + hashFn = nobleSha256; + break; + case 'sha512': + hashFn = nobleSha512; + break; + default: + throw new Error(`Unsupported HMAC algorithm: ${algorithm}`); + } + + const keyBytes = typeof key === 'string' ? new TextEncoder().encode(key) : key; + const hmacState = hmac.create(hashFn, keyBytes); + let finalized = false; + + return { + update(data: string | Uint8Array) { + if (finalized) { + throw new Error('Cannot update after calling digest(). Hash instance has been finalized.'); + } + const dataBytes = typeof data === 'string' ? new TextEncoder().encode(data) : data; + hmacState.update(dataBytes); + return this; + }, + digest(encoding?: BufferEncoding) { + if (finalized) { + throw new Error('Digest already called. Hash instance has been finalized.'); + } + finalized = true; + const result = hmacState.digest(); + + if (encoding === 'hex') { + return Array.from(result) + .map((b: number) => b.toString(16).padStart(2, '0')) + .join(''); + } + return typeof Buffer !== 'undefined' ? Buffer.from(result) : result; + }, + }; +} + +function randomBytes(size: number): Uint8Array | Buffer { + if (!Number.isInteger(size) || size <= 0) { + throw new Error('randomBytes size must be a positive integer'); + } + const cryptoObj = globalThis.crypto; + if (typeof cryptoObj?.getRandomValues !== 'function') { + throw new Error('globalThis.crypto.getRandomValues is not available'); + } + const out = new Uint8Array(size); + const MAX = 65536; // WebCrypto limit per call + for (let offset = 0; offset < size; offset += MAX) { + cryptoObj.getRandomValues(out.subarray(offset, Math.min(offset + MAX, size))); + } + return typeof Buffer !== 'undefined' ? Buffer.from(out) : out; +} + +function pbkdf2Sync( + password: string | Uint8Array, + salt: string | Uint8Array, + iterations: number, + keylen: number, + digest: string +): Uint8Array | Buffer { + const passwordBytes = + typeof password === 'string' ? new TextEncoder().encode(password) : password; + const saltBytes = typeof salt === 'string' ? new TextEncoder().encode(salt) : salt; + + let hashFn: any; + switch (digest.toLowerCase()) { + case 'sha1': + hashFn = nobleSha1; + break; + case 'sha256': + hashFn = nobleSha256; + break; + case 'sha512': + hashFn = nobleSha512; + break; + default: + throw new Error(`Unsupported PBKDF2 digest: ${digest}`); + } + + const derivedKey = noblePbkdf2(hashFn, passwordBytes, saltBytes, { + c: iterations, + dkLen: keylen, + }); + return typeof Buffer !== 'undefined' ? Buffer.from(derivedKey) : derivedKey; +} + +// Export crypto-like interface +export default { + createHash, + createHmac, + randomBytes, + pbkdf2Sync, +}; + +export { createHash, createHmac, pbkdf2Sync, randomBytes }; diff --git a/common/src/types/globals.d.ts b/common/src/types/globals.d.ts new file mode 100644 index 000000000..bf68989ed --- /dev/null +++ b/common/src/types/globals.d.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +declare global { + /** + * Development mode flag + * Set to true when running in development mode, false in production + */ + const __DEV__: boolean; +} + +export {}; diff --git a/common/src/types/index.ts b/common/src/types/index.ts index 84f11c052..3de702c3c 100644 --- a/common/src/types/index.ts +++ b/common/src/types/index.ts @@ -1,3 +1,9 @@ -export type { DocumentCategory, DocumentType, PassportData } from '../utils/types.js'; +export type { + DocumentCatalog, + DocumentCategory, + DocumentMetadata, + DocumentType, + PassportData, +} from '../utils/types.js'; export type { PassportMetadata } from '../utils/passports/passport_parsing/parsePassportData.js'; export type { UserIdType } from '../utils/circuits/uuid.js'; diff --git a/common/src/utils/bytes.ts b/common/src/utils/bytes.ts index ffd9deeca..850ca3e95 100644 --- a/common/src/utils/bytes.ts +++ b/common/src/utils/bytes.ts @@ -91,7 +91,7 @@ export function num2Bits(n: number, inValue: bigint): bigint[] { return out; } -export function packBytes(unpacked) { +export function packBytes(unpacked: number[]) { const bytesCount = [31, 31, 31]; const packed = [0n, 0n, 0n]; diff --git a/common/src/utils/certificate_parsing/curves.ts b/common/src/utils/certificate_parsing/curves.ts index 283ae9fb0..b572be4da 100644 --- a/common/src/utils/certificate_parsing/curves.ts +++ b/common/src/utils/certificate_parsing/curves.ts @@ -9,7 +9,7 @@ export interface StandardCurve { } export function getCurveForElliptic(curveName: string): string { - const curves = { + const curves: Record = { secp224r1: 'p224', secp256r1: 'p256', secp384r1: 'p384', diff --git a/common/src/utils/index.ts b/common/src/utils/index.ts index f152e13c7..c7fb6220e 100644 --- a/common/src/utils/index.ts +++ b/common/src/utils/index.ts @@ -1,21 +1,24 @@ -export type { AadhaarData, DocumentCategory, PassportData } from './types.js'; +export type { + AadhaarData, + DeployedCircuits, + DocumentCatalog, + DocumentCategory, + DocumentMetadata, + IDDocument, + OfacTree, + PassportData, +} from './types.js'; export type { CertificateData, PublicKeyDetailsECDSA, PublicKeyDetailsRSA, } from './certificate_parsing/dataStructure.js'; +export type { EndpointType, Mode, SelfApp, SelfAppDisclosureConfig } from './appType.js'; export type { IdDocInput } from './passports/genMockIdDoc.js'; export type { PassportMetadata } from './passports/passport_parsing/parsePassportData.js'; export type { TEEPayload, TEEPayloadBase, TEEPayloadDisclose } from './proving.js'; export type { UserIdType } from './circuits/uuid.js'; -export { - EndpointType, - Mode, - SelfApp, - SelfAppBuilder, - SelfAppDisclosureConfig, - getUniversalLink, -} from './appType.js'; +export { SelfAppBuilder, getUniversalLink } from './appType.js'; export { bigIntToString, formatEndpoint, hashEndpointWithScope, stringToBigInt } from './scope.js'; export { brutforceSignatureAlgorithmDsc } from './passports/passport_parsing/brutForceDscSignature.js'; export { buildSMT, getLeafCscaTree, getLeafDscTree } from './trees.js'; @@ -27,7 +30,6 @@ export { inferDocumentCategory, initPassportDataParsing, } from './passports/passport.js'; -export { isAadhaarDocument, isMRZDocument } from './types.js'; export { calculateUserIdentifierHash, customHasher, @@ -47,6 +49,7 @@ export { } from './proving.js'; export { extractQRDataFields, getAadharRegistrationWindow } from './aadhaar/utils.js'; export { formatMrz } from './passports/format.js'; +export { fetchOfacTrees } from './ofac.js'; export { genAndInitMockPassportData } from './passports/genMockPassportData.js'; export { genMockIdDoc, @@ -62,9 +65,11 @@ export { export { generateTEEInputsAadhaarDisclose, generateTEEInputsAadhaarRegister, + generateTEEInputsDiscloseStateless, } from './circuits/registerInputs.js'; export { getCircuitNameFromPassportData } from './circuits/circuitsName.js'; export { getSKIPEM } from './csca.js'; export { initElliptic } from './certificate_parsing/elliptic.js'; +export { isAadhaarDocument, isMRZDocument } from './types.js'; export { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple.js'; export { parseDscCertificateData } from './passports/passport_parsing/parseDscCertificateData.js'; diff --git a/common/tests/cryptoHash.test.ts b/common/tests/cryptoHash.test.ts new file mode 100644 index 000000000..996b4d1c9 --- /dev/null +++ b/common/tests/cryptoHash.test.ts @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +import { createHash } from '../src/polyfills/crypto'; +import { sha256 } from '@noble/hashes/sha256'; + +describe('Hash Finalization', () => { + const message = 'Hello World!'; + + it('should throw on subsequent digest calls (Node.js parity)', () => { + const hashInstance = createHash('sha256'); + hashInstance.update(message); + + const digest1 = hashInstance.digest('hex'); + expect(typeof digest1).toBe('string'); + expect(digest1.length).toBe(64); // SHA256 hex is 64 chars + + // Subsequent digest calls should throw + expect(() => hashInstance.digest('hex')).toThrow(/Digest already called/); + expect(() => hashInstance.digest()).toThrow(/Digest already called/); + + // Updates should also throw after finalization + expect(() => hashInstance.update('more data')).toThrow(/Cannot update after calling digest/); + }); + + it('should produce correct hash before finalization', () => { + const hashInstance = createHash('sha256'); + hashInstance.update(message); + + // Expected result from @noble/hashes + const expected = sha256(new TextEncoder().encode(message)); + const expectedHex = Array.from(expected) + .map((b: number) => b.toString(16).padStart(2, '0')) + .join(''); + + // Test hex digest + const hexResult = hashInstance.digest('hex'); + expect(hexResult).toBe(expectedHex); + }); + + it('should produce correct binary digest before finalization', () => { + const hashInstance = createHash('sha256'); + hashInstance.update(message); + + // Expected result from @noble/hashes + const expected = sha256(new TextEncoder().encode(message)); + + // Test binary digest + const binaryResult = hashInstance.digest(); + // Convert to Uint8Array for comparison (handles both Buffer and Uint8Array cases) + const resultArray = new Uint8Array(binaryResult); + + expect(resultArray).toEqual(expected); + }); +}); diff --git a/common/tests/cryptoHmac.test.ts b/common/tests/cryptoHmac.test.ts new file mode 100644 index 000000000..200764927 --- /dev/null +++ b/common/tests/cryptoHmac.test.ts @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +import { createHmac } from '../src/polyfills/crypto'; +import { hmac } from '@noble/hashes/hmac'; +import { sha256 } from '@noble/hashes/sha256'; + +describe('HMAC Streaming', () => { + const key = 'test-key'; + const message1 = 'Hello '; + const message2 = 'World!'; + const fullMessage = message1 + message2; + + it('should produce the same result for single vs multiple update calls', () => { + // Expected result: compute HMAC of full message in one go + const expected = hmac( + sha256, + new TextEncoder().encode(key), + new TextEncoder().encode(fullMessage) + ); + const expectedHex = Array.from(expected) + .map((b: number) => b.toString(16).padStart(2, '0')) + .join(''); + + // Single update call + const hmacSingle = createHmac('sha256', key); + hmacSingle.update(fullMessage); + const singleResult = hmacSingle.digest('hex'); + + // Multiple update calls (this should be equivalent but currently fails) + const hmacMultiple = createHmac('sha256', key); + hmacMultiple.update(message1); + hmacMultiple.update(message2); + const multipleResult = hmacMultiple.digest('hex'); + + // These should all be equal + expect(singleResult).toBe(expectedHex); + expect(multipleResult).toBe(expectedHex); + expect(singleResult).toBe(multipleResult); + }); + + it('should handle binary data correctly with streaming', () => { + const chunk1 = new Uint8Array([1, 2, 3]); + const chunk2 = new Uint8Array([4, 5, 6]); + const fullData = new Uint8Array([1, 2, 3, 4, 5, 6]); + + // Expected result + const expected = hmac(sha256, new TextEncoder().encode(key), fullData); + + // Single update + const hmacSingle = createHmac('sha256', key); + hmacSingle.update(fullData); + const singleResult = hmacSingle.digest(); + + // Multiple updates + const hmacMultiple = createHmac('sha256', key); + hmacMultiple.update(chunk1); + hmacMultiple.update(chunk2); + const multipleResult = hmacMultiple.digest(); + + // Convert to Uint8Array for comparison (handles both Buffer and Uint8Array cases) + const singleArray = new Uint8Array(singleResult); + const multipleArray = new Uint8Array(multipleResult); + + expect(singleArray).toEqual(expected); + expect(multipleArray).toEqual(expected); + expect(singleArray).toEqual(multipleArray); + }); + + it('should throw on subsequent digest calls (Node.js parity)', () => { + const hmacInstance = createHmac('sha256', key); + hmacInstance.update(fullMessage); + + const digest1 = hmacInstance.digest('hex'); + expect(typeof digest1).toBe('string'); + expect(digest1.length).toBe(64); // SHA256 hex is 64 chars + + // Subsequent digest calls should throw + expect(() => hmacInstance.digest('hex')).toThrow(); + expect(() => hmacInstance.digest()).toThrow(); + + // Updates should also throw after finalization + expect(() => hmacInstance.update('more data')).toThrow(); + }); +}); diff --git a/package.json b/package.json index 5ea4bfeaf..5d4f3e921 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,23 @@ { "name": "self-workspace-root", - "workspaces": [ - "app", - "circuits", - "common", - "contracts", - "packages/*", - "prover/tests", - "sdk/*", - "scripts/tests", - "packages/mobile-sdk-alpha/demo-app" - ], + "workspaces": { + "packages": [ + "app", + "circuits", + "common", + "contracts", + "packages/*", + "prover/tests", + "scripts/tests", + "sdk/*" + ] + }, "scripts": { - "build": "yarn workspaces foreach --topological-dev --parallel --exclude @selfxyz/contracts -i --all run build", + "build": "yarn workspaces foreach --topological-dev --parallel --exclude @selfxyz/contracts --exclude @selfxyz/circuits --exclude mobile-sdk-demo -i --all run build", + "build:demo": "yarn workspace mobile-sdk-demo build", + "build:mobile-sdk": "yarn workspace @selfxyz/mobile-sdk-alpha build", "check:versions": "node scripts/check-package-versions.mjs", + "demo:mobile": "yarn build:mobile-sdk && yarn build:demo && yarn workspace mobile-sdk-demo start", "format": "SKIP_BUILD_DEPS=1 yarn format:root && yarn format:github && SKIP_BUILD_DEPS=1 yarn workspaces foreach --parallel -i --all --exclude self-workspace-root run format", "format:github": "yarn prettier --parser yaml --write .github/**/*.yml --single-quote false", "format:root": "echo 'format markdown' && yarn prettier --parser markdown --write *.md && echo 'format yaml' && yarn prettier --parser yaml --write .*.{yml,yaml} --single-quote false && yarn prettier --write scripts/**/*.{js,mjs,ts} && yarn prettier --parser json --write scripts/**/*.json", @@ -23,11 +27,11 @@ "lint:headers": "node scripts/check-duplicate-headers.cjs . && node scripts/check-license-headers.mjs . --check", "lint:headers:fix": "node scripts/check-duplicate-headers.cjs . && node scripts/check-license-headers.mjs . --fix", "prepare": "husky", - "reinstall-app": "rm -rf node_modules app/node_modules && yarn install && yarn workspace @selfxyz/mobile-app run install-app", + "reinstall-app": "yarn install && (cd app && yarn clean:watchman && yarn clean:build && yarn clean:ios && yarn clean:xcode && yarn clean:pod-cache && yarn clean:android-deps && rm -rf app/node_modules) && yarn install && yarn workspace @selfxyz/mobile-app run install-app", "sort-package-jsons": "find . -name 'package.json' -not -path './node_modules/*' -not -path './*/node_modules/*' | xargs npx sort-package-json", "test": "yarn workspaces foreach --parallel -i --all run test", "test:license-headers": "cd scripts/tests && node check-license-headers.test.mjs", - "types": "yarn workspaces foreach --topological-dev --parallel --exclude @selfxyz/contracts -i --all run types " + "types": "yarn workspaces foreach --topological-dev --parallel --exclude @selfxyz/contracts --exclude @selfxyz/common --exclude @selfxyz/mobile-app -i --all run types" }, "resolutions": { "@babel/core": "^7.28.4", @@ -38,9 +42,17 @@ "@types/react": "^18.3.4", "punycode": "npm:punycode.js@^2.3.1", "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-native": "0.76.9" + }, + "dependencies": { + "@babel/runtime": "^7.28.3", + "js-sha1": "^0.7.0", + "react": "^18.3.1", "react-native": "0.76.9" }, "devDependencies": { + "@react-native-community/cli-server-api": "^16.0.3", "@types/node": "^22.18.3", "gitleaks": "1.0.0", "husky": "9.1.7", diff --git a/packages/mobile-sdk-alpha/.eslintignore b/packages/mobile-sdk-alpha/.eslintignore index 73bac7a1a..e69de29bb 100644 --- a/packages/mobile-sdk-alpha/.eslintignore +++ b/packages/mobile-sdk-alpha/.eslintignore @@ -1 +0,0 @@ -demo-app/** diff --git a/packages/mobile-sdk-alpha/.eslintrc.cjs b/packages/mobile-sdk-alpha/.eslintrc.cjs index abd9cf6a3..33612a6f2 100644 --- a/packages/mobile-sdk-alpha/.eslintrc.cjs +++ b/packages/mobile-sdk-alpha/.eslintrc.cjs @@ -8,11 +8,13 @@ module.exports = { parserOptions: { ecmaVersion: 2021, sourceType: 'module', - ecmaFeatures: { jsx: false }, + ecmaFeatures: { jsx: true }, }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', 'plugin:import/recommended', 'plugin:import/typescript', 'plugin:prettier/recommended', @@ -20,6 +22,9 @@ module.exports = { plugins: ['simple-import-sort', 'import', 'sort-exports'], ignorePatterns: ['dist/', 'node_modules/'], settings: { + react: { + version: 'detect', + }, 'import/resolver': { typescript: { alwaysTryTypes: true, @@ -67,6 +72,8 @@ module.exports = { '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], // Add prettier rule to show prettier errors as ESLint errors 'prettier/prettier': ['warn', {}, { usePrettierrc: true }], + // Disable prop-types for TypeScript files since we use TypeScript types + 'react/prop-types': 'off', }, overrides: [ { diff --git a/packages/mobile-sdk-alpha/.prettierignore b/packages/mobile-sdk-alpha/.prettierignore index 2516c633d..de4d1f007 100644 --- a/packages/mobile-sdk-alpha/.prettierignore +++ b/packages/mobile-sdk-alpha/.prettierignore @@ -1,4 +1,2 @@ dist node_modules -demo-app/android -demo-app/ios diff --git a/packages/mobile-sdk-alpha/README.md b/packages/mobile-sdk-alpha/README.md index 4f71acac7..d393e2a17 100644 --- a/packages/mobile-sdk-alpha/README.md +++ b/packages/mobile-sdk-alpha/README.md @@ -109,22 +109,3 @@ describe('Real mobile-sdk-alpha Integration', () => { - `npm run validate:exports` — ensure named exports only. - `npm run validate:pkg` — check packaging and export conditions. - `npm run report:exports` — output current public symbols. - -## Self Demo App - -The Self Demo App is a lightweight React Native playground in [`demo-app`](./demo-app). - -```bash -# start Metro bundler -yarn workspace demo-app start - -# type-check -yarn workspace demo-app build - -# run tests -yarn workspace demo-app test - -# or via package scripts -cd packages/mobile-sdk-alpha -yarn run:demo -``` diff --git a/packages/mobile-sdk-alpha/demo-app/App.tsx b/packages/mobile-sdk-alpha/demo-app/App.tsx deleted file mode 100644 index 64548fc90..000000000 --- a/packages/mobile-sdk-alpha/demo-app/App.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. -// SPDX-License-Identifier: BUSL-1.1 -// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. - -import React from 'react'; -import { StyleSheet, Text, View } from 'react-native'; - -function App() { - return ( - - Self Demo App - Register Document - Generate Mock - Prove QR Code - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#fff', - }, - title: { - fontSize: 20, - marginBottom: 12, - fontWeight: 'bold', - }, - item: { - fontSize: 16, - marginVertical: 4, - }, -}); - -export default App; diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/build.gradle b/packages/mobile-sdk-alpha/demo-app/android/app/build.gradle deleted file mode 100644 index 219d424fd..000000000 --- a/packages/mobile-sdk-alpha/demo-app/android/app/build.gradle +++ /dev/null @@ -1,119 +0,0 @@ -apply plugin: "com.android.application" -apply plugin: "org.jetbrains.kotlin.android" -apply plugin: "com.facebook.react" - -/** - * This is the configuration block to customize your React Native Android app. - * By default you don't need to apply any configuration, just uncomment the lines you need. - */ -react { - /* Folders */ - // The root of your project, i.e. where "package.json" lives. Default is '../..' - root = file("../../../") - // The folder where the react-native NPM package is. Default is ../../node_modules/react-native - reactNativeDir = file("../../../node_modules/react-native") - // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen - codegenDir = file("../../../node_modules/@react-native/codegen") - // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js - cliFile = file("../../../node_modules/react-native/cli.js") - - /* Variants */ - // The list of variants to that are debuggable. For those we're going to - // skip the bundling of the JS bundle and the assets. By default is just 'debug'. - // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. - // debuggableVariants = ["liteDebug", "prodDebug"] - - /* Bundling */ - // A list containing the node command and its flags. Default is just 'node'. - // nodeExecutableAndArgs = ["node"] - // - // The command to run when bundling. By default is 'bundle' - // bundleCommand = "ram-bundle" - // - // The path to the CLI configuration file. Default is empty. - // bundleConfig = file(../rn-cli.config.js) - // - // The name of the generated asset file containing your JS bundle - // bundleAssetName = "MyApplication.android.bundle" - // - // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' - // entryFile = file("../js/MyApplication.android.js") - // - // A list of extra flags to pass to the 'bundle' commands. - // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle - // extraPackagerArgs = [] - - /* Hermes Commands */ - // The hermes compiler command to run. By default it is 'hermesc' - // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" - // - // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" - // hermesFlags = ["-O", "-output-source-map"] - - /* Autolinking */ - autolinkLibrariesWithApp() -} - -/** - * Set this to true to Run Proguard on Release builds to minify the Java bytecode. - */ -def enableProguardInReleaseBuilds = false - -/** - * The preferred build flavor of JavaScriptCore (JSC) - * - * For example, to use the international variant, you can use: - * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+` - * - * The international variant includes ICU i18n library and necessary data - * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that - * give correct results when using with locales other than en-US. Note that - * this variant is about 6MiB larger per architecture than default. - */ -def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' - -android { - ndkVersion rootProject.ext.ndkVersion - buildToolsVersion rootProject.ext.buildToolsVersion - compileSdk rootProject.ext.compileSdkVersion - - namespace "com.selfdemoapp" - defaultConfig { - applicationId "com.selfdemoapp" - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" - } - signingConfigs { - debug { - storeFile file('debug.keystore') - storePassword 'android' - keyAlias 'androiddebugkey' - keyPassword 'android' - } - } - buildTypes { - debug { - signingConfig signingConfigs.debug - } - release { - // Caution! In production, you need to generate your own keystore file. - // see https://reactnative.dev/docs/signed-apk-android. - signingConfig signingConfigs.debug - minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - } -} - -dependencies { - // The version of react-native is set by the React Native Gradle Plugin - implementation("com.facebook.react:react-android") - - if (hermesEnabled.toBoolean()) { - implementation("com.facebook.react:hermes-android") - } else { - implementation jscFlavor - } -} diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/java/com/selfdemoapp/MainActivity.kt b/packages/mobile-sdk-alpha/demo-app/android/app/src/main/java/com/selfdemoapp/MainActivity.kt deleted file mode 100644 index dafa2976f..000000000 --- a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/java/com/selfdemoapp/MainActivity.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.selfdemoapp - -import com.facebook.react.ReactActivity -import com.facebook.react.ReactActivityDelegate -import com.facebook.react.ReactApplication -import com.facebook.react.ReactNativeHost -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled -import com.facebook.react.defaults.DefaultReactActivityDelegate - -class MainActivity : ReactActivity() { - - /** - * Returns the name of the main component registered from JavaScript. This is used to schedule - * rendering of the component. - */ - override fun getMainComponentName(): String = "SelfDemoApp" - - /** - * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] - * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] - */ - override fun createReactActivityDelegate(): ReactActivityDelegate = - object : DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) { - override fun getReactNativeHost(): ReactNativeHost { - return (application as ReactApplication).reactNativeHost - } - } -} diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/java/com/selfdemoapp/MainApplication.kt b/packages/mobile-sdk-alpha/demo-app/android/app/src/main/java/com/selfdemoapp/MainApplication.kt deleted file mode 100644 index 053ce3903..000000000 --- a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/java/com/selfdemoapp/MainApplication.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.selfdemoapp - -import android.app.Application -import com.facebook.react.PackageList -import com.facebook.react.ReactApplication -import com.facebook.react.ReactNativeHost -import com.facebook.react.ReactPackage -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint -import com.facebook.react.defaults.DefaultReactNativeHost -import com.facebook.soloader.SoLoader -import com.facebook.react.soloader.OpenSourceMergedSoMapping - -class MainApplication : Application(), ReactApplication { - - override val reactNativeHost: ReactNativeHost = - object : DefaultReactNativeHost(this) { - override fun getPackages(): MutableList = - PackageList(this).packages.apply { - // Packages that cannot be autolinked yet can be added manually here, for example: - // add(MyReactNativePackage()) - } - - override fun getJSMainModuleName(): String = "index" - - override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG - - override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED - override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED - } - - override fun onCreate() { - super.onCreate() - // Initialize SoLoader with the merged mapping to support Hermes on RN 0.76+ - SoLoader.init(this, OpenSourceMergedSoMapping) - if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { - DefaultNewArchitectureEntryPoint.load() - } - } -} diff --git a/packages/mobile-sdk-alpha/demo-app/android/build.gradle b/packages/mobile-sdk-alpha/demo-app/android/build.gradle deleted file mode 100644 index 7092a7902..000000000 --- a/packages/mobile-sdk-alpha/demo-app/android/build.gradle +++ /dev/null @@ -1,21 +0,0 @@ -buildscript { - ext { - buildToolsVersion = "36.0.0" - minSdkVersion = 24 - compileSdkVersion = 36 - targetSdkVersion = 36 - ndkVersion = "27.0.12077973" - kotlinVersion = "2.1.20" - } - repositories { - google() - mavenCentral() - } - dependencies { - classpath("com.android.tools.build:gradle") - classpath("com.facebook.react:react-native-gradle-plugin") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") - } -} - -apply plugin: "com.facebook.react.rootproject" diff --git a/packages/mobile-sdk-alpha/demo-app/android/settings.gradle b/packages/mobile-sdk-alpha/demo-app/android/settings.gradle deleted file mode 100644 index fa197ee4d..000000000 --- a/packages/mobile-sdk-alpha/demo-app/android/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -pluginManagement { includeBuild("/Volumes/files/Projects/selfxyz/selfapp/node_modules/@react-native/gradle-plugin") } -plugins { id("com.facebook.react.settings") } -extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } -rootProject.name = 'SelfDemoApp' -include ':app' diff --git a/packages/mobile-sdk-alpha/demo-app/metro.config.cjs b/packages/mobile-sdk-alpha/demo-app/metro.config.cjs deleted file mode 100644 index 60b0a1955..000000000 --- a/packages/mobile-sdk-alpha/demo-app/metro.config.cjs +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. -// SPDX-License-Identifier: BUSL-1.1 -// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. - -const path = require('path'); -const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); - -const defaultConfig = getDefaultConfig(__dirname); - -const config = { - watchFolders: [ - path.resolve(__dirname, '../../..'), // monorepo root - ], - resolver: { - extraNodeModules: { - '@babel/runtime': path.resolve(__dirname, '../../../node_modules/@babel/runtime'), - // Pin React and React Native to monorepo root - react: path.resolve(__dirname, '../../../node_modules/react'), - 'react-native': path.resolve(__dirname, '../../../node_modules/react-native'), - // Crypto polyfills - stream: require.resolve('stream-browserify'), - buffer: require.resolve('buffer'), - util: require.resolve('util'), - assert: require.resolve('assert'), - }, - nodeModulesPaths: [path.resolve(__dirname, 'node_modules'), path.resolve(__dirname, '../../../node_modules')], - }, -}; - -module.exports = mergeConfig(defaultConfig, config); diff --git a/packages/mobile-sdk-alpha/demo-app/package.json b/packages/mobile-sdk-alpha/demo-app/package.json deleted file mode 100644 index 181566bb9..000000000 --- a/packages/mobile-sdk-alpha/demo-app/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "demo-app", - "version": "0.0.1", - "private": true, - "main": "index.js", - "scripts": { - "android": "react-native run-android", - "build": "tsc -p tsconfig.json --noEmit --pretty false", - "ios": "react-native run-ios", - "start": "react-native start", - "test": "jest" - }, - "dependencies": { - "@babel/runtime": "^7.28.3", - "@noble/hashes": "^1.5.0", - "@react-native/gradle-plugin": "0.76.9", - "assert": "^2.1.0", - "buffer": "^6.0.3", - "ethers": "^6.11.0", - "react": "^18.3.1", - "react-native": "0.76.9", - "react-native-get-random-values": "^1.11.0", - "stream-browserify": "^3.0.0", - "util": "^0.12.5" - }, - "devDependencies": { - "@babel/core": "^7.28.3", - "@tsconfig/react-native": "^3.0.6", - "@types/jest": "^29.5.14", - "@types/react": "^18.3.4", - "babel-jest": "^29.6.3", - "jest": "^29.6.3", - "metro-react-native-babel-preset": "0.76.9", - "react-test-renderer": "^18.3.1", - "typescript": "^5.9.2" - } -} diff --git a/packages/mobile-sdk-alpha/package.json b/packages/mobile-sdk-alpha/package.json index 02a0dba92..33dba6a4e 100644 --- a/packages/mobile-sdk-alpha/package.json +++ b/packages/mobile-sdk-alpha/package.json @@ -14,16 +14,22 @@ "exports": { ".": { "types": "./dist/esm/index.d.ts", + "react-native": "./dist/esm/index.js", "browser": "./dist/esm/browser.js", "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.cjs", - "default": "./dist/esm/index.js" + "require": "./dist/cjs/index.cjs" }, "./browser": { "types": "./dist/esm/browser.d.ts", "import": "./dist/esm/browser.js", "require": "./dist/cjs/browser.cjs" }, + "./constants": { + "types": "./dist/esm/constants/index.d.ts", + "react-native": "./dist/esm/constants/index.js", + "import": "./dist/esm/constants/index.js", + "require": "./dist/cjs/constants/index.cjs" + }, "./stores": { "types": "./dist/esm/stores.d.ts", "import": "./dist/esm/stores.js", @@ -31,12 +37,26 @@ }, "./constants/analytics": { "types": "./dist/esm/constants/analytics.d.ts", + "react-native": "./dist/esm/constants/analytics.js", "import": "./dist/esm/constants/analytics.js", "require": "./dist/cjs/constants/analytics.cjs" + }, + "./components": { + "types": "./dist/esm/components/index.d.ts", + "react-native": "./dist/esm/components/index.js", + "import": "./dist/esm/components/index.js", + "require": "./dist/cjs/components/index.cjs" + }, + "./hooks": { + "types": "./dist/esm/hooks/index.d.ts", + "react-native": "./dist/esm/hooks/index.js", + "import": "./dist/esm/hooks/index.js", + "require": "./dist/cjs/hooks/index.cjs" } }, "main": "./dist/cjs/index.cjs", "module": "./dist/esm/index.js", + "react-native": "./dist/esm/index.js", "types": "./dist/esm/index.d.ts", "files": [ "dist", @@ -48,12 +68,8 @@ "scripts": { "build": "rm -rf dist && tsup && yarn postbuild", "postbuild": "node ./scripts/postBuild.mjs", - "demo:android": "yarn workspace demo-app android", - "demo:ios": "yarn workspace demo-app ios", - "demo:start": "yarn workspace demo-app start", - "demo:test": "yarn workspace demo-app test", - "fmt": "yarn prettier --check .", - "fmt:fix": "yarn prettier --write .", + "fmt": "prettier --check .", + "fmt:fix": "prettier --write .", "format": "sh -c 'if [ -z \"$SKIP_BUILD_DEPS\" ]; then yarn nice; else yarn fmt:fix; fi'", "lint": "eslint .", "lint:fix": "eslint --fix .", @@ -62,20 +78,22 @@ "report:exports": "node ./scripts/report-exports.mjs", "test": "vitest run", "test:build": "yarn build && yarn test && yarn types && yarn lint", - "test:demo": "yarn workspace demo-app test", "typecheck": "tsc -p tsconfig.json --noEmit", "types": "tsc -p tsconfig.json --noEmit", "validate:exports": "node ./scripts/validate-exports.mjs", "validate:pkg": "node ./scripts/verify-conditions.mjs" }, "dependencies": { + "@babel/runtime": "^7.28.3", "@selfxyz/common": "workspace:^", "socket.io-client": "^4.8.1", "zustand": "^4.5.2" }, "devDependencies": { + "@tamagui/types": "1.126.14", "@testing-library/react": "^14.1.2", "@types/react": "^18.3.4", + "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "eslint": "^8.57.0", @@ -83,12 +101,16 @@ "eslint-import-resolver-typescript": "^4.4.4", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react": "^7.37.5", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-sort-exports": "^0.9.1", "jsdom": "^24.0.0", "prettier": "^3.5.3", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-native": "0.76.9", + "react-native-web": "^0.21.1", + "tamagui": "1.126.14", "tsup": "^8.0.1", "typescript": "^5.9.2", "vitest": "^1.6.0" @@ -96,7 +118,12 @@ "peerDependencies": { "react": "^18.3.1", "react-native": "0.76.9", - "tamagui": "^1.126.0" + "tamagui": "1.126.x" + }, + "peerDependenciesMeta": { + "tamagui": { + "optional": false + } }, "packageManager": "yarn@4.6.0", "publishConfig": { diff --git a/packages/mobile-sdk-alpha/src/browser.ts b/packages/mobile-sdk-alpha/src/browser.ts index 4c2991070..1dbeffc1e 100644 --- a/packages/mobile-sdk-alpha/src/browser.ts +++ b/packages/mobile-sdk-alpha/src/browser.ts @@ -57,7 +57,7 @@ export { extractMRZInfo, formatDateToYYMMDD, scanMRZ } from './mrz'; export { generateMockDocument, signatureAlgorithmToStrictSignatureAlgorithm } from './mock/generator'; -export { generateTEEInputsDisclose } from './processing/generate-disclosure-inputs'; +export { generateTEEInputsDisclose } from './processing/generateDisclosureInputs'; // Core functions export { isPassportDataValid } from './validation/document'; diff --git a/packages/mobile-sdk-alpha/src/client.ts b/packages/mobile-sdk-alpha/src/client.ts index 51f4d3d22..a1d5b6ef0 100644 --- a/packages/mobile-sdk-alpha/src/client.ts +++ b/packages/mobile-sdk-alpha/src/client.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import type { DocumentCatalog, PassportData } from '@selfxyz/common/utils/types'; +import type { DocumentCatalog, PassportData } from '@selfxyz/common'; import { defaultConfig } from './config/defaults'; import { mergeConfig } from './config/merge'; diff --git a/packages/mobile-sdk-alpha/src/components/screens/NFCScannerScreen.tsx b/packages/mobile-sdk-alpha/src/components/screens/NFCScannerScreen.tsx index eb5a0b81d..befd88093 100644 --- a/packages/mobile-sdk-alpha/src/components/screens/NFCScannerScreen.tsx +++ b/packages/mobile-sdk-alpha/src/components/screens/NFCScannerScreen.tsx @@ -3,10 +3,10 @@ // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. import { useCallback } from 'react'; -import { Button, Text, YStack } from 'tamagui'; +import { StyleSheet, Text, TouchableOpacity } from 'react-native'; +import { View } from 'tamagui'; -import { getSKIPEM } from '@selfxyz/common/utils/csca'; -import { initPassportDataParsing } from '@selfxyz/common/utils/passports'; +import { getSKIPEM, initPassportDataParsing } from '@selfxyz/common'; import { useSelfClient } from '../../context'; import { MRZInfo, ScanResultNFC } from '../../types/public'; @@ -40,11 +40,38 @@ export const NFCScannerScreen = ({ onSuccess, onFailure, mrzData }: ScreenProps ); return ( - - - NFC Scanner - - - + + NFC Scanner + onNFCScan({})}> + Simulate NFC Scan + + ); }; + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + justifyContent: 'center', + alignItems: 'center', + gap: 16, + }, + title: { + fontSize: 24, + fontWeight: 'bold', + textAlign: 'center', + marginBottom: 16, + }, + button: { + backgroundColor: '#007AFF', + paddingHorizontal: 24, + paddingVertical: 12, + borderRadius: 8, + }, + buttonText: { + color: 'white', + fontSize: 16, + fontWeight: '600', + }, +}); diff --git a/packages/mobile-sdk-alpha/src/components/screens/PassportCameraScreen.tsx b/packages/mobile-sdk-alpha/src/components/screens/PassportCameraScreen.tsx index 6c5f4d5a7..5e78c36b6 100644 --- a/packages/mobile-sdk-alpha/src/components/screens/PassportCameraScreen.tsx +++ b/packages/mobile-sdk-alpha/src/components/screens/PassportCameraScreen.tsx @@ -2,20 +2,21 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import { Button, Text, YStack } from 'tamagui'; +import { StyleSheet, Text, TouchableOpacity } from 'react-native'; +import { View } from 'tamagui'; import type { PassportCameraProps } from '../../types/ui'; import { MRZScannerView } from '../MRZScannerView'; // Simple placeholder component - this would be replaced with actual camera UI export const PassportCameraScreen = ({ onMRZDetected }: PassportCameraProps) => ( - - - Passport Camera - + + Passport Camera - - + Simulate MRZ Detection + + ); + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + justifyContent: 'center', + alignItems: 'center', + gap: 16, + }, + title: { + fontSize: 24, + fontWeight: 'bold', + textAlign: 'center', + marginBottom: 16, + }, + button: { + backgroundColor: '#007AFF', + paddingHorizontal: 24, + paddingVertical: 12, + borderRadius: 8, + }, + buttonText: { + color: 'white', + fontSize: 16, + fontWeight: '600', + }, +}); diff --git a/packages/mobile-sdk-alpha/src/components/screens/QRCodeScreen.tsx b/packages/mobile-sdk-alpha/src/components/screens/QRCodeScreen.tsx index c0e7b2514..1320a0ab9 100644 --- a/packages/mobile-sdk-alpha/src/components/screens/QRCodeScreen.tsx +++ b/packages/mobile-sdk-alpha/src/components/screens/QRCodeScreen.tsx @@ -2,18 +2,59 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import { Button, Text, YStack } from 'tamagui'; +import { StyleSheet, Text, TouchableOpacity } from 'react-native'; +import { View } from 'tamagui'; import type { ScreenProps } from '../../types/ui'; export const QRCodeScreen = ({ onSuccess, onFailure }: ScreenProps) => ( - - - QR Code Scanner - - - - + + QR Code Scanner + + Simulate Success + + onFailure(new Error('QR scan failed'))}> + Simulate Failure + + ); + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + justifyContent: 'center', + alignItems: 'center', + gap: 16, + }, + title: { + fontSize: 24, + fontWeight: 'bold', + textAlign: 'center', + marginBottom: 16, + }, + button: { + backgroundColor: '#007AFF', + paddingHorizontal: 24, + paddingVertical: 12, + borderRadius: 8, + }, + buttonText: { + color: 'white', + fontSize: 16, + fontWeight: '600', + }, + outlinedButton: { + backgroundColor: 'transparent', + borderWidth: 1, + borderColor: '#007AFF', + paddingHorizontal: 24, + paddingVertical: 12, + borderRadius: 8, + }, + outlinedButtonText: { + color: '#007AFF', + fontSize: 16, + fontWeight: '600', + }, +}); diff --git a/packages/mobile-sdk-alpha/src/documents/utils.ts b/packages/mobile-sdk-alpha/src/documents/utils.ts index 64228717d..6c7e56c36 100644 --- a/packages/mobile-sdk-alpha/src/documents/utils.ts +++ b/packages/mobile-sdk-alpha/src/documents/utils.ts @@ -2,16 +2,20 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import { +import type { AadhaarData, + DocumentMetadata, + IDDocument, + PublicKeyDetailsECDSA, + PublicKeyDetailsRSA, +} from '@selfxyz/common'; +import { brutforceSignatureAlgorithmDsc, + calculateContentHash, + inferDocumentCategory, isMRZDocument, parseCertificateSimple, - PublicKeyDetailsECDSA, - PublicKeyDetailsRSA, } from '@selfxyz/common'; -import { calculateContentHash, inferDocumentCategory } from '@selfxyz/common/utils'; -import { DocumentMetadata, IDDocument } from '@selfxyz/common/utils/types'; import { SelfClient } from '../types/public'; diff --git a/packages/mobile-sdk-alpha/src/index.ts b/packages/mobile-sdk-alpha/src/index.ts index 0af419d6a..1843fea7a 100644 --- a/packages/mobile-sdk-alpha/src/index.ts +++ b/packages/mobile-sdk-alpha/src/index.ts @@ -56,11 +56,9 @@ export { sdkError, } from './errors'; +// Screen Components (React Native-based) export { NFCScannerScreen } from './components/screens/NFCScannerScreen'; - -// Screen Components export { PassportCameraScreen } from './components/screens/PassportCameraScreen'; - export { QRCodeScreen } from './components/screens/QRCodeScreen'; export { SdkEvents } from './types/events'; @@ -92,10 +90,9 @@ export { formatDateToYYMMDD, scanMRZ } from './mrz'; export { generateMockDocument, signatureAlgorithmToStrictSignatureAlgorithm } from './mock/generator'; -export { generateTEEInputsDisclose } from './processing/generate-disclosure-inputs'; +export { generateTEEInputsDisclose } from './processing/generateDisclosureInputs'; // Documents utils - // Core functions export { isPassportDataValid } from './validation/document'; diff --git a/packages/mobile-sdk-alpha/src/mock/generator.ts b/packages/mobile-sdk-alpha/src/mock/generator.ts index d9ba4c71f..b6aedc44d 100644 --- a/packages/mobile-sdk-alpha/src/mock/generator.ts +++ b/packages/mobile-sdk-alpha/src/mock/generator.ts @@ -2,9 +2,8 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import type { IdDocInput, PassportData } from '@selfxyz/common/utils'; -import { getSKIPEM } from '@selfxyz/common/utils/csca'; -import { generateMockDSC, genMockIdDoc, initPassportDataParsing } from '@selfxyz/common/utils/passports'; +import type { IdDocInput, PassportData } from '@selfxyz/common'; +import { generateMockDSC, genMockIdDoc, getSKIPEM, initPassportDataParsing } from '@selfxyz/common'; export interface GenerateMockDocumentOptions { age: number; diff --git a/packages/mobile-sdk-alpha/src/processing/generate-disclosure-inputs.ts b/packages/mobile-sdk-alpha/src/processing/generateDisclosureInputs.ts similarity index 86% rename from packages/mobile-sdk-alpha/src/processing/generate-disclosure-inputs.ts rename to packages/mobile-sdk-alpha/src/processing/generateDisclosureInputs.ts index 24c421a9a..a653e75e6 100644 --- a/packages/mobile-sdk-alpha/src/processing/generate-disclosure-inputs.ts +++ b/packages/mobile-sdk-alpha/src/processing/generateDisclosureInputs.ts @@ -2,9 +2,8 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import type { DocumentCategory, PassportData } from '@selfxyz/common/types'; -import type { SelfApp } from '@selfxyz/common/utils'; -import { generateTEEInputsDiscloseStateless } from '@selfxyz/common/utils/circuits/registerInputs'; +import type { DocumentCategory, PassportData, SelfApp } from '@selfxyz/common'; +import { generateTEEInputsDiscloseStateless } from '@selfxyz/common'; import { useProtocolStore } from '../stores/protocolStore'; diff --git a/packages/mobile-sdk-alpha/src/stores/protocolStore.ts b/packages/mobile-sdk-alpha/src/stores/protocolStore.ts index 580655193..a82b754ad 100644 --- a/packages/mobile-sdk-alpha/src/stores/protocolStore.ts +++ b/packages/mobile-sdk-alpha/src/stores/protocolStore.ts @@ -4,6 +4,7 @@ import { create } from 'zustand'; +import type { DeployedCircuits, OfacTree } from '@selfxyz/common'; import { API_URL, API_URL_STAGING, @@ -15,15 +16,14 @@ import { DSC_TREE_URL_ID_CARD, DSC_TREE_URL_STAGING, DSC_TREE_URL_STAGING_ID_CARD, + fetchOfacTrees, IDENTITY_TREE_URL, IDENTITY_TREE_URL_ID_CARD, IDENTITY_TREE_URL_STAGING, IDENTITY_TREE_URL_STAGING_ID_CARD, TREE_URL, TREE_URL_STAGING, -} from '@selfxyz/common/constants'; -import { fetchOfacTrees } from '@selfxyz/common/utils/ofac'; -import type { DeployedCircuits, OfacTree } from '@selfxyz/common/utils/types'; +} from '@selfxyz/common'; interface ProtocolState { passport: { diff --git a/packages/mobile-sdk-alpha/src/stores/selfAppStore.tsx b/packages/mobile-sdk-alpha/src/stores/selfAppStore.tsx index 379ee87ad..3aa31674e 100644 --- a/packages/mobile-sdk-alpha/src/stores/selfAppStore.tsx +++ b/packages/mobile-sdk-alpha/src/stores/selfAppStore.tsx @@ -6,8 +6,8 @@ import type { Socket } from 'socket.io-client'; import socketIo from 'socket.io-client'; import { create } from 'zustand'; -import { WS_DB_RELAYER } from '@selfxyz/common/constants'; -import type { SelfApp } from '@selfxyz/common/utils/appType'; +import type { SelfApp } from '@selfxyz/common'; +import { WS_DB_RELAYER } from '@selfxyz/common'; interface SelfAppState { selfApp: SelfApp | null; diff --git a/packages/mobile-sdk-alpha/src/types/events.ts b/packages/mobile-sdk-alpha/src/types/events.ts index 8c6d2921d..9cdb33a46 100644 --- a/packages/mobile-sdk-alpha/src/types/events.ts +++ b/packages/mobile-sdk-alpha/src/types/events.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import { DocumentCategory } from '@selfxyz/common/types'; +import { DocumentCategory } from '@selfxyz/common'; import type { Progress } from './public'; diff --git a/packages/mobile-sdk-alpha/src/types/public.ts b/packages/mobile-sdk-alpha/src/types/public.ts index 0fc120c4b..6dfc53f6a 100644 --- a/packages/mobile-sdk-alpha/src/types/public.ts +++ b/packages/mobile-sdk-alpha/src/types/public.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import type { DocumentCatalog, IDDocument, PassportData } from '@selfxyz/common/utils/types'; +import type { DocumentCatalog, IDDocument, PassportData } from '@selfxyz/common'; import { SDKEvent, SDKEventMap } from './events'; diff --git a/packages/mobile-sdk-alpha/src/validation/document.ts b/packages/mobile-sdk-alpha/src/validation/document.ts index 04015536c..2f6041da5 100644 --- a/packages/mobile-sdk-alpha/src/validation/document.ts +++ b/packages/mobile-sdk-alpha/src/validation/document.ts @@ -2,9 +2,8 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import { hash } from '@selfxyz/common/utils/hash/sha'; -import { formatMrz } from '@selfxyz/common/utils/passportFormat'; -import type { PassportData } from '@selfxyz/common/utils/types'; +import type { PassportData } from '@selfxyz/common'; +import { formatMrz, hash } from '@selfxyz/common'; /** * Checks if two numeric arrays contain the same values in the same order. diff --git a/packages/mobile-sdk-alpha/tests/client-mrz.test.ts b/packages/mobile-sdk-alpha/tests/clientMrz.test.ts similarity index 100% rename from packages/mobile-sdk-alpha/tests/client-mrz.test.ts rename to packages/mobile-sdk-alpha/tests/clientMrz.test.ts diff --git a/packages/mobile-sdk-alpha/tests/documents/utils.test.ts b/packages/mobile-sdk-alpha/tests/documents/utils.test.ts index 9c4d6eb97..a6da43a89 100644 --- a/packages/mobile-sdk-alpha/tests/documents/utils.test.ts +++ b/packages/mobile-sdk-alpha/tests/documents/utils.test.ts @@ -4,7 +4,8 @@ import { describe, expect, it } from 'vitest'; -import { DocumentCatalog, PassportData } from '@selfxyz/common/utils/types'; +import type { DocumentCatalog } from '@selfxyz/common/types'; +import type { PassportData } from '@selfxyz/common/types/passport'; import { createSelfClient, defaultConfig, DocumentsAdapter, loadSelectedDocument, SelfClient } from '../../src'; diff --git a/packages/mobile-sdk-alpha/tests/entry.test.tsx b/packages/mobile-sdk-alpha/tests/entry.test.tsx index 939127cd5..83c4ab747 100644 --- a/packages/mobile-sdk-alpha/tests/entry.test.tsx +++ b/packages/mobile-sdk-alpha/tests/entry.test.tsx @@ -3,7 +3,6 @@ // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. /* @vitest-environment jsdom */ -import React from 'react'; import { describe, expect, it } from 'vitest'; import { SelfMobileSdk, useSelfClient } from '../src/index'; diff --git a/packages/mobile-sdk-alpha/tests/mock/generator.test.ts b/packages/mobile-sdk-alpha/tests/mock/generator.test.ts index 6f88a8223..71d690826 100644 --- a/packages/mobile-sdk-alpha/tests/mock/generator.test.ts +++ b/packages/mobile-sdk-alpha/tests/mock/generator.test.ts @@ -6,14 +6,11 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { generateMockDocument, signatureAlgorithmToStrictSignatureAlgorithm } from '../../src/mock/generator'; -// Mock the external dependencies -vi.mock('@selfxyz/common/utils/csca', () => ({ - getSKIPEM: vi.fn(), -})); - -vi.mock('@selfxyz/common/utils/passports', () => ({ +// Mock the @selfxyz/common module to match the actual import path used in generator.ts +vi.mock('@selfxyz/common', () => ({ generateMockDSC: vi.fn(), genMockIdDoc: vi.fn(), + getSKIPEM: vi.fn(), initPassportDataParsing: vi.fn(), })); @@ -80,13 +77,8 @@ describe('generateMockDocument', () => { beforeEach(async () => { vi.clearAllMocks(); - // Import the mocked functions - const csca = await import('@selfxyz/common/utils/csca'); - const passports = await import('@selfxyz/common/utils/passports'); - getSKIPEM = csca.getSKIPEM; - generateMockDSC = passports.generateMockDSC; - genMockIdDoc = passports.genMockIdDoc; - initPassportDataParsing = passports.initPassportDataParsing; + // Import the mocked functions from the same path used by the implementation + ({ getSKIPEM, generateMockDSC, genMockIdDoc, initPassportDataParsing } = await import('@selfxyz/common')); // Setup default mocks with proper types vi.mocked(getSKIPEM).mockResolvedValue({ 'mock-key': 'mock-ski-pem' }); @@ -402,13 +394,8 @@ describe('generateMockDocument integration', () => { beforeEach(async () => { vi.clearAllMocks(); - // Import the mocked functions - const csca = await import('@selfxyz/common/utils/csca'); - const passports = await import('@selfxyz/common/utils/passports'); - getSKIPEM = csca.getSKIPEM; - generateMockDSC = passports.generateMockDSC; - genMockIdDoc = passports.genMockIdDoc; - initPassportDataParsing = passports.initPassportDataParsing; + // Import the mocked functions from the same path used by the implementation + ({ getSKIPEM, generateMockDSC, genMockIdDoc, initPassportDataParsing } = await import('@selfxyz/common')); // Setup default mocks with proper types vi.mocked(getSKIPEM).mockResolvedValue({ 'mock-key': 'mock-ski-pem' }); diff --git a/packages/mobile-sdk-alpha/tests/processing/generate-disclosure-inputs.test.ts b/packages/mobile-sdk-alpha/tests/processing/generateDisclosureInputs.test.ts similarity index 99% rename from packages/mobile-sdk-alpha/tests/processing/generate-disclosure-inputs.test.ts rename to packages/mobile-sdk-alpha/tests/processing/generateDisclosureInputs.test.ts index 754702efb..d33fca2fc 100644 --- a/packages/mobile-sdk-alpha/tests/processing/generate-disclosure-inputs.test.ts +++ b/packages/mobile-sdk-alpha/tests/processing/generateDisclosureInputs.test.ts @@ -10,7 +10,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import type { PassportData, SelfApp } from '@selfxyz/common'; -import { generateTEEInputsDisclose } from '../../src/processing/generate-disclosure-inputs'; +import { generateTEEInputsDisclose } from '../../src/processing/generateDisclosureInputs'; import { useProtocolStore } from '../../src/stores/protocolStore'; // Mocks for dependencies const mockSecret = '0x' + '00'.repeat(30) + 'a4ec'; // 32-byte hex string diff --git a/packages/mobile-sdk-alpha/tests/validation/document.test.ts b/packages/mobile-sdk-alpha/tests/validation/document.test.ts index cec4c0ad0..d1d7ba5df 100644 --- a/packages/mobile-sdk-alpha/tests/validation/document.test.ts +++ b/packages/mobile-sdk-alpha/tests/validation/document.test.ts @@ -4,9 +4,7 @@ import { describe, expect, it, vi } from 'vitest'; -import { hash } from '@selfxyz/common/utils/hash/sha'; -import { formatMrz } from '@selfxyz/common/utils/passportFormat'; -import { genAndInitMockPassportData } from '@selfxyz/common/utils/passports/genMockPassportData'; +import { formatMrz, genAndInitMockPassportData, hash } from '@selfxyz/common'; import { isPassportDataValid } from '../../src/validation/document'; diff --git a/packages/mobile-sdk-alpha/tsconfig.json b/packages/mobile-sdk-alpha/tsconfig.json index d76b5fac3..7e7ac63a4 100644 --- a/packages/mobile-sdk-alpha/tsconfig.json +++ b/packages/mobile-sdk-alpha/tsconfig.json @@ -16,7 +16,18 @@ "noEmit": true, "resolveJsonModule": true, "verbatimModuleSyntax": false, - "types": ["vitest/globals", "react"] + "types": ["vitest/globals", "react"], + "baseUrl": ".", + "paths": { + "@selfxyz/common": ["../../common/dist/esm/index"], + "@selfxyz/common/constants": ["../../common/dist/esm/src/constants/index"], + "@selfxyz/common/types": ["../../common/dist/esm/src/types/index"], + "@selfxyz/common/utils": ["../../common/dist/esm/src/utils/index"], + "@selfxyz/common/utils/hash/sha": ["../../common/dist/esm/src/utils/hash/sha"], + "@selfxyz/common/utils/passportFormat": ["../../common/dist/esm/src/utils/passports/format"], + "@selfxyz/common/utils/csca": ["../../common/dist/esm/src/utils/csca"], + "@selfxyz/common/utils/passports": ["../../common/dist/esm/src/utils/passports/index"] + } }, "include": ["src", "tests"] } diff --git a/packages/mobile-sdk-alpha/tsup.config.ts b/packages/mobile-sdk-alpha/tsup.config.ts index d2faf5bb8..da0723eb3 100644 --- a/packages/mobile-sdk-alpha/tsup.config.ts +++ b/packages/mobile-sdk-alpha/tsup.config.ts @@ -19,12 +19,27 @@ export default defineConfig([ format: ['esm'], dts: true, sourcemap: true, - splitting: false, + splitting: true, clean: true, outDir: 'dist/esm', tsconfig: './tsconfig.json', target: 'es2020', - external: ['react', 'react-native', '@selfxyz/common'], + external: [ + 'react', + 'react-native', + '@selfxyz/common', + // Common crypto dependencies (already in main app) + 'elliptic', + 'js-sha256', + 'js-sha1', + 'js-sha512', + 'node-forge', + 'ethers', + // React Native dependencies + '@react-native-async-storage/async-storage', + 'react-native-keychain', + 'react-native-sqlite-storage', + ], esbuildOptions(options) { options.supported = { ...options.supported, @@ -48,12 +63,27 @@ export default defineConfig([ format: ['cjs'], dts: false, sourcemap: true, - splitting: false, + splitting: true, clean: false, outDir: 'dist/cjs', tsconfig: './tsconfig.cjs.json', target: 'es2020', - external: ['react', 'react-native', '@selfxyz/common'], + external: [ + 'react', + 'react-native', + '@selfxyz/common', + // Common crypto dependencies (already in main app) + 'elliptic', + 'js-sha256', + 'js-sha1', + 'js-sha512', + 'node-forge', + 'ethers', + // React Native dependencies + '@react-native-async-storage/async-storage', + 'react-native-keychain', + 'react-native-sqlite-storage', + ], outExtension: ({ format }) => ({ js: format === 'cjs' ? '.cjs' : '.js' }), esbuildOptions(options) { options.supported = { diff --git a/packages/mobile-sdk-alpha/vitest.config.ts b/packages/mobile-sdk-alpha/vitest.config.ts index 5f69475af..e00ed40e9 100644 --- a/packages/mobile-sdk-alpha/vitest.config.ts +++ b/packages/mobile-sdk-alpha/vitest.config.ts @@ -9,12 +9,7 @@ export default defineConfig({ globals: true, environment: 'jsdom', setupFiles: ['./tests/setup.ts'], - exclude: ['demo-app/**'], - }, - resolve: { - alias: { - // Mock React Native modules for testing - 'react-native': 'react-native-web', - }, + include: ['tests/**/*.test.{ts,tsx}', 'src/**/*.test.{ts,tsx}'], + exclude: ['node_modules/**'], }, }); diff --git a/packages/mobile-sdk-demo/.eslintrc.cjs b/packages/mobile-sdk-demo/.eslintrc.cjs new file mode 100644 index 000000000..88988d0da --- /dev/null +++ b/packages/mobile-sdk-demo/.eslintrc.cjs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 2021, + sourceType: 'module', + ecmaFeatures: { jsx: true }, + }, + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], + plugins: ['prettier', 'simple-import-sort'], + ignorePatterns: ['dist/', 'node_modules/', 'android/', 'ios/'], + env: { + node: true, + es6: true, + jest: true, + }, + globals: { + globalThis: 'readonly', + }, + settings: { + 'import/resolver': { + typescript: { + alwaysTryTypes: true, + project: ['packages/*/tsconfig.json', 'tsconfig.json'], + }, + }, + }, + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], + '@typescript-eslint/no-require-imports': 'off', + 'prettier/prettier': ['warn', {}, { usePrettierrc: true }], + }, +}; diff --git a/packages/mobile-sdk-alpha/demo-app/.gitignore b/packages/mobile-sdk-demo/.gitignore similarity index 91% rename from packages/mobile-sdk-alpha/demo-app/.gitignore rename to packages/mobile-sdk-demo/.gitignore index 63b28ce59..9e64fd4fc 100644 --- a/packages/mobile-sdk-alpha/demo-app/.gitignore +++ b/packages/mobile-sdk-demo/.gitignore @@ -19,9 +19,6 @@ android/app/build/ android/app/.cxx/ android/build/ android/.gradle/ -android/gradle/ -android/gradlew -android/gradlew.bat android/local.properties *.apk *.aab diff --git a/packages/mobile-sdk-demo/.prettierrc b/packages/mobile-sdk-demo/.prettierrc new file mode 100644 index 000000000..7f393b90e --- /dev/null +++ b/packages/mobile-sdk-demo/.prettierrc @@ -0,0 +1,20 @@ +{ + "arrowParens": "avoid", + "bracketSameLine": false, + "bracketSpacing": true, + "singleQuote": true, + "trailingComma": "all", + "tabWidth": 2, + "useTabs": false, + "semi": true, + "endOfLine": "auto", + "printWidth": 120, + "overrides": [ + { + "files": ["*.yml", "*.yaml"], + "options": { + "singleQuote": false + } + } + ] +} diff --git a/packages/mobile-sdk-demo/App.tsx b/packages/mobile-sdk-demo/App.tsx new file mode 100644 index 000000000..b55490bda --- /dev/null +++ b/packages/mobile-sdk-demo/App.tsx @@ -0,0 +1,203 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +import React, { useState } from 'react'; +import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; + +import type { IDDocument } from '@selfxyz/common'; + +type Screen = 'home' | 'register' | 'generate' | 'prove' | 'camera' | 'nfc' | 'onboarding' | 'qr'; +type GenerateMockCmp = typeof import('./src/GenerateMock').default; +type RegisterDocumentCmp = typeof import('./src/RegisterDocument').default; +type ProveQRCodeCmp = typeof import('./src/ProveQRCode').default; + +function App() { + const [screen, setScreen] = useState('home'); + const [mockDocument, setMockDocument] = useState(null); + + const navigate = (next: Screen) => setScreen(next); + + if (screen === 'generate') { + const GenerateMock = require('./src/GenerateMock').default as GenerateMockCmp; + return navigate('home')} />; + } + + if (screen === 'register') { + const RegisterDocument = require('./src/RegisterDocument').default as RegisterDocumentCmp; + return navigate('home')} />; + } + + if (screen === 'prove') { + const ProveQRCode = require('./src/ProveQRCode').default as ProveQRCodeCmp; + return navigate('home')} />; + } + + if (screen === 'camera') { + const DocumentCamera = require('./src/DocumentCamera').default; + return navigate('home')} />; + } + + if (screen === 'nfc') { + const DocumentNFCScan = require('./src/DocumentNFCScan').default; + return navigate('home')} />; + } + + if (screen === 'onboarding') { + const DocumentOnboarding = require('./src/DocumentOnboarding').default; + return navigate('home')} />; + } + + if (screen === 'qr') { + const QRCodeViewFinder = require('./src/QRCodeViewFinder').default; + return navigate('home')} />; + } + + const MenuButton = ({ + title, + onPress, + isWorking = false, + }: { + title: string; + onPress: () => void; + isWorking?: boolean; + }) => ( + + + {title} + + + ); + + return ( + + + Self Demo App + Mobile SDK Alpha - Available Screens + + + + 🎯 Core Features + navigate('generate')} isWorking={true} /> + navigate('register')} + isWorking={Boolean(mockDocument)} + /> + navigate('prove')} isWorking={Boolean(mockDocument)} /> + + + + 📷 Document Scanning + navigate('camera')} /> + navigate('nfc')} /> + navigate('onboarding')} /> + + + + 📱 QR Code Features + navigate('qr')} /> + + + + ✅ Working | ⏳ Placeholder (Not Implemented) + Tap any screen to explore the demo interface + + + ); +} + +const styles = StyleSheet.create({ + container: { + flexGrow: 1, + backgroundColor: '#f8f9fa', + padding: 20, + }, + header: { + alignItems: 'center', + marginBottom: 32, + paddingTop: 20, + }, + title: { + fontSize: 28, + fontWeight: 'bold', + textAlign: 'center', + color: '#1a1a1a', + marginBottom: 8, + }, + subtitle: { + fontSize: 16, + color: '#666', + textAlign: 'center', + }, + section: { + marginBottom: 32, + }, + sectionTitle: { + fontSize: 20, + fontWeight: 'bold', + marginBottom: 16, + color: '#333', + textAlign: 'center', + }, + menuButton: { + width: '100%', + paddingVertical: 16, + paddingHorizontal: 20, + borderRadius: 12, + marginBottom: 12, + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.1, + shadowRadius: 3.84, + elevation: 5, + }, + workingButton: { + backgroundColor: '#007AFF', + }, + placeholderButton: { + backgroundColor: '#fff', + borderWidth: 1, + borderColor: '#e1e5e9', + }, + menuButtonText: { + fontSize: 16, + fontWeight: '600', + textAlign: 'center', + }, + workingButtonText: { + color: '#fff', + }, + placeholderButtonText: { + color: '#666', + }, + footer: { + marginTop: 20, + padding: 20, + backgroundColor: '#fff', + borderRadius: 12, + borderWidth: 1, + borderColor: '#e1e5e9', + }, + footerText: { + textAlign: 'center', + color: '#666', + fontSize: 14, + fontWeight: '500', + marginBottom: 8, + }, + footerSubtext: { + textAlign: 'center', + color: '#999', + fontSize: 12, + }, +}); + +export default App; diff --git a/packages/mobile-sdk-demo/README.md b/packages/mobile-sdk-demo/README.md new file mode 100644 index 000000000..a5f226065 --- /dev/null +++ b/packages/mobile-sdk-demo/README.md @@ -0,0 +1,53 @@ +# Self Demo App + +This is a demo application for testing the Self mobile SDK. + +## Configuration + +### New Architecture + +The new architecture (Fabric + TurboModules) can be toggled on/off: + +**Android**: Set `newArchEnabled` in `android/gradle.properties` + +- `newArchEnabled=true` - Enable new architecture +- `newArchEnabled=false` - Disable new architecture (default) + +**iOS**: Set `:fabric_enabled` in `ios/Podfile` + +- `:fabric_enabled => true` - Enable new architecture +- `:fabric_enabled => false` - Disable new architecture (default) + +### Hermes Engine + +Hermes JavaScript engine can be toggled on/off: + +**Android**: Set `hermesEnabled` in `android/gradle.properties` + +- `hermesEnabled=true` - Enable Hermes (default) +- `hermesEnabled=false` - Use JSC instead + +**iOS**: Set `:hermes_enabled` in `ios/Podfile` + +- `:hermes_enabled => true` - Enable Hermes (default) +- `:hermes_enabled => false` - Use JSC instead + +## Current Settings + +- **New Architecture**: Disabled +- **Hermes**: Enabled + +## Build Commands + +After changing configuration: + +```bash +# Clean and rebuild +yarn clean + +# Run on Android +yarn android + +# Run on iOS +yarn ios +``` diff --git a/packages/mobile-sdk-alpha/demo-app/__tests__/App.test.tsx b/packages/mobile-sdk-demo/__tests__/App.test.tsx similarity index 50% rename from packages/mobile-sdk-alpha/demo-app/__tests__/App.test.tsx rename to packages/mobile-sdk-demo/__tests__/App.test.tsx index 60b80c6b6..2f65bbb4f 100644 --- a/packages/mobile-sdk-alpha/demo-app/__tests__/App.test.tsx +++ b/packages/mobile-sdk-demo/__tests__/App.test.tsx @@ -3,15 +3,20 @@ // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. import React from 'react'; -import renderer from 'react-test-renderer'; import { Text } from 'react-native'; +import renderer from 'react-test-renderer'; + import App from '../App'; -test('renders menu items', () => { +test('renders menu buttons', () => { const rendered = renderer.create(); - const texts = rendered.root.findAllByType(Text).map(node => React.Children.toArray(node.props.children).join('')); - const expected = ['Self Demo App', 'Register Document', 'Generate Mock', 'Prove QR Code']; - expect(texts).toEqual(expect.arrayContaining(expected)); - expect(texts).toHaveLength(expected.length); + const textNodes = rendered.root.findAllByType(Text); + + expect(textNodes.some(node => node.props.children === 'Self Demo App')).toBe(true); + + ['✅ Generate Mock Data', '⏳ Register Document', '⏳ Prove QR Code'].forEach(label => { + expect(textNodes.some(node => node.props.children === label)).toBe(true); + }); + rendered.unmount(); }); diff --git a/packages/mobile-sdk-alpha/demo-app/__tests__/cryptoPolyfills.test.ts b/packages/mobile-sdk-demo/__tests__/cryptoPolyfills.test.ts similarity index 99% rename from packages/mobile-sdk-alpha/demo-app/__tests__/cryptoPolyfills.test.ts rename to packages/mobile-sdk-demo/__tests__/cryptoPolyfills.test.ts index f516fda91..2318401ef 100644 --- a/packages/mobile-sdk-alpha/demo-app/__tests__/cryptoPolyfills.test.ts +++ b/packages/mobile-sdk-demo/__tests__/cryptoPolyfills.test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import { randomBytes, sha256, sha512, computeHmac, pbkdf2 } from '../src/utils/ethers'; +import { computeHmac, pbkdf2, randomBytes, sha256, sha512 } from '../src/utils/ethers'; describe('Crypto Polyfills', () => { describe('randomBytes', () => { diff --git a/packages/mobile-sdk-demo/android/app/build.gradle b/packages/mobile-sdk-demo/android/app/build.gradle new file mode 100644 index 000000000..2ad7aae31 --- /dev/null +++ b/packages/mobile-sdk-demo/android/app/build.gradle @@ -0,0 +1,53 @@ +apply plugin: "com.android.application" +apply plugin: "com.facebook.react" +apply plugin: "org.jetbrains.kotlin.android" + +react { + root = file("../../") + reactNativeDir = file("../../../../node_modules/react-native") + codegenDir = file("../../../../node_modules/@react-native/codegen") + cliFile = file("../../../../node_modules/react-native/cli.js") + autolinkLibrariesWithApp() +} + +android { + namespace "com.selfxyz.demoapp" + ndkVersion rootProject.ext.ndkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + compileSdkVersion rootProject.ext.compileSdkVersion + + defaultConfig { + applicationId "com.selfxyz.demoapp" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.debug + } + } + + buildFeatures { + buildConfig true + } +} + +dependencies { + implementation("com.facebook.react:react-android:0.76.9") + implementation("com.facebook.react:hermes-android:0.76.9") + if (project.hasProperty('newArchEnabled') ? newArchEnabled.toBoolean() : false) { + implementation("com.facebook.react:react-android-codegen:0.76.9") + } +} diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/debug.keystore b/packages/mobile-sdk-demo/android/app/debug.keystore similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/debug.keystore rename to packages/mobile-sdk-demo/android/app/debug.keystore diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/proguard-rules.pro b/packages/mobile-sdk-demo/android/app/proguard-rules.pro similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/proguard-rules.pro rename to packages/mobile-sdk-demo/android/app/proguard-rules.pro diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/debug/AndroidManifest.xml b/packages/mobile-sdk-demo/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/debug/AndroidManifest.xml rename to packages/mobile-sdk-demo/android/app/src/debug/AndroidManifest.xml diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/AndroidManifest.xml b/packages/mobile-sdk-demo/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/AndroidManifest.xml rename to packages/mobile-sdk-demo/android/app/src/main/AndroidManifest.xml diff --git a/packages/mobile-sdk-demo/android/app/src/main/java/com/selfxyz/demoapp/MainActivity.kt b/packages/mobile-sdk-demo/android/app/src/main/java/com/selfxyz/demoapp/MainActivity.kt new file mode 100644 index 000000000..77e827622 --- /dev/null +++ b/packages/mobile-sdk-demo/android/app/src/main/java/com/selfxyz/demoapp/MainActivity.kt @@ -0,0 +1,24 @@ +package com.selfxyz.demoapp + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +class MainActivity : ReactActivity() { + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "SelfDemoApp" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate { + return DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) + } +} diff --git a/packages/mobile-sdk-demo/android/app/src/main/java/com/selfxyz/demoapp/MainApplication.kt b/packages/mobile-sdk-demo/android/app/src/main/java/com/selfxyz/demoapp/MainApplication.kt new file mode 100644 index 000000000..a3bbfd440 --- /dev/null +++ b/packages/mobile-sdk-demo/android/app/src/main/java/com/selfxyz/demoapp/MainApplication.kt @@ -0,0 +1,46 @@ +package com.selfxyz.demoapp + +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.soloader.SoLoader +import com.facebook.react.soloader.OpenSourceMergedSoMapping + +class MainApplication : Application(), ReactApplication { + + private val mReactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { + override fun getPackages(): List { + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + return PackageList(this).packages + } + + override fun getJSMainModuleName(): String { + return "index" + } + + override fun getUseDeveloperSupport(): Boolean { + return BuildConfig.DEBUG + } + + override val isNewArchEnabled: Boolean + get() = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean + get() = BuildConfig.IS_HERMES_ENABLED + } + + override val reactNativeHost: ReactNativeHost + get() = mReactNativeHost + + override fun onCreate() { + super.onCreate() + SoLoader.init(this, OpenSourceMergedSoMapping) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + load() + } + } +} diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/drawable/rn_edit_text_material.xml b/packages/mobile-sdk-demo/android/app/src/main/res/drawable/rn_edit_text_material.xml similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/drawable/rn_edit_text_material.xml rename to packages/mobile-sdk-demo/android/app/src/main/res/drawable/rn_edit_text_material.xml diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to packages/mobile-sdk-demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/values/strings.xml b/packages/mobile-sdk-demo/android/app/src/main/res/values/strings.xml similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/values/strings.xml rename to packages/mobile-sdk-demo/android/app/src/main/res/values/strings.xml diff --git a/packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/values/styles.xml b/packages/mobile-sdk-demo/android/app/src/main/res/values/styles.xml similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/android/app/src/main/res/values/styles.xml rename to packages/mobile-sdk-demo/android/app/src/main/res/values/styles.xml diff --git a/packages/mobile-sdk-demo/android/build.gradle b/packages/mobile-sdk-demo/android/build.gradle new file mode 100644 index 000000000..df682b4c5 --- /dev/null +++ b/packages/mobile-sdk-demo/android/build.gradle @@ -0,0 +1,40 @@ +buildscript { + ext { + buildToolsVersion = "35.0.0" + minSdkVersion = 24 + compileSdkVersion = 35 + targetSdkVersion = 35 + ndkVersion = "27.0.11718014" + kotlinVersion = "1.9.24" + } + repositories { + google() + mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath("com.android.tools.build:gradle:8.6.0") + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + } +} + +allprojects { + repositories { + google() + mavenCentral() + maven { + // All of React Native (JS, Android binaries) is installed from npm + url("$rootDir/../../../node_modules/react-native/android") + } + maven { + // Android JSC is installed from npm + url("$rootDir/../../../node_modules/jsc-android/dist") + } + maven { url 'https://jitpack.io' } + } +} + +apply plugin: "com.facebook.react.rootproject" diff --git a/packages/mobile-sdk-alpha/demo-app/android/gradle.properties b/packages/mobile-sdk-demo/android/gradle.properties similarity index 95% rename from packages/mobile-sdk-alpha/demo-app/android/gradle.properties rename to packages/mobile-sdk-demo/android/gradle.properties index 183b46a8d..e646a71a8 100644 --- a/packages/mobile-sdk-alpha/demo-app/android/gradle.properties +++ b/packages/mobile-sdk-demo/android/gradle.properties @@ -42,3 +42,6 @@ hermesEnabled=true # This allows your app to draw behind system bars for an immersive UI. # Note: Only works with ReactActivity and should not be used with custom Activity. edgeToEdgeEnabled=false + +# Designate the project root for the React Native Gradle plugin +react.projectRoot=../../../../ diff --git a/packages/mobile-sdk-demo/android/gradle/libs.versions.toml b/packages/mobile-sdk-demo/android/gradle/libs.versions.toml new file mode 100644 index 000000000..3b161c3fe --- /dev/null +++ b/packages/mobile-sdk-demo/android/gradle/libs.versions.toml @@ -0,0 +1,20 @@ +[versions] +agp = "8.6.0" +gson = "2.8.9" +guava = "31.0.1-jre" +javapoet = "1.13.0" +junit = "4.13.2" +kotlin = "1.9.25" +assertj = "3.25.1" + +[libraries] +kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "agp" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } +javapoet = { module = "com.squareup:javapoet", version.ref = "javapoet" } +junit = {module = "junit:junit", version.ref = "junit" } +assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } + +[plugins] +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/packages/mobile-sdk-demo/android/gradle/wrapper/gradle-wrapper.jar b/packages/mobile-sdk-demo/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..a4b76b953 Binary files /dev/null and b/packages/mobile-sdk-demo/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/packages/mobile-sdk-demo/android/gradle/wrapper/gradle-wrapper.properties b/packages/mobile-sdk-demo/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..c1d5e0185 --- /dev/null +++ b/packages/mobile-sdk-demo/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/packages/mobile-sdk-demo/android/gradlew b/packages/mobile-sdk-demo/android/gradlew new file mode 100755 index 000000000..f5feea6d6 --- /dev/null +++ b/packages/mobile-sdk-demo/android/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/packages/mobile-sdk-demo/android/gradlew.bat b/packages/mobile-sdk-demo/android/gradlew.bat new file mode 100644 index 000000000..16302dede --- /dev/null +++ b/packages/mobile-sdk-demo/android/gradlew.bat @@ -0,0 +1,99 @@ +@REM Copyright (c) Meta Platforms, Inc. and affiliates. +@REM +@REM This source code is licensed under the MIT license found in the +@REM LICENSE file in the root directory of this source tree. + +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/packages/mobile-sdk-demo/android/settings.gradle b/packages/mobile-sdk-demo/android/settings.gradle new file mode 100644 index 000000000..dc05e371f --- /dev/null +++ b/packages/mobile-sdk-demo/android/settings.gradle @@ -0,0 +1,8 @@ +pluginManagement { includeBuild("../../../node_modules/@react-native/gradle-plugin") } +plugins { id("com.facebook.react.settings") } +extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> + ex.autolinkLibrariesFromCommand(['yarn','exec','react-native','config']) +} +rootProject.name = 'SelfDemoApp' +include ':app' +includeBuild('../../../node_modules/@react-native/gradle-plugin') diff --git a/packages/mobile-sdk-alpha/demo-app/app.json b/packages/mobile-sdk-demo/app.json similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/app.json rename to packages/mobile-sdk-demo/app.json diff --git a/packages/mobile-sdk-alpha/demo-app/src/GenerateMock.tsx b/packages/mobile-sdk-demo/babel.config.js similarity index 62% rename from packages/mobile-sdk-alpha/demo-app/src/GenerateMock.tsx rename to packages/mobile-sdk-demo/babel.config.js index 939f30b21..23cd46c8b 100644 --- a/packages/mobile-sdk-alpha/demo-app/src/GenerateMock.tsx +++ b/packages/mobile-sdk-demo/babel.config.js @@ -2,7 +2,6 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -export default function GenerateMock() { - // TODO: implement mock generation - return null; -} +module.exports = { + presets: ['module:@react-native/babel-preset'], +}; diff --git a/packages/mobile-sdk-demo/crypto-polyfill.js b/packages/mobile-sdk-demo/crypto-polyfill.js new file mode 100644 index 000000000..1c69bd729 --- /dev/null +++ b/packages/mobile-sdk-demo/crypto-polyfill.js @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +// Crypto polyfill using @noble/hashes for React Native compatibility +const { sha256 } = require('@noble/hashes/sha256'); +const { sha1 } = require('@noble/hashes/sha1'); +const { sha512 } = require('@noble/hashes/sha512'); +const { Buffer } = require('buffer'); +require('react-native-get-random-values'); // installs globalThis.crypto.getRandomValues + +// Create a crypto polyfill that provides the Node.js crypto API +const crypto = { + createHash: algorithm => { + const algorithms = { + sha256: sha256, + sha1: sha1, + sha512: sha512, + }; + + const hashFunction = algorithms[algorithm.toLowerCase()]; + if (!hashFunction) { + throw new Error(`Unsupported hash algorithm: ${algorithm}`); + } + + let data = Buffer.alloc(0); + + const api = { + update: inputData => { + // Accumulate data + data = Buffer.concat([data, Buffer.from(inputData)]); + return api; + }, + digest: encoding => { + const hash = hashFunction(data); + if (encoding === 'hex') { + return Buffer.from(hash).toString('hex'); + } + return Buffer.from(hash); + }, + }; + return api; + }, + + // Add other commonly used crypto methods as needed + randomBytes: size => { + const array = new Uint8Array(size); + if (typeof globalThis.crypto?.getRandomValues !== 'function') { + throw new Error('crypto.getRandomValues not available; ensure polyfill is loaded'); + } + globalThis.crypto.getRandomValues(array); + return Buffer.from(array); + }, +}; + +module.exports = crypto; diff --git a/packages/mobile-sdk-alpha/demo-app/index.js b/packages/mobile-sdk-demo/index.js similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/index.js rename to packages/mobile-sdk-demo/index.js diff --git a/packages/mobile-sdk-alpha/demo-app/ios/.xcode.env b/packages/mobile-sdk-demo/ios/.xcode.env similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/.xcode.env rename to packages/mobile-sdk-demo/ios/.xcode.env diff --git a/packages/mobile-sdk-alpha/demo-app/ios/Podfile b/packages/mobile-sdk-demo/ios/Podfile similarity index 80% rename from packages/mobile-sdk-alpha/demo-app/ios/Podfile rename to packages/mobile-sdk-demo/ios/Podfile index b1e79c1d7..20d5c2340 100644 --- a/packages/mobile-sdk-alpha/demo-app/ios/Podfile +++ b/packages/mobile-sdk-demo/ios/Podfile @@ -1,6 +1,6 @@ # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command("node", ["-p", - 'require.resolve( + 'require.resolve( "react-native/scripts/react_native_pods.rb", {paths: [process.argv[1]]}, )', __dir__]).strip @@ -21,9 +21,13 @@ target "SelfDemoApp" do :path => config[:reactNativePath], # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/..", - :fabric_enabled => false + :fabric_enabled => false, + :hermes_enabled => true, ) + # Use the custom NFCPassportReader fork + pod "NFCPassportReader", :git => "git@github.com:selfxyz/NFCPassportReader.git" + post_install do |installer| # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 react_native_post_install( diff --git a/packages/mobile-sdk-alpha/demo-app/ios/Podfile.lock b/packages/mobile-sdk-demo/ios/Podfile.lock similarity index 95% rename from packages/mobile-sdk-alpha/demo-app/ios/Podfile.lock rename to packages/mobile-sdk-demo/ios/Podfile.lock index 0f64e921f..55d6ef350 100644 --- a/packages/mobile-sdk-alpha/demo-app/ios/Podfile.lock +++ b/packages/mobile-sdk-demo/ios/Podfile.lock @@ -8,6 +8,18 @@ PODS: - hermes-engine (0.76.9): - hermes-engine/Pre-built (= 0.76.9) - hermes-engine/Pre-built (0.76.9) + - Mixpanel-swift (5.0.0): + - Mixpanel-swift/Complete (= 5.0.0) + - Mixpanel-swift/Complete (5.0.0) + - mobile-sdk-alpha (0.1.0): + - NFCPassportReader + - QKMRZParser + - React-Core + - NFCPassportReader (2.1.1): + - Mixpanel-swift (~> 5.0.0) + - OpenSSL-Universal (= 1.1.1900) + - OpenSSL-Universal (1.1.1900) + - QKMRZParser (2.0.0) - RCT-Folly (2024.10.14.00): - boost - DoubleConversion @@ -1286,6 +1298,8 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - react-native-get-random-values (1.11.0): + - React-Core - React-nativeconfig (0.76.9) - React-NativeModulesApple (0.76.9): - glog @@ -1558,6 +1572,27 @@ PODS: - React-logger - React-perflogger - React-utils (= 0.76.9) + - RNCPicker (2.11.1): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.10.14.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 - SocketRocket (0.7.1) - Yoga (0.0.0) @@ -1569,6 +1604,8 @@ DEPENDENCIES: - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - "mobile-sdk-alpha (from `../node_modules/@selfxyz/mobile-sdk-alpha`)" + - "NFCPassportReader (from `git@github.com:selfxyz/NFCPassportReader.git`)" - 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`) - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) @@ -1600,6 +1637,7 @@ DEPENDENCIES: - 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-get-random-values (from `../node_modules/react-native-get-random-values`) - 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`) @@ -1627,10 +1665,14 @@ DEPENDENCIES: - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - ReactCodegen (from `build/generated/ios`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: trunk: + - Mixpanel-swift + - OpenSSL-Universal + - QKMRZParser - SocketRocket EXTERNAL SOURCES: @@ -1649,6 +1691,10 @@ EXTERNAL SOURCES: hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" :tag: hermes-2024-11-12-RNv0.76.2-5b4aa20c719830dcf5684832b89a6edb95ac3d64 + mobile-sdk-alpha: + :path: "../node_modules/@selfxyz/mobile-sdk-alpha" + NFCPassportReader: + :git: "git@github.com:selfxyz/NFCPassportReader.git" RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTDeprecation: @@ -1707,6 +1753,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon" React-microtasksnativemodule: :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" + react-native-get-random-values: + :path: "../node_modules/react-native-get-random-values" React-nativeconfig: :path: "../node_modules/react-native/ReactCommon" React-NativeModulesApple: @@ -1761,9 +1809,16 @@ EXTERNAL SOURCES: :path: build/generated/ios ReactCommon: :path: "../node_modules/react-native/ReactCommon" + RNCPicker: + :path: "../node_modules/@react-native-picker/picker" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" +CHECKOUT OPTIONS: + NFCPassportReader: + :commit: 04ede227cbfd377e2b4bc9b38f9a89eebdcab52f + :git: "git@github.com:selfxyz/NFCPassportReader.git" + SPEC CHECKSUMS: boost: 1dca942403ed9342f98334bf4c3621f011aa7946 DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385 @@ -1772,6 +1827,11 @@ SPEC CHECKSUMS: fmt: 01b82d4ca6470831d1cc0852a1af644be019e8f6 glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a hermes-engine: 9e868dc7be781364296d6ee2f56d0c1a9ef0bb11 + Mixpanel-swift: e9bef28a9648faff384d5ba6f48ecc2787eb24c0 + mobile-sdk-alpha: 96949ad8c8b61a9fa6b918a4202f9cebb9c678cc + NFCPassportReader: 48873f856f91215dbfa1eaaec20eae639672862e + OpenSSL-Universal: 84efb8a29841f2764ac5403e0c4119a28b713346 + QKMRZParser: 6b419b6f07d6bff6b50429b97de10846dc902c29 RCT-Folly: ea9d9256ba7f9322ef911169a9f696e5857b9e17 RCTDeprecation: ebe712bb05077934b16c6bf25228bdec34b64f83 RCTRequired: ca91e5dd26b64f577b528044c962baf171c6b716 @@ -1801,6 +1861,7 @@ SPEC CHECKSUMS: React-logger: c4052eb941cca9a097ef01b59543a656dc088559 React-Mapbuffer: 33546a3ebefbccb8770c33a1f8a5554fa96a54de React-microtasksnativemodule: d80ff86c8902872d397d9622f1a97aadcc12cead + react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba React-nativeconfig: 8efdb1ef1e9158c77098a93085438f7e7b463678 React-NativeModulesApple: cebca2e5320a3d66e123cade23bd90a167ffce5e React-perflogger: 72e653eb3aba9122f9e57cf012d22d2486f33358 @@ -1828,9 +1889,10 @@ SPEC CHECKSUMS: React-utils: ed818f19ab445000d6b5c4efa9d462449326cc9f ReactCodegen: f853a20cc9125c5521c8766b4b49375fec20648b ReactCommon: 300d8d9c5cb1a6cd79a67cf5d8f91e4d477195f9 + RNCPicker: 3549e7ab9a00047753e9fa852a1858a154cc4275 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: feb4910aba9742cfedc059e2b2902e22ffe9954a -PODFILE CHECKSUM: 224b208fda585f58e738758a69abedc60fa27789 +PODFILE CHECKSUM: 7db6890d140dc2f697c16380d1412b8861ebcff7 COCOAPODS: 1.16.2 diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcodeproj/project.pbxproj b/packages/mobile-sdk-demo/ios/SelfDemoApp.xcodeproj/project.pbxproj similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcodeproj/project.pbxproj rename to packages/mobile-sdk-demo/ios/SelfDemoApp.xcodeproj/project.pbxproj diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/SelfDemoApp.xcscheme b/packages/mobile-sdk-demo/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/SelfDemoApp.xcscheme similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/SelfDemoApp.xcscheme rename to packages/mobile-sdk-demo/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/SelfDemoApp.xcscheme diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/TempProject.xcscheme b/packages/mobile-sdk-demo/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/TempProject.xcscheme similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/TempProject.xcscheme rename to packages/mobile-sdk-demo/ios/SelfDemoApp.xcodeproj/xcshareddata/xcschemes/TempProject.xcscheme diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcworkspace/contents.xcworkspacedata b/packages/mobile-sdk-demo/ios/SelfDemoApp.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp.xcworkspace/contents.xcworkspacedata rename to packages/mobile-sdk-demo/ios/SelfDemoApp.xcworkspace/contents.xcworkspacedata diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/AppDelegate.swift b/packages/mobile-sdk-demo/ios/SelfDemoApp/AppDelegate.swift similarity index 88% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/AppDelegate.swift rename to packages/mobile-sdk-demo/ios/SelfDemoApp/AppDelegate.swift index 0d5a70d24..4bb67808c 100644 --- a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/AppDelegate.swift +++ b/packages/mobile-sdk-demo/ios/SelfDemoApp/AppDelegate.swift @@ -12,10 +12,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { window = UIWindow(frame: UIScreen.main.bounds) - let bridge = RCTBridge( + guard let bridge = RCTBridge( delegate: self, launchOptions: launchOptions - ) + ) else { + assertionFailure("Failed to initialize RCTBridge") + return false + } let rootView = RCTRootView( bridge: bridge, diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Images.xcassets/AppIcon.appiconset/Contents.json b/packages/mobile-sdk-demo/ios/SelfDemoApp/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Images.xcassets/AppIcon.appiconset/Contents.json rename to packages/mobile-sdk-demo/ios/SelfDemoApp/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Images.xcassets/Contents.json b/packages/mobile-sdk-demo/ios/SelfDemoApp/Images.xcassets/Contents.json similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Images.xcassets/Contents.json rename to packages/mobile-sdk-demo/ios/SelfDemoApp/Images.xcassets/Contents.json diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Info-Debug.plist b/packages/mobile-sdk-demo/ios/SelfDemoApp/Info-Debug.plist similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Info-Debug.plist rename to packages/mobile-sdk-demo/ios/SelfDemoApp/Info-Debug.plist diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Info.plist b/packages/mobile-sdk-demo/ios/SelfDemoApp/Info.plist similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/Info.plist rename to packages/mobile-sdk-demo/ios/SelfDemoApp/Info.plist diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/LaunchScreen.storyboard b/packages/mobile-sdk-demo/ios/SelfDemoApp/LaunchScreen.storyboard similarity index 100% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/LaunchScreen.storyboard rename to packages/mobile-sdk-demo/ios/SelfDemoApp/LaunchScreen.storyboard diff --git a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/PrivacyInfo.xcprivacy b/packages/mobile-sdk-demo/ios/SelfDemoApp/PrivacyInfo.xcprivacy similarity index 97% rename from packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/PrivacyInfo.xcprivacy rename to packages/mobile-sdk-demo/ios/SelfDemoApp/PrivacyInfo.xcprivacy index 41b8317f0..5cae44312 100644 --- a/packages/mobile-sdk-alpha/demo-app/ios/SelfDemoApp/PrivacyInfo.xcprivacy +++ b/packages/mobile-sdk-demo/ios/SelfDemoApp/PrivacyInfo.xcprivacy @@ -6,18 +6,19 @@ NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons - C617.1 + 1C8F.1 + CA92.1 NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPICategoryFileTimestamp NSPrivacyAccessedAPITypeReasons - CA92.1 + C617.1 diff --git a/packages/mobile-sdk-alpha/demo-app/jest.config.cjs b/packages/mobile-sdk-demo/jest.config.cjs similarity index 53% rename from packages/mobile-sdk-alpha/demo-app/jest.config.cjs rename to packages/mobile-sdk-demo/jest.config.cjs index 25a9b5619..8554cd893 100644 --- a/packages/mobile-sdk-alpha/demo-app/jest.config.cjs +++ b/packages/mobile-sdk-demo/jest.config.cjs @@ -4,6 +4,12 @@ module.exports = { preset: 'react-native', + setupFilesAfterEnv: ['/jest.setup.js'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], transformIgnorePatterns: ['node_modules/(?!(react-native|@react-native|@selfxyz)/)'], + moduleDirectories: ['node_modules', '/../../../node_modules'], + moduleNameMapper: { + '^@selfxyz/common$': '/../../common/dist/cjs/index.cjs', + '^@selfxyz/mobile-sdk-alpha$': '/../mobile-sdk-alpha/dist/cjs/index.cjs', + }, }; diff --git a/packages/mobile-sdk-demo/jest.setup.js b/packages/mobile-sdk-demo/jest.setup.js new file mode 100644 index 000000000..9e50c5605 --- /dev/null +++ b/packages/mobile-sdk-demo/jest.setup.js @@ -0,0 +1,163 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +/** @jest-environment jsdom */ + +// Mock the native bridge configuration FIRST +global.__fbBatchedBridgeConfig = { + remoteModuleConfig: [], + localModulesConfig: {}, +}; + +// Mock React Native's native modules +const { NativeModules } = require('react-native'); + +// Mock NativeModules +NativeModules.PlatformConstants = { + getConstants: () => ({ + isTesting: true, + reactNativeVersion: { + major: 0, + minor: 76, + patch: 9, + }, + }), +}; + +// Mock DeviceInfo native module +NativeModules.DeviceInfo = { + getConstants: () => ({ + Dimensions: { + window: { width: 375, height: 812 }, + screen: { width: 375, height: 812 }, + }, + PixelRatio: 2, + }), +}; + +// Mock other common native modules +NativeModules.StatusBarManager = { + getConstants: () => ({}), +}; + +NativeModules.Appearance = { + getConstants: () => ({}), +}; + +NativeModules.SourceCode = { + getConstants: () => ({ + scriptURL: 'http://localhost:8081/index.bundle?platform=ios&dev=true', + }), +}; + +NativeModules.UIManager = { + getConstants: () => ({}), + measure: jest.fn(), + measureInWindow: jest.fn(), + measureLayout: jest.fn(), + findSubviewIn: jest.fn(), + dispatchViewManagerCommand: jest.fn(), + setLayoutAnimationEnabledExperimental: jest.fn(), + configureNextLayoutAnimation: jest.fn(), + removeSubviewsFromContainerWithID: jest.fn(), + replaceExistingNonRootView: jest.fn(), + setChildren: jest.fn(), + manageChildren: jest.fn(), + setJSResponder: jest.fn(), + clearJSResponder: jest.fn(), + createView: jest.fn(), + updateView: jest.fn(), + removeRootView: jest.fn(), + addRootView: jest.fn(), + updateRootView: jest.fn(), +}; + +NativeModules.KeyboardObserver = { + addListener: jest.fn(), + removeListeners: jest.fn(), +}; + +// Mock react-native-get-random-values +jest.mock('react-native-get-random-values', () => ({ + polyfillGlobal: jest.fn(), +})); + +// Mock @react-native-picker/picker +jest.mock('@react-native-picker/picker', () => ({ + Picker: 'Picker', + PickerIOS: 'PickerIOS', +})); + +// Mock ethers +jest.mock('ethers', () => { + const mockRandomBytes = jest.fn().mockImplementation(length => new Uint8Array(length)); + mockRandomBytes.register = jest.fn(); + + const mockHashFunction = jest.fn().mockImplementation(() => '0x' + 'a'.repeat(64)); + mockHashFunction.register = jest.fn(); + + const mockSha512Function = jest.fn().mockImplementation(() => '0x' + 'a'.repeat(128)); + mockSha512Function.register = jest.fn(); + + return { + ethers: { + Wallet: jest.fn().mockImplementation(() => ({ + address: '0x1234567890123456789012345678901234567890', + signMessage: jest.fn().mockResolvedValue('0xsignature'), + })), + JsonRpcProvider: jest.fn().mockImplementation(() => ({ + getNetwork: jest.fn().mockResolvedValue({ chainId: 1 }), + })), + randomBytes: mockRandomBytes, + computeHmac: mockHashFunction, + pbkdf2: mockHashFunction, + sha256: mockHashFunction, + sha512: mockSha512Function, + ripemd160: mockHashFunction, + scrypt: mockHashFunction, + }, + }; +}); + +// Mock @selfxyz/common +jest.mock('@selfxyz/common', () => ({ + generateMockPassportData: jest.fn().mockReturnValue({ + documentNumber: '123456789', + dateOfBirth: '1990-01-01', + dateOfExpiry: '2030-01-01', + firstName: 'John', + lastName: 'Doe', + }), + cryptoPolyfill: { + createHash: jest.fn().mockReturnValue({ + update: jest.fn().mockReturnThis(), + digest: jest.fn().mockReturnValue('mocked-hash'), + }), + createHmac: jest.fn().mockReturnValue({ + update: jest.fn().mockReturnThis(), + digest: jest.fn().mockReturnValue('mocked-hmac'), + }), + randomBytes: jest.fn().mockImplementation(size => new Uint8Array(size)), + pbkdf2Sync: jest.fn().mockImplementation(() => new Uint8Array(32)), + }, +})); + +// Mock @selfxyz/mobile-sdk-alpha +jest.mock('@selfxyz/mobile-sdk-alpha', () => ({ + SelfSDK: { + initialize: jest.fn().mockResolvedValue(undefined), + generateProof: jest.fn().mockResolvedValue('mock-proof'), + registerDocument: jest.fn().mockResolvedValue('mock-registration'), + }, +})); + +// Mock console methods to avoid test output clutter +global.console = { + ...console, + log: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), +}; diff --git a/packages/mobile-sdk-demo/metro.config.cjs b/packages/mobile-sdk-demo/metro.config.cjs new file mode 100644 index 000000000..6ad3d83c5 --- /dev/null +++ b/packages/mobile-sdk-demo/metro.config.cjs @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); +const path = require('node:path'); +const findYarnWorkspaceRoot = require('find-yarn-workspace-root'); + +const defaultConfig = getDefaultConfig(__dirname); + +const projectRoot = __dirname; +const workspaceRoot = findYarnWorkspaceRoot(__dirname) || path.resolve(__dirname, '../..'); + +/** + * Modern Metro configuration for demo app using native workspace capabilities + * Based on the working main app configuration + */ +const config = { + projectRoot, + + watchFolders: [ + workspaceRoot, // Watch entire workspace root + path.resolve(workspaceRoot, 'common'), + path.resolve(workspaceRoot, 'packages/mobile-sdk-alpha'), + ], + + resolver: { + // Prevent Haste module naming collisions from duplicate package.json files + blockList: [ + // Ignore built package.json files to prevent Haste collisions + /.*\/dist\/package\.json$/, + /.*\/build\/package\.json$/, + ], + // Let workspace packages resolve naturally to their built exports (override where needed) + alias: { + '@selfxyz/mobile-sdk-alpha': path.resolve(workspaceRoot, 'packages/mobile-sdk-alpha/src'), + }, + // Enable workspace-aware resolution + enableGlobalPackages: true, + unstable_enablePackageExports: true, + // Prefer React Native-specific exports when available to avoid Node-only deps + unstable_conditionNames: ['require', 'react-native'], + unstable_enableSymlinks: true, + nodeModulesPaths: [path.resolve(projectRoot, 'node_modules'), path.resolve(workspaceRoot, 'node_modules')], + extraNodeModules: { + '@babel/runtime': path.resolve(__dirname, '../../node_modules/@babel/runtime'), + // Pin React and React Native to monorepo root + react: path.resolve(__dirname, '../../node_modules/react'), + 'react-native': path.resolve(__dirname, '../../node_modules/react-native'), + // Add workspace packages for proper resolution + '@selfxyz/common': path.resolve(workspaceRoot, 'common'), + // Fix snarkjs resolution for @anon-aadhaar/core + snarkjs: path.resolve(__dirname, '../../node_modules/snarkjs/build/main.cjs'), + // Fix ffjavascript resolution for snarkjs dependencies + ffjavascript: path.resolve(__dirname, '../../node_modules/ffjavascript/build/main.cjs'), + // Crypto polyfills - use custom polyfill with @noble/hashes + crypto: path.resolve(__dirname, 'src/polyfills/cryptoPolyfill.js'), + stream: require.resolve('stream-browserify'), + buffer: require.resolve('buffer'), + util: require.resolve('util'), + assert: require.resolve('assert'), + constants: require.resolve('constants-browserify'), + }, + // Prefer source files for @selfxyz/common so stack traces reference real filenames + resolveRequest: (context, moduleName, platform) => { + // Handle problematic Node.js modules that don't work in React Native + const nodeModuleRedirects = { + crypto: path.resolve(__dirname, 'src/polyfills/cryptoPolyfill.js'), + fs: false, // Disable filesystem access + os: false, // Disable OS-specific modules + readline: false, // Disable readline (pulls in events) + 'web-worker': false, // Disable web workers (not supported in React Native) + }; + + if (Object.prototype.hasOwnProperty.call(nodeModuleRedirects, moduleName)) { + if (nodeModuleRedirects[moduleName] === false) { + // Return empty module for disabled modules + return { type: 'empty' }; + } + // Redirect to polyfill + return { + type: 'sourceFile', + filePath: nodeModuleRedirects[moduleName], + }; + } + + // Let @selfxyz/common resolve through its package.json exports + // Remove custom resolution to let Metro handle it naturally + return context.resolveRequest(context, moduleName, platform); + }, + }, +}; + +module.exports = mergeConfig(defaultConfig, config); diff --git a/packages/mobile-sdk-demo/package.json b/packages/mobile-sdk-demo/package.json new file mode 100644 index 000000000..7069195b3 --- /dev/null +++ b/packages/mobile-sdk-demo/package.json @@ -0,0 +1,66 @@ +{ + "name": "mobile-sdk-demo", + "version": "0.0.1", + "private": true, + "main": "index.js", + "scripts": { + "analyze:bundle:android": "yarn prebuild && node scripts/bundle-analyze-ci.cjs android", + "analyze:bundle:ios": "yarn prebuild && node scripts/bundle-analyze-ci.cjs ios", + "preandroid": "yarn prebuild", + "android": "react-native run-android --verbose", + "prebuild": "yarn workspace @selfxyz/mobile-sdk-alpha build", + "build": "tsc -p tsconfig.json --noEmit --pretty false", + "clean": "rm -rf ios/build android/app/build android/build && cd android && ./gradlew clean && cd ..", + "fmt": "prettier --check .", + "fmt:fix": "prettier --write .", + "preios": "yarn prebuild", + "ios": "react-native run-ios", + "lint": "eslint .", + "lint:fix": "eslint --fix .", + "nice": "yarn lint:fix && yarn fmt:fix", + "start": "react-native start", + "test": "jest" + }, + "dependencies": { + "@babel/runtime": "^7.28.3", + "@noble/hashes": "^1.5.0", + "@react-native-picker/picker": "^2.11.1", + "@react-native/gradle-plugin": "0.76.9", + "@selfxyz/common": "workspace:*", + "@selfxyz/mobile-sdk-alpha": "workspace:*", + "assert": "^2.1.0", + "buffer": "^6.0.3", + "constants-browserify": "^1.0.0", + "ethers": "^6.11.0", + "find-yarn-workspace-root": "^2.0.0", + "react": "^18.3.1", + "react-native": "0.76.9", + "react-native-get-random-values": "^1.11.0", + "stream-browserify": "^3.0.0", + "tamagui": "1.126.14", + "util": "^0.12.5" + }, + "devDependencies": { + "@babel/core": "^7.28.3", + "@react-native-community/cli": "^16.0.3", + "@react-native/metro-config": "0.76.9", + "@tsconfig/react-native": "^3.0.6", + "@types/jest": "^29.5.14", + "@types/react": "^18.3.4", + "@typescript-eslint/eslint-plugin": "^8.44.0", + "@typescript-eslint/parser": "^8.44.0", + "babel-jest": "^29.6.3", + "eslint": "^8.57.0", + "eslint-config-prettier": "^10.1.8", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-sort-exports": "^0.9.1", + "jest": "^29.6.3", + "metro-react-native-babel-preset": "0.76.9", + "prettier": "^3.6.2", + "react-test-renderer": "^18.3.1", + "typescript": "^5.9.2" + } +} diff --git a/packages/mobile-sdk-demo/scripts/bundle-analyze-ci.cjs b/packages/mobile-sdk-demo/scripts/bundle-analyze-ci.cjs new file mode 100644 index 000000000..f99eef475 --- /dev/null +++ b/packages/mobile-sdk-demo/scripts/bundle-analyze-ci.cjs @@ -0,0 +1,98 @@ +#!/usr/bin/env node +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +const { execSync } = require('child_process'); +const { existsSync, statSync, unlinkSync } = require('fs'); +const os = require('os'); +const { join } = require('path'); + +const platform = process.argv[2]; +if (!platform || !['android', 'ios'].includes(platform)) { + console.error('Usage: bundle-analyze-ci.cjs '); + process.exit(1); +} + +// Bundle size thresholds in MB - adjusted for demo app +const BUNDLE_THRESHOLDS_MB = { + ios: 10, // Smaller threshold for demo app + android: 10, // Smaller threshold for demo app +}; + +function formatBytes(bytes) { + const sizes = ['Bytes', 'KB', 'MB', 'GB']; + if (bytes === 0) return '0 Bytes'; + const i = Math.floor(Math.log(bytes) / Math.log(1024)); + return Math.round((bytes / Math.pow(1024, i)) * 100) / 100 + ' ' + sizes[i]; +} + +function checkBundleSize(bundleSize, targetPlatform) { + const thresholdMB = BUNDLE_THRESHOLDS_MB[targetPlatform]; + const thresholdBytes = thresholdMB * 1024 * 1024; + + console.log(`\n📦 Demo App Bundle size: ${formatBytes(bundleSize)}`); + console.log(`🎯 Threshold: ${thresholdMB}MB (${formatBytes(thresholdBytes)})`); + + if (bundleSize > thresholdBytes) { + const overage = bundleSize - thresholdBytes; + console.error(`\n❌ Bundle size exceeds threshold by ${formatBytes(overage)}!`); + console.error(` Current: ${formatBytes(bundleSize)}`); + console.error(` Threshold: ${thresholdMB}MB`); + console.error(` Please reduce bundle size to continue.`); + console.error(`\n💡 To increase the threshold, edit BUNDLE_THRESHOLDS_MB in this script.`); + return false; + } else { + const remaining = thresholdBytes - bundleSize; + console.log(`✅ Demo app bundle size is within threshold (${formatBytes(remaining)} remaining)`); + return true; + } +} + +// Use Metro's built-in bundle command +const tmpDir = os.tmpdir(); +const bundleFile = join(tmpDir, `demo-app-${platform}.bundle`); +const sourcemapFile = join(tmpDir, `demo-app-${platform}.bundle.map`); + +console.log(`🔨 Generating demo app ${platform} bundle using Metro...`); + +try { + execSync( + `npx react-native bundle ` + + `--platform ${platform} ` + + `--dev false ` + + `--entry-file index.js ` + + `--bundle-output ${bundleFile} ` + + `--sourcemap-output ${sourcemapFile} ` + + `--minify false ` + + `--config metro.config.cjs ` + + `--reset-cache`, + { + stdio: 'inherit', + }, + ); +} catch (error) { + console.error(`❌ Failed to generate demo app bundle: ${error.message}`); + process.exit(1); +} + +// Check bundle size against threshold +if (existsSync(bundleFile)) { + const bundleSize = statSync(bundleFile).size; + console.log(`📁 Demo app bundle generated at: ${bundleFile}`); + if (!checkBundleSize(bundleSize, platform)) { + process.exit(1); + } + + // Clean up temporary files + try { + unlinkSync(bundleFile); + unlinkSync(sourcemapFile); + console.log('🧹 Cleaned up temporary bundle files'); + } catch (cleanupError) { + console.warn('⚠️ Could not clean up temporary files:', cleanupError.message); + } +} else { + console.error(`❌ Bundle file not found at ${bundleFile}`); + process.exit(1); +} diff --git a/packages/mobile-sdk-demo/src/DocumentCamera.tsx b/packages/mobile-sdk-demo/src/DocumentCamera.tsx new file mode 100644 index 000000000..055865fca --- /dev/null +++ b/packages/mobile-sdk-demo/src/DocumentCamera.tsx @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. +// SPDX-License-Identifier: BUSL-1.1 +// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. + +import React from 'react'; +import { Button, ScrollView, StyleSheet, Text, View } from 'react-native'; + +type Props = { + onBack: () => void; +}; + +export default function DocumentCamera({ onBack }: Props) { + return ( + + Document Camera + Passport/ID Scanning + + + + This screen would handle camera-based document scanning for passports and ID cards. + + + + Features (Not Implemented): + • Camera integration for document scanning + • MRZ (Machine Readable Zone) detection + • Document validation and parsing + • Real-time feedback and guidance + + + +