[SELF-700] feat: add mock document generator demo (#995)

* feat: add mock document generator demo

* feat: add mock document generator

* fixes

* chore: refresh workflow cache

* update lock

* build

* updates

* more fixes

* code rabbit feedback

* compiles

* save wip

* updates

* merge with dev and fixes

* fix: align hoisting and demo Jest resolver (#1003)

* chore(app): map common src paths and declare svg flag module

* ci fix

* update lock

* save wip

* chore: address yarn lock issues (#1004)

* address yarn lock issues

* fix postinstall

* fix ci

* use metro js proxy

* android build working for /app

* save wip

* fix merge

* pipeline fixes

* format

* fix pipelines

* bump limit and split

* fix pipeline issues

* chore: decouple demo app build (#1013)

* chore: decouple demo app build

* chore: move demo app to workspace

* chore: unpublish demo workspace

* fix mobile sdk tests

* updates

* remove polyfills

* update merge

* update resolutions

* update resolutions

* fix merge

* fix paths

* save wip

* save wip fixes rd2

* working android

* update lock

* save wip ios building

* fix merge

* readd public key

* fixes

* ci fixes

* fixes

* fix web building

* fix ci

* fix tests

* update lock

* fix ci rd2

* formatting and fix ci

* fix

* finalize ci fixes

* fix tests and metro config paths for building

* save wip

* install missing package for pipeline

* fix wip app building

* wip react config

* save working emulator compile

* first round of pr fixes and feedback

* clean up demo app artifacts from sdk

* Add Gradle wrapper files for mobile-sdk-demo Android build

- Added gradlew, gradlew.bat, and gradle/wrapper/ directory
- Updated .gitignore to allow committing Gradle wrapper files
- Fixes Android build error: spawn ./gradlew ENOENT

* codex feedback and fixes

* fix tests

* file renames

* revert back to dev

* add types

* coderabbit fixes

* fix tests

* fix tests

* fix test

* fixes

* fix wip coderabbit issues

* coderabbit suggestions rd 2

* fix ci pipelines and addresss warnings

* cr fixes

* convert kebab to camelCase

* save wip fixes

* update reinstall and lock files

* fixes

* remove file

* fix lint

* fix polyfill fallback issues

* ensure that mock document is not on ofac list

* prettier
This commit is contained in:
Justin Hernandez
2025-09-27 13:59:47 -07:00
committed by GitHub
parent 0dc8b18d40
commit 20fa5c5adc
183 changed files with 4316 additions and 1454 deletions

View File

@@ -244,7 +244,6 @@ app/src/assets/animations/*.json
app/src/assets/fonts/
# Yarn configuration
.yarnrc.yml
**/.yarn/
# Certificate generation config

View File

@@ -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: |

View File

@@ -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

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@ showcase
output/*
*.tsbuildinfo
.yarnrc.yml
.giga/tasks/*
package-lock.json
# CI-generated tarballs (don't commit these!)

View File

@@ -1,4 +1,5 @@
nodeLinker: node-modules
nmHoistingLimits: workspaces
enableGlobalCache: true
enableScripts: true
checksumBehavior: "update"

View File

@@ -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)

View File

@@ -19,3 +19,5 @@ declare module '*.svg' {
const content: React.FC<SvgProps>;
export default content;
}
declare module 'react-native-svg-circle-country-flags';

View File

@@ -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()")

View File

@@ -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

File diff suppressed because one or more lines are too long

View File

@@ -22,9 +22,13 @@ module.exports = {
'^@selfxyz/mobile-sdk-alpha/(.*)$':
'<rootDir>/../packages/mobile-sdk-alpha/dist/cjs/$1.cjs',
// Fix snarkjs resolution for @anon-aadhaar/core
'^snarkjs$': '<rootDir>/../node_modules/snarkjs/build/main.cjs',
'^snarkjs$': '<rootDir>/../circuits/node_modules/snarkjs/build/main.cjs',
// Fix ffjavascript resolution for snarkjs dependencies
'^ffjavascript$': '<rootDir>/../node_modules/ffjavascript/build/main.cjs',
'^ffjavascript$':
'<rootDir>/../circuits/node_modules/ffjavascript/build/main.cjs',
// Fix @anon-aadhaar/core resolution
'^@anon-aadhaar/core$':
'<rootDir>/../common/node_modules/@anon-aadhaar/core/dist/index.js',
},
globals: {
'ts-jest': {

View File

@@ -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',

View File

@@ -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,
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
// 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(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);

View File

@@ -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",

View File

@@ -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';

View File

@@ -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');

View File

@@ -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');
};

View File

@@ -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';

View File

@@ -628,9 +628,7 @@ const DocumentNFCScanScreen: React.FC = () => {
width="$8"
alignSelf="center"
borderRadius={1000}
source={{
uri: NFC_IMAGE,
}}
source={NFC_IMAGE}
margin={20}
/>
</>

View File

@@ -55,9 +55,7 @@ const DocumentNFCScanScreen: React.FC = () => {
width="$8"
alignSelf="center"
borderRadius={1000}
source={{
uri: NFC_IMAGE,
}}
source={NFC_IMAGE}
margin={20}
/>
</>

View File

@@ -259,7 +259,7 @@ const AadhaarUploadScreen: React.FC = () => {
paddingVertical={20}
>
<Image
source={AadhaarImage}
source={AadhaarImage as any}
width="100%"
height="100%"
objectFit="contain"

View File

@@ -12,7 +12,6 @@ import {
usePreventRemove,
} from '@react-navigation/native';
import { PassportData } from '@selfxyz/common/types';
import { DocumentCatalog, IDDocument } from '@selfxyz/common/utils/types';
import { DocumentMetadata, useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import { DocumentEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';

View File

@@ -8,7 +8,6 @@ import { Button, Text, XStack, YStack, ZStack } from 'tamagui';
import { BlurView } from '@react-native-community/blur';
import { useNavigation } from '@react-navigation/native';
import { PassportData } from '@selfxyz/common/types';
import { DocumentCatalog, IDDocument } from '@selfxyz/common/utils/types';
import IdCardLayout from '@/components/homeScreen/idCard';

View File

@@ -7,8 +7,8 @@ import { ScrollView, StyleSheet } from 'react-native';
import { Card, Image, Text, XStack, YStack } from 'tamagui';
import { CheckSquare2, Info, Wallet } from '@tamagui/lucide-icons';
import type { ProofHistory } from '@/stores/proof-types';
import { ProofStatus } from '@/stores/proof-types';
import type { ProofHistory } from '@/stores/proofTypes';
import { ProofStatus } from '@/stores/proofTypes';
import {
black,
blue100,

View File

@@ -14,9 +14,9 @@ import { useNavigation } from '@react-navigation/native';
import { CheckSquare2, Wallet, XCircle } from '@tamagui/lucide-icons';
import { BodyText } from '@/components/typography/BodyText';
import type { ProofHistory } from '@/stores/proof-types';
import { ProofStatus } from '@/stores/proof-types';
import { useProofHistoryStore } from '@/stores/proofHistoryStore';
import type { ProofHistory } from '@/stores/proofTypes';
import { ProofStatus } from '@/stores/proofTypes';
import {
black,
blue100,

View File

@@ -15,9 +15,9 @@ import { useNavigation } from '@react-navigation/native';
import { CheckSquare2, Wallet, XCircle } from '@tamagui/lucide-icons';
import { BodyText } from '@/components/typography/BodyText';
import type { ProofHistory } from '@/stores/proof-types';
import { ProofStatus } from '@/stores/proof-types';
import { useProofHistoryStore } from '@/stores/proofHistoryStore';
import type { ProofHistory } from '@/stores/proofTypes';
import { ProofStatus } from '@/stores/proofTypes';
import {
black,
blue100,

View File

@@ -23,8 +23,8 @@ import { typography } from '@/components/typography/styles';
import { Title } from '@/components/typography/Title';
import useHapticNavigation from '@/hooks/useHapticNavigation';
import { ExpandableBottomLayout } from '@/layouts/ExpandableBottomLayout';
import { ProofStatus } from '@/stores/proof-types';
import { useProofHistoryStore } from '@/stores/proofHistoryStore';
import { ProofStatus } from '@/stores/proofTypes';
import { black, white } from '@/utils/colors';
import {
buttonTap,

View File

@@ -36,8 +36,8 @@ import {
setDefaultDocumentTypeIfNeeded,
usePassport,
} from '@/providers/passportDataProvider';
import { ProofStatus } from '@/stores/proof-types';
import { useProofHistoryStore } from '@/stores/proofHistoryStore';
import { ProofStatus } from '@/stores/proofTypes';
import { black, slate300, white } from '@/utils/colors';
import { formatUserId } from '@/utils/formatUserId';
import { buttonTap } from '@/utils/haptic';

View File

@@ -36,10 +36,6 @@ const QRCodeViewFinderScreen: React.FC = () => {
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(

View File

@@ -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<string, string> format expected by AlternativeCSCA
return publicKeys
? Object.fromEntries(publicKeys.map(key => [key, key]))
: {};
}
return useProtocolStore.getState()[docCategory].alternative_csca;
},

View File

@@ -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<string, string> format expected by AlternativeCSCA
return publicKeys
? Object.fromEntries(publicKeys.map(key => [key, key]))
: {};
}
return useProtocolStore.getState()[docCategory].alternative_csca;
},

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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[];

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -6,6 +6,6 @@ declare module '*.svg' {
import type React from 'react';
import type { SvgProps } from 'react-native-svg';
const content: React.FC<SvgProps>;
export default content;
const svgContent: React.FC<SvgProps>;
export default svgContent;
}

View File

@@ -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<ProvingState>((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<ProvingState>((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<string, string> format expected by AlternativeCSCA
return publicKeys
? Object.fromEntries(publicKeys.map(key => [key, key]))
: {};
}
return useProtocolStore.getState()[docType].alternative_csca;
},
},
);
logProofEvent(

View File

@@ -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', () => ({

View File

@@ -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', () => ({

View File

@@ -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()),
},
),
};
});

View File

@@ -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(() => {

View File

@@ -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/*"]
}
},

View File

@@ -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,

View File

@@ -5,6 +5,22 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Self App</title>
<script>
// Polyfill Buffer for browser compatibility
if (typeof global === 'undefined') {
var global = globalThis;
}
</script>
<script type="module">
// Import Buffer from the bundled dependency (safer than CDN)
import { Buffer } from 'buffer';
window.Buffer = Buffer;
globalThis.Buffer = Buffer;
// Create a buffer external mapping for modules that expect it
window.__vite_browser_external = {
buffer: { Buffer },
};
</script>
</head>
<body>
<div id="root"></div>

View File

@@ -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

View File

@@ -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",

View File

@@ -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 };

13
common/src/types/globals.d.ts vendored Normal file
View File

@@ -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 {};

View File

@@ -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';

View File

@@ -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];

View File

@@ -9,7 +9,7 @@ export interface StandardCurve {
}
export function getCurveForElliptic(curveName: string): string {
const curves = {
const curves: Record<string, string> = {
secp224r1: 'p224',
secp256r1: 'p256',
secp384r1: 'p384',

View File

@@ -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';

View File

@@ -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);
});
});

View File

@@ -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();
});
});

View File

@@ -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",

View File

@@ -1 +0,0 @@
demo-app/**

View File

@@ -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: [
{

View File

@@ -1,4 +1,2 @@
dist
node_modules
demo-app/android
demo-app/ios

View File

@@ -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
```

View File

@@ -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 (
<View style={styles.container}>
<Text style={styles.title}>Self Demo App</Text>
<Text style={styles.item}>Register Document</Text>
<Text style={styles.item}>Generate Mock</Text>
<Text style={styles.item}>Prove QR Code</Text>
</View>
);
}
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;

View File

@@ -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
}
}

View File

@@ -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
}
}
}

View File

@@ -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<ReactPackage> =
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()
}
}
}

View File

@@ -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"

View File

@@ -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'

View File

@@ -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);

View File

@@ -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"
}
}

View File

@@ -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": {

View File

@@ -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';

View File

@@ -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';

View File

@@ -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 (
<YStack space="$4" padding="$4">
<Text fontSize="$6" fontWeight="bold">
NFC Scanner
</Text>
<Button onPress={() => onNFCScan({})}>Simulate NFC Scan</Button>
</YStack>
<View style={styles.container}>
<Text style={styles.title}>NFC Scanner</Text>
<TouchableOpacity style={styles.button} onPress={() => onNFCScan({})}>
<Text style={styles.buttonText}>Simulate NFC Scan</Text>
</TouchableOpacity>
</View>
);
};
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',
},
});

View File

@@ -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) => (
<YStack space="$4" padding="$4">
<Text fontSize="$6" fontWeight="bold">
Passport Camera
</Text>
<View style={styles.container}>
<Text style={styles.title}>Passport Camera</Text>
<MRZScannerView onMRZDetected={onMRZDetected} />
<Button
<TouchableOpacity
style={styles.button}
onPress={() =>
onMRZDetected({
documentNumber: 'L898902C3',
@@ -34,7 +35,34 @@ export const PassportCameraScreen = ({ onMRZDetected }: PassportCameraProps) =>
})
}
>
Simulate MRZ Detection
</Button>
</YStack>
<Text style={styles.buttonText}>Simulate MRZ Detection</Text>
</TouchableOpacity>
</View>
);
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',
},
});

View File

@@ -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) => (
<YStack space="$4" padding="$4">
<Text fontSize="$6" fontWeight="bold">
QR Code Scanner
</Text>
<Button onPress={onSuccess}>Simulate Success</Button>
<Button variant="outlined" onPress={() => onFailure(new Error('QR scan failed'))}>
Simulate Failure
</Button>
</YStack>
<View style={styles.container}>
<Text style={styles.title}>QR Code Scanner</Text>
<TouchableOpacity style={styles.button} onPress={onSuccess}>
<Text style={styles.buttonText}>Simulate Success</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.outlinedButton} onPress={() => onFailure(new Error('QR scan failed'))}>
<Text style={styles.outlinedButtonText}>Simulate Failure</Text>
</TouchableOpacity>
</View>
);
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',
},
});

View File

@@ -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,
brutforceSignatureAlgorithmDsc,
isMRZDocument,
parseCertificateSimple,
DocumentMetadata,
IDDocument,
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
} from '@selfxyz/common';
import { calculateContentHash, inferDocumentCategory } from '@selfxyz/common/utils';
import { DocumentMetadata, IDDocument } from '@selfxyz/common/utils/types';
import {
brutforceSignatureAlgorithmDsc,
calculateContentHash,
inferDocumentCategory,
isMRZDocument,
parseCertificateSimple,
} from '@selfxyz/common';
import { SelfClient } from '../types/public';

View File

@@ -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';

View File

@@ -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;

View File

@@ -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';

View File

@@ -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: {

View File

@@ -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;

View File

@@ -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';

View File

@@ -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';

View File

@@ -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.

View File

@@ -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';

View File

@@ -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';

View File

@@ -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' });

View File

@@ -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

View File

@@ -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';

Some files were not shown because too many files have changed in this diff Show More