remove lazy loading (#1018)

* remove lazy loading

* fix tests

* formatting

* fix imports and web ci

* fix tests

* fix building

* fix

* debug ci

* fix web ci issue

* fix

* fix

* fix ci

* remove web render test

* coderabbit feedback

* fix ci

* use import

* fix lint

* fix compiling

* update lock

* update lock

* fix: update yarn.lock hash for @selfxyz/mobile-sdk-alpha

Resolves CI error where yarn install --immutable failed due to
outdated package hash. The hash changed from b2afc4 to f9ebb9.

* fix: update yarn.lock hash after mobile-sdk-alpha changes

- Hash changed from c0e6b9 to 0d0f72 due to package modifications
- Cleaned caches and regenerated lockfile to ensure consistency
- This resolves CI cache mismatch where old artifacts had stale hash

* fix: update yarn.lock hash after building mobile-sdk-alpha

- Final hash: 89f5a6 (includes built dist artifacts)
- Built mobile-sdk-alpha to ensure package is in stable state
- This should resolve CI immutable install errors

* fix yarn lock and build
This commit is contained in:
Justin Hernandez
2025-09-09 00:55:23 -07:00
committed by GitHub
parent b62df10e1c
commit a1c69981eb
36 changed files with 668 additions and 1157 deletions

View File

@@ -0,0 +1,30 @@
name: cache-built-deps
description: Cache built JS artifacts (common + mobile-sdk-alpha)
inputs:
cache-version:
description: Cache version string for cache key
required: true
outputs:
cache-hit:
description: Whether cache was hit during restore
value: ${{ steps.restore.outputs.cache-hit }}
runs:
using: composite
steps:
- id: restore
name: Restore Built Dependencies
uses: actions/cache/restore@v4
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ inputs.cache-version }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
fail-on-cache-miss: false
- name: Save Built Dependencies
if: steps.restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ inputs.cache-version }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}

View File

@@ -69,28 +69,16 @@ jobs:
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}
- name: Install Dependencies
uses: ./.github/actions/yarn-install
- name: Restore Built Dependencies
id: built-deps-restore
uses: actions/cache/restore@v4
- name: Cache Built Dependencies
id: built-deps
uses: ./.github/actions/cache-built-deps
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
fail-on-cache-miss: false
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}
- name: Build dependencies (cache miss)
if: steps.built-deps-restore.outputs.cache-hit != 'true'
if: steps.built-deps.outputs.cache-hit != 'true'
run: |
echo "Cache miss for built dependencies. Building now..."
yarn workspace @selfxyz/mobile-app run build:deps
- name: Save Built Dependencies
if: steps.built-deps-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
- name: Run linter
run: yarn lint
working-directory: ./app
@@ -137,30 +125,70 @@ jobs:
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}
- name: Install Dependencies
uses: ./.github/actions/yarn-install
- name: Restore Built Dependencies
id: built-deps-restore
uses: actions/cache/restore@v4
- name: Cache Built Dependencies
id: built-deps
uses: ./.github/actions/cache-built-deps
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
fail-on-cache-miss: false
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}
- name: Debug Cache Restoration
run: |
echo "Cache hit: ${{ steps.built-deps.outputs.cache-hit }}"
echo "Cache key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}"
echo "Checking if cached files exist:"
ls -la packages/mobile-sdk-alpha/dist/ || echo "❌ mobile-sdk-alpha dist not found"
ls -la packages/mobile-sdk-alpha/dist/cjs/ || echo "❌ mobile-sdk-alpha dist/cjs not found"
ls -la packages/mobile-sdk-alpha/dist/cjs/index.cjs || echo "❌ mobile-sdk-alpha dist/cjs/index.cjs not found"
ls -la common/dist/ || echo "❌ common dist not found"
ls -la common/dist/cjs/ || echo "❌ common dist/cjs not found"
ls -la common/dist/cjs/index.cjs || echo "❌ common dist/cjs/index.cjs not found"
- name: Build dependencies (cache miss)
if: steps.built-deps-restore.outputs.cache-hit != 'true'
if: steps.built-deps.outputs.cache-hit != 'true'
run: |
echo "Cache miss for built dependencies. Building now..."
yarn workspace @selfxyz/mobile-app run build:deps
- name: Save Built Dependencies
if: steps.built-deps-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
# Verify build completed successfully
if [ ! -f "packages/mobile-sdk-alpha/dist/cjs/index.cjs" ] || [ ! -f "common/dist/cjs/index.cjs" ]; then
echo "❌ Build failed - required files missing after build"
ls -la packages/mobile-sdk-alpha/dist/ || echo "mobile-sdk-alpha dist not found"
ls -la common/dist/ || echo "common dist not found"
exit 1
fi
echo "✅ Build completed successfully"
- name: Force Build Dependencies If Missing
run: |
# Force build if required files don't exist, regardless of cache status
if [ ! -f "packages/mobile-sdk-alpha/dist/cjs/index.cjs" ] || [ ! -f "common/dist/cjs/index.cjs" ]; then
echo "❌ Required dependency files missing, forcing rebuild..."
echo "Missing files:"
[ ! -f "packages/mobile-sdk-alpha/dist/cjs/index.cjs" ] && echo " - packages/mobile-sdk-alpha/dist/cjs/index.cjs"
[ ! -f "common/dist/cjs/index.cjs" ] && echo " - common/dist/cjs/index.cjs"
yarn workspace @selfxyz/mobile-app run build:deps
# Verify build completed successfully
if [ ! -f "packages/mobile-sdk-alpha/dist/cjs/index.cjs" ] || [ ! -f "common/dist/cjs/index.cjs" ]; then
echo "❌ Forced build failed - required files still missing"
ls -la packages/mobile-sdk-alpha/ || echo "packages/mobile-sdk-alpha not found"
ls -la packages/mobile-sdk-alpha/dist/ || echo "mobile-sdk-alpha dist not found"
ls -la common/ || echo "common not found"
ls -la common/dist/ || echo "common dist not found"
exit 1
fi
echo "✅ Forced build completed successfully"
else
echo "✅ All required dependency files exist"
fi
- name: Test
run: yarn test
run: |
# Final verification from app directory perspective
echo "Final verification before running tests (from app directory)..."
if [ ! -f "../packages/mobile-sdk-alpha/dist/cjs/index.cjs" ] || [ ! -f "../common/dist/cjs/index.cjs" ]; then
echo "❌ Dependencies still not found from app directory"
ls -la ../packages/mobile-sdk-alpha/dist/ || echo "mobile-sdk-alpha dist not found"
ls -la ../common/dist/ || echo "common dist not found"
exit 1
fi
echo "✅ All dependencies verified, running tests..."
# Run jest through yarn to avoid the build:deps step since CI already built dependencies
yarn jest --passWithNoTests && node --test scripts/tests/*.cjs
working-directory: ./app
build-ios:
runs-on: macos-latest-large
@@ -257,28 +285,16 @@ jobs:
${{ runner.os }}-xcode-index-${{ env.XCODE_VERSION }}-
- name: Install Mobile Dependencies
uses: ./.github/actions/yarn-install
- name: Restore Built Dependencies
id: built-deps-restore
uses: actions/cache/restore@v4
- name: Cache Built Dependencies
id: built-deps
uses: ./.github/actions/cache-built-deps
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
fail-on-cache-miss: false
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}
- name: Build dependencies (cache miss)
if: steps.built-deps-restore.outputs.cache-hit != 'true'
if: steps.built-deps.outputs.cache-hit != 'true'
run: |
echo "Cache miss for built dependencies. Building now..."
yarn workspace @selfxyz/mobile-app run build:deps
- name: Save Built Dependencies
if: steps.built-deps-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
- name: Install Ruby Dependencies
run: |
echo "Installing Ruby dependencies..."
@@ -416,28 +432,16 @@ jobs:
run: sdkmanager "ndk;${{ env.ANDROID_NDK_VERSION }}"
- name: Install Mobile Dependencies
uses: ./.github/actions/yarn-install
- name: Restore Built Dependencies
id: built-deps-restore
uses: actions/cache/restore@v4
- name: Cache Built Dependencies
id: built-deps
uses: ./.github/actions/cache-built-deps
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
fail-on-cache-miss: false
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}
- name: Build dependencies (cache miss)
if: steps.built-deps-restore.outputs.cache-hit != 'true'
if: steps.built-deps.outputs.cache-hit != 'true'
run: |
echo "Cache miss for built dependencies. Building now..."
yarn workspace @selfxyz/mobile-app run build:deps
- name: Save Built Dependencies
if: steps.built-deps-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
common/dist
packages/mobile-sdk-alpha/dist
key: built-deps-${{ env.GH_CACHE_VERSION }}-${{ env.NODE_VERSION_SANITIZED }}-${{ hashFiles('common/**/*', 'packages/mobile-sdk-alpha/**/*', '!common/dist/**', '!packages/mobile-sdk-alpha/dist/**') }}
- name: Build Android (with AAPT2 symlink fix)
run: yarn android:ci
working-directory: ./app

View File

@@ -22,4 +22,4 @@ jobs:
shell: bash
run: yarn workspace @selfxyz/common build
- name: Build web app
run: yarn web:build
run: yarn workspace @selfxyz/mobile-app web:build

2
.nvmrc
View File

@@ -1 +1 @@
22
22.12.0

View File

@@ -1 +1,2 @@
nodeLinker: node-modules
enableGlobalCache: true

View File

@@ -38,6 +38,18 @@ module.exports = {
typescript: {
alwaysTryTypes: true,
project: './tsconfig.json',
extensions: [
'.ts',
'.tsx',
'.native.ts',
'.native.tsx',
'.web.ts',
'.web.tsx',
'.ios.ts',
'.ios.tsx',
'.android.ts',
'.android.tsx',
],
},
},
'import/ignore': ['react-native'],

View File

@@ -25,7 +25,7 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.4.0)
aws-partitions (1.1155.0)
aws-partitions (1.1156.0)
aws-sdk-core (3.232.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
@@ -37,7 +37,7 @@ GEM
aws-sdk-kms (1.112.0)
aws-sdk-core (~> 3, >= 3.231.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.198.0)
aws-sdk-s3 (1.199.0)
aws-sdk-core (~> 3, >= 3.231.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
@@ -256,7 +256,7 @@ GEM
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.4.2)
rexml (3.4.3)
rouge (3.28.0)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)

View File

@@ -12,7 +12,6 @@ import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import io.tradle.nfc.RNPassportReaderModule
import com.selfxyz.selfSDK.RNSelfPassportReaderModule
class MainActivity : ReactActivity() {
/**

View File

@@ -15,7 +15,6 @@ import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.soloader.SoLoader
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.selfxyz.selfSDK.RNSelfPassportReaderPackage
class MainApplication : Application(), ReactApplication {

View File

@@ -6,7 +6,7 @@ module.exports = {
preset: 'react-native',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
transformIgnorePatterns: [
'node_modules/(?!(react-native|@react-native|@react-navigation|@react-native-community|@segment/analytics-react-native|@openpassport|react-native-keychain|react-native-check-version|react-native-nfc-manager|react-native-passport-reader|react-native-gesture-handler|uuid|@stablelib|@react-native-google-signin|react-native-cloud-storage|@react-native-clipboard|@react-native-firebase|@selfxyz)/)',
'node_modules/(?!(react-native|@react-native|@react-navigation|@react-native-community|@segment/analytics-react-native|@openpassport|react-native-keychain|react-native-check-version|react-native-nfc-manager|react-native-passport-reader|react-native-gesture-handler|uuid|@stablelib|@react-native-google-signin|react-native-cloud-storage|@react-native-clipboard|@react-native-firebase|@selfxyz|@sentry)/)',
],
setupFiles: ['<rootDir>/jest.setup.js'],
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',

View File

@@ -157,6 +157,7 @@
"@testing-library/react-native": "^13.3.3",
"@tsconfig/react-native": "^3.0.6",
"@types/add": "^2",
"@types/dompurify": "^3.2.0",
"@types/elliptic": "^6",
"@types/jest": "^29.5.14",
"@types/node-forge": "^1.3.14",
@@ -170,6 +171,7 @@
"@typescript-eslint/parser": "^8.39.0",
"@vitejs/plugin-react-swc": "^3.10.2",
"babel-plugin-module-resolver": "^5.0.2",
"dompurify": "^3.2.6",
"eslint": "^8.57.0",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-typescript": "^3.7.0",

View File

@@ -0,0 +1,18 @@
// 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, { forwardRef } from 'react';
import type { StyleProp, ViewStyle } from 'react-native';
import { SvgXml as RNSvgXml } from 'react-native-svg';
type Props = {
xml: string;
width?: number;
height?: number;
style?: StyleProp<ViewStyle>;
};
export const SvgXml = forwardRef<any, Props>((p, _ref) => <RNSvgXml {...p} />);
SvgXml.displayName = 'SvgXml';
export default SvgXml;

View File

@@ -0,0 +1,8 @@
// 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.
// Re-export from the native version - Metro resolver will automatically
// pick the appropriate platform-specific file (.web.tsx or .native.tsx)
export { SvgXml } from '@/components/homeScreen/SvgXmlWrapper.native';
export { default } from '@/components/homeScreen/SvgXmlWrapper.native';

View File

@@ -0,0 +1,37 @@
// 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 DOMPurify from 'dompurify';
import React, { createElement, forwardRef } from 'react';
type Props = {
xml: string;
width?: number;
height?: number;
style?: React.CSSProperties;
} & React.HTMLAttributes<HTMLDivElement>;
export const SvgXml = forwardRef<HTMLDivElement, Props>(
({ xml, width, height, style, ...props }, ref) => {
// Initialize DOMPurify for web browser environment
const purify = DOMPurify(window);
const safe = purify.sanitize(xml, {
USE_PROFILES: { svg: true, svgFilters: true },
});
return createElement('div', {
ref,
style: {
width: width || 'auto',
height: height || 'auto',
display: 'inline-block',
...style,
},
dangerouslySetInnerHTML: { __html: safe },
...props,
});
},
);
SvgXml.displayName = 'SvgXml';
export default SvgXml;

View File

@@ -4,18 +4,18 @@
import React, { useCallback, useState } from 'react';
import { Dimensions, Pressable } from 'react-native';
import { SvgXml } from 'react-native-svg';
import { Button, Image, Separator, Text, XStack, YStack } from 'tamagui';
import { useFocusEffect } from '@react-navigation/native';
import {
attributeToPosition,
attributeToPosition_ID,
formatMrz,
PassportData,
} from '@selfxyz/common/dist/esm';
import { pad } from '@selfxyz/common/dist/esm/src/utils/passports/passport';
} from '@selfxyz/common/constants';
import { PassportData } from '@selfxyz/common/types';
import { formatMrz } from '@selfxyz/common/utils';
import { pad } from '@selfxyz/common/utils/passports/passport';
import { SvgXml } from '@/components/homeScreen/SvgXmlWrapper';
import EPassport from '@/images/icons/epassport.svg';
import LogoGray from '@/images/logo_gray.svg';
import LogoInversed from '@/images/logo_inversed.svg';

View File

@@ -0,0 +1,35 @@
// 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, { createElement, forwardRef } from 'react';
type BlurViewProps = React.HTMLAttributes<HTMLDivElement> & {
blurType?: string;
blurAmount?: number;
reducedTransparencyFallbackColor?: string;
pointerEvents?: 'auto' | 'none';
};
// Mock BlurView component for web builds
export const BlurView = forwardRef<HTMLDivElement, BlurViewProps>(
({ children, style, pointerEvents, blurAmount, ...props }, ref) => {
return createElement(
'div',
{
ref,
style: {
backgroundColor: 'rgba(255, 255, 255, 0.1)',
backdropFilter: `blur(${typeof blurAmount === 'number' ? blurAmount : 10}px)`,
pointerEvents: pointerEvents,
...style,
},
// Do not spread pointerEvents as a DOM attribute
...props,
},
children,
);
},
);
BlurView.displayName = 'BlurView';

View File

@@ -0,0 +1,67 @@
// 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';
export const Circle = React.forwardRef<
SVGCircleElement,
React.SVGProps<SVGCircleElement>
>((props, ref) => {
return React.createElement('circle', { ref, ...props });
});
Circle.displayName = 'Circle';
export const Path = React.forwardRef<
SVGPathElement,
React.SVGProps<SVGPathElement>
>((props, ref) => {
return React.createElement('path', { ref, ...props });
});
Path.displayName = 'Path';
export const Rect = React.forwardRef<
SVGRectElement,
React.SVGProps<SVGRectElement>
>((props, ref) => {
return React.createElement('rect', { ref, ...props });
});
Rect.displayName = 'Rect';
// Re-export other common SVG components that might be used
export const Svg = React.forwardRef<
SVGSVGElement,
React.SVGProps<SVGSVGElement>
>((props, ref) => {
return React.createElement('svg', { ref, ...props });
});
Svg.displayName = 'Svg';
// Mock SvgXml component for web builds
export const SvgXml = React.forwardRef<
HTMLDivElement,
{
xml: string;
width?: number;
height?: number;
style?: React.CSSProperties;
}
>(({ xml, width, height, style, ...props }, ref) => {
return React.createElement('div', {
ref,
style: {
width: width || 'auto',
height: height || 'auto',
display: 'inline-block',
...style,
},
dangerouslySetInnerHTML: { __html: xml },
...props,
});
});
SvgXml.displayName = 'SvgXml';

View File

@@ -2,17 +2,13 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import { ProgressNavBar } from '@/components/NavBar';
import { shouldShowAesopRedesign } from '@/hooks/useAesopRedesign';
import DocumentOnboardingScreen from '@/screens/aesop/DocumentOnboardingScreen';
import { white } from '@/utils/colors';
const DocumentOnboardingScreen = lazy(
() => import('@/screens/aesop/DocumentOnboardingScreen'),
);
const aesopScreens = {
DocumentOnboarding: {
screen: DocumentOnboardingScreen,

View File

@@ -2,26 +2,16 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import CreateMockScreen from '@/screens/dev/CreateMockScreen';
import CreateMockScreenDeepLink from '@/screens/dev/CreateMockScreenDeepLink';
import DevFeatureFlagsScreen from '@/screens/dev/DevFeatureFlagsScreen';
import DevHapticFeedbackScreen from '@/screens/dev/DevHapticFeedbackScreen';
import DevPrivateKeyScreen from '@/screens/dev/DevPrivateKeyScreen';
import DevSettingsScreen from '@/screens/dev/DevSettingsScreen';
import { black, white } from '@/utils/colors';
const DevFeatureFlagsScreen = lazy(
() => import('@/screens/dev/DevFeatureFlagsScreen'),
);
const DevHapticFeedbackScreen = lazy(
() => import('@/screens/dev/DevHapticFeedbackScreen'),
);
const DevPrivateKeyScreen = lazy(
() => import('@/screens/dev/DevPrivateKeyScreen'),
);
const DevSettingsScreen = lazy(() => import('@/screens/dev/DevSettingsScreen'));
const CreateMockScreen = lazy(() => import('@/screens/dev/CreateMockScreen'));
const CreateMockScreenDeepLink = lazy(
() => import('@/screens/dev/CreateMockScreenDeepLink'),
);
const devHeaderOptions: NativeStackNavigationOptions = {
headerStyle: {
backgroundColor: black,

View File

@@ -2,30 +2,15 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
const DocumentCameraScreen = lazy(
() => import('@/screens/document/DocumentCameraScreen'),
);
const DocumentCameraTroubleScreen = lazy(
() => import('@/screens/document/DocumentCameraTroubleScreen'),
);
const DocumentNFCScanScreen = lazy(
() => import('@/screens/document/DocumentNFCScanScreen'),
);
const DocumentNFCTroubleScreen = lazy(
() => import('@/screens/document/DocumentNFCTroubleScreen'),
);
const DocumentOnboardingScreen = lazy(
() => import('@/screens/document/DocumentOnboardingScreen'),
);
const UnsupportedDocumentScreen = lazy(
() => import('@/screens/document/UnsupportedDocumentScreen'),
);
const DocumentNFCMethodSelectionScreen = lazy(
() => import('@/screens/document/DocumentNFCMethodSelectionScreen'),
);
import DocumentCameraScreen from '@/screens/document/DocumentCameraScreen';
import DocumentCameraTroubleScreen from '@/screens/document/DocumentCameraTroubleScreen';
import DocumentNFCMethodSelectionScreen from '@/screens/document/DocumentNFCMethodSelectionScreen';
import DocumentNFCScanScreen from '@/screens/document/DocumentNFCScanScreen';
import DocumentNFCTroubleScreen from '@/screens/document/DocumentNFCTroubleScreen';
import DocumentOnboardingScreen from '@/screens/document/DocumentOnboardingScreen';
import UnsupportedDocumentScreen from '@/screens/document/UnsupportedDocumentScreen';
const documentScreens = {
DocumentCamera: {

View File

@@ -2,20 +2,15 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import { HomeNavBar, IdDetailsNavBar } from '@/components/NavBar';
import DisclaimerScreen from '@/screens/home/DisclaimerScreen';
import HomeScreen from '@/screens/home/HomeScreen';
import IdDetailsScreen from '@/screens/home/IdDetailsScreen';
import ProofHistoryDetailScreen from '@/screens/home/ProofHistoryDetailScreen';
import ProofHistoryScreen from '@/screens/home/ProofHistoryScreen';
const DisclaimerScreen = lazy(() => import('@/screens/home/DisclaimerScreen'));
const HomeScreen = lazy(() => import('@/screens/home/HomeScreen'));
const ProofHistoryDetailScreen = lazy(
() => import('@/screens/home/ProofHistoryDetailScreen'),
);
const ProofHistoryScreen = lazy(
() => import('@/screens/home/ProofHistoryScreen'),
);
const IdDetailsScreen = lazy(() => import('@/screens/home/IdDetailsScreen'));
const homeScreens = {
Disclaimer: {
screen: DisclaimerScreen,

View File

@@ -2,10 +2,9 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import React, { Suspense, useEffect } from 'react';
import { Platform, View } from 'react-native';
import React, { useEffect } from 'react';
import { Platform } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { Text } from 'tamagui';
import type { StaticParamList } from '@react-navigation/native';
import {
createNavigationContainerRef,
@@ -63,17 +62,6 @@ declare global {
const { trackScreenView } = analytics();
const Navigation = createStaticNavigation(AppNavigation);
const SuspenseFallback = () => {
if (Platform.OS === 'web') {
return <div>Loading...</div>;
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Loading...</Text>
</View>
);
};
const NavigationWithTracking = () => {
const trackScreen = () => {
const currentRoute = navigationRef.getCurrentRoute();
@@ -96,9 +84,7 @@ const NavigationWithTracking = () => {
return (
<GestureHandlerRootView>
<Suspense fallback={<SuspenseFallback />}>
<Navigation ref={navigationRef} onStateChange={trackScreen} />
</Suspense>
<Navigation ref={navigationRef} onStateChange={trackScreen} />
</GestureHandlerRootView>
);
};

View File

@@ -1,19 +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 { lazy, type LazyExoticComponent } from 'react';
// Helper around React.lazy that exposes the underlying dynamic import
// so callers can manually preload a screen when debugging or profiling.
// Prefer using React.lazy directly and opt into this only when you need
// to eagerly load a component.
export function lazyWithPreload<T extends React.ComponentType<any>>(
factory: () => Promise<{ default: T }>,
) {
const Component = lazy(factory) as LazyExoticComponent<T> & {
preload: () => Promise<{ default: T }>;
};
Component.preload = factory;
return Component;
}

View File

@@ -2,25 +2,15 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import ConfirmBelongingScreen from '@/screens/prove/ConfirmBelongingScreen';
import ProofRequestStatusScreen from '@/screens/prove/ProofRequestStatusScreen';
import ProveScreen from '@/screens/prove/ProveScreen';
import QRCodeTroubleScreen from '@/screens/prove/QRCodeTroubleScreen';
import QRCodeViewFinderScreen from '@/screens/prove/QRCodeViewFinderScreen';
import { black, white } from '@/utils/colors';
const ConfirmBelongingScreen = lazy(
() => import('@/screens/prove/ConfirmBelongingScreen'),
);
const ProofRequestStatusScreen = lazy(
() => import('@/screens/prove/ProofRequestStatusScreen'),
);
const ProveScreen = lazy(() => import('@/screens/prove/ProveScreen'));
const QRCodeTroubleScreen = lazy(
() => import('@/screens/prove/QRCodeTroubleScreen'),
);
const QRCodeViewFinderScreen = lazy(
() => import('@/screens/prove/QRCodeViewFinderScreen'),
);
const proveScreens = {
ConfirmBelonging: {
screen: ConfirmBelongingScreen,

View File

@@ -2,30 +2,16 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import AccountRecoveryChoiceScreen from '@/screens/recovery/AccountRecoveryChoiceScreen';
import AccountRecoveryScreen from '@/screens/recovery/AccountRecoveryScreen';
import AccountVerifiedSuccessScreen from '@/screens/recovery/AccountVerifiedSuccessScreen';
import DocumentDataNotFound from '@/screens/recovery/DocumentDataNotFoundScreen';
import RecoverWithPhraseScreen from '@/screens/recovery/RecoverWithPhraseScreen';
import SaveRecoveryPhraseScreen from '@/screens/recovery/SaveRecoveryPhraseScreen';
import { black, slate300 } from '@/utils/colors';
const AccountRecoveryChoiceScreen = lazy(
() => import('@/screens/recovery/AccountRecoveryChoiceScreen'),
);
const AccountRecoveryScreen = lazy(
() => import('@/screens/recovery/AccountRecoveryScreen'),
);
const AccountVerifiedSuccessScreen = lazy(
() => import('@/screens/recovery/AccountVerifiedSuccessScreen'),
);
const DocumentDataNotFound = lazy(
() => import('@/screens/recovery/DocumentDataNotFoundScreen'),
);
const RecoverWithPhraseScreen = lazy(
() => import('@/screens/recovery/RecoverWithPhraseScreen'),
);
const SaveRecoveryPhraseScreen = lazy(
() => import('@/screens/recovery/SaveRecoveryPhraseScreen'),
);
const recoveryScreens = {
AccountRecovery: {
screen: AccountRecoveryScreen,

View File

@@ -2,12 +2,9 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
const DocumentDataNotFound = lazy(
() => import('@/screens/recovery/DocumentDataNotFoundScreen'),
);
import DocumentDataNotFound from '@/screens/recovery/DocumentDataNotFoundScreen';
const recoveryScreens = {
DocumentDataNotFound: {

View File

@@ -2,25 +2,15 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import CloudBackupScreen from '@/screens/settings/CloudBackupScreen';
import DocumentDataInfoScreen from '@/screens/settings/DocumentDataInfoScreen';
import ManageDocumentsScreen from '@/screens/settings/ManageDocumentsScreen';
import SettingsScreen from '@/screens/settings/SettingsScreen';
import ShowRecoveryPhraseScreen from '@/screens/settings/ShowRecoveryPhraseScreen';
import { black, slate300, white } from '@/utils/colors';
const CloudBackupScreen = lazy(
() => import('@/screens/settings/CloudBackupScreen'),
);
const ManageDocumentsScreen = lazy(
() => import('@/screens/settings/ManageDocumentsScreen'),
);
const DocumentDataInfoScreen = lazy(
() => import('@/screens/settings/DocumentDataInfoScreen'),
);
const SettingsScreen = lazy(() => import('@/screens/settings/SettingsScreen'));
const ShowRecoveryPhraseScreen = lazy(
() => import('@/screens/settings/ShowRecoveryPhraseScreen'),
);
const settingsScreens = {
CloudBackupSettings: {
screen: CloudBackupScreen,

View File

@@ -2,19 +2,13 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { lazy } from 'react';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
import DocumentDataInfoScreen from '@/screens/settings/DocumentDataInfoScreen';
import ManageDocumentsScreen from '@/screens/settings/ManageDocumentsScreen';
import SettingsScreen from '@/screens/settings/SettingsScreen';
import { black, white } from '@/utils/colors';
const ManageDocumentsScreen = lazy(
() => import('@/screens/settings/ManageDocumentsScreen'),
);
const DocumentDataInfoScreen = lazy(
() => import('@/screens/settings/DocumentDataInfoScreen'),
);
const SettingsScreen = lazy(() => import('@/screens/settings/SettingsScreen'));
const settingsScreens = {
ManageDocuments: {
screen: ManageDocumentsScreen,

View File

@@ -2,22 +2,16 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import React, { lazy } from 'react';
import React from 'react';
import { SystemBars } from 'react-native-edge-to-edge';
import type { NativeStackNavigationOptions } from '@react-navigation/native-stack';
// Important: SplashScreen is imported directly and not lazy-loaded.
// This is because it's used as a fallback for the Suspense boundary in the root navigator,
// ensuring it's immediately available at startup.
import DeferredLinkingInfoScreen from '@/screens/system/DeferredLinkingInfoScreen';
import LaunchScreen from '@/screens/system/LaunchScreen';
import LoadingScreen from '@/screens/system/Loading';
import ModalScreen from '@/screens/system/ModalScreen';
import SplashScreen from '@/screens/system/SplashScreen';
const LaunchScreen = lazy(() => import('@/screens/system/LaunchScreen'));
const LoadingScreen = lazy(() => import('@/screens/system/Loading'));
const ModalScreen = lazy(() => import('@/screens/system/ModalScreen'));
const DeferredLinkingInfoScreen = lazy(
() => import('@/screens/system/DeferredLinkingInfoScreen'),
);
const systemScreens = {
Launch: {
screen: LaunchScreen,

View File

@@ -12,8 +12,8 @@ import {
usePreventRemove,
} from '@react-navigation/native';
import { PassportData } from '@selfxyz/common/dist/esm';
import { DocumentCatalog } from '@selfxyz/common/dist/esm/src/utils/types';
import { PassportData } from '@selfxyz/common/types';
import { DocumentCatalog } from '@selfxyz/common/utils/types';
import { DocumentMetadata, useSelfClient } from '@selfxyz/mobile-sdk-alpha';
import { ProofEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';

View File

@@ -9,8 +9,8 @@ import { Button, Text, XStack, YStack, ZStack } from 'tamagui';
import { BlurView } from '@react-native-community/blur';
import { useNavigation, useRoute } from '@react-navigation/native';
import { DocumentCatalog } from '@selfxyz/common/dist/esm/src/utils/types';
import { PassportData } from '@selfxyz/common/types';
import { DocumentCatalog } from '@selfxyz/common/utils/types';
import IdCardLayout from '@/components/homeScreen/idCard';
import { usePassport } from '@/providers/passportDataProvider';

View File

@@ -28,6 +28,7 @@ describe('navigation', () => {
'DocumentNFCTrouble',
'DocumentOnboarding',
'Home',
'IdDetails',
'Launch',
'Loading',
'ManageDocuments',

View File

@@ -1,176 +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.
/**
* @jest-environment node
*/
// Override global error handling to prevent circular references
import { execSync, spawn } from 'child_process';
import { afterAll, beforeAll, describe, expect, test } from '@jest/globals';
const originalError = global.Error;
global.Error = class SafeError extends originalError {
constructor(...args: any[]) {
super(...args);
// Ensure no circular references are added to error objects
Object.defineProperty(this, 'error', {
value: undefined,
writable: false,
enumerable: false,
});
}
};
// Ensure fetch is available (Node.js 18+ has built-in fetch)
if (typeof fetch === 'undefined') {
throw new Error(
'fetch is not available. This test requires Node.js 18+ with built-in fetch support.',
);
}
// Increase default timeouts for build and page load
const BUILD_TIMEOUT = 120_000;
const PAGE_LOAD_TIMEOUT = 10_000;
const PREVIEW_URL = 'http://localhost:4173';
describe('Web Build and Render', () => {
let previewProcess: ReturnType<typeof spawn> | undefined;
beforeAll(async () => {
// Build the web app
execSync('yarn web:build', {
stdio: 'inherit',
timeout: BUILD_TIMEOUT,
cwd: process.cwd(),
});
// Start preview server
previewProcess = spawn(
'yarn',
['web:preview', '--port', '4173', '--host'],
{
cwd: process.cwd(),
stdio: 'pipe',
},
);
await new Promise<void>((resolve, reject) => {
const timeout = setTimeout(
() => reject(new Error('Preview server failed to start')),
15_000, // Increased timeout to account for Tamagui build time
);
let serverOutput = '';
if (previewProcess?.stdout) {
previewProcess.stdout.on('data', (data: Buffer) => {
const output = data.toString();
serverOutput += output;
// Suppress noisy output in tests
if (process.env.DEBUG_BUILD_TEST) {
console.log('Preview server stdout:', JSON.stringify(output));
}
// Look for the Local: indicator that the server is ready
// Be more flexible with pattern matching
const isReady =
output.includes('Local:') ||
output.includes('localhost:4173') ||
/Local:\s*http:\/\/localhost:4173/i.test(output) ||
/➜\s*Local:/i.test(output) ||
(output.includes('4173') && output.includes('Local'));
if (isReady) {
if (process.env.DEBUG_BUILD_TEST) {
console.log('Server ready detected!');
}
clearTimeout(timeout);
resolve();
}
});
}
if (previewProcess?.stderr) {
previewProcess.stderr.on('data', (data: Buffer) => {
const error = data.toString();
console.error('Preview server stderr:', error);
serverOutput += error;
});
}
previewProcess?.on('error', error => {
clearTimeout(timeout);
// Avoid circular references by only using the error message string
const errorMessage =
error?.message || error?.toString() || 'Unknown error';
reject(new Error(`Preview server process error: ${errorMessage}`));
});
previewProcess?.on('exit', (code, _signal) => {
if (code !== null && code !== 0) {
clearTimeout(timeout);
reject(
new Error(
`Preview server exited with code ${code}. Output: ${serverOutput}`,
),
);
}
});
});
// Give the server a moment to fully start
await new Promise(resolve => setTimeout(resolve, 3000));
}, BUILD_TIMEOUT + 10_000);
afterAll(async () => {
if (previewProcess) {
try {
previewProcess.kill('SIGTERM');
// Give it a moment to terminate gracefully
await new Promise(resolve => setTimeout(resolve, 1000));
if (!previewProcess.killed) {
previewProcess.kill('SIGKILL');
}
} catch (error) {
// Safely log error without circular references
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error('Error killing preview process:', errorMessage);
}
}
});
test(
'web app builds and server responds with valid HTML',
async () => {
// Test that the server responds with a 200 status
const response = await fetch(PREVIEW_URL);
expect(response.status).toBe(200);
expect(response.headers.get('content-type')).toContain('text/html');
// Test that the response contains basic HTML structure
const html = await response.text();
expect(html.toLowerCase()).toContain('<!doctype html>');
expect(html).toContain('<html');
expect(html).toContain('<head>');
expect(html).toContain('<body>');
expect(html).toContain('<div id="root">');
// Test that essential assets are referenced
expect(html).toContain('.js');
expect(html).toContain('.css');
// Verify the HTML is not empty or minimal
expect(html.length).toBeGreaterThan(500);
// Test that the title is present
expect(html).toContain('<title>');
expect(html).toContain('Self App');
},
PAGE_LOAD_TIMEOUT,
);
});

View File

@@ -34,6 +34,10 @@ export default defineConfig({
'@': resolve(__dirname, 'src'),
'react-native-svg': 'react-native-svg-web',
'lottie-react-native': 'lottie-react',
'@react-native-community/blur': resolve(
__dirname,
'src/mocks/react-native-community-blur.ts',
),
'react-native-safe-area-context': resolve(
__dirname,
'src/mocks/react-native-safe-area-context.js',

View File

@@ -3,28 +3,18 @@
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
module.exports = {
dependencies: {
'@selfxyz/mobile-sdk-alpha': {
platforms: {
ios: {
sourceDir: './ios',
podspecPath: './mobile-sdk-alpha.podspec',
},
android: {
sourceDir: './android',
manifestPath: 'src/main/AndroidManifest.xml',
packageImportPath: 'import com.selfxyz.selfSDK.RNSelfPassportReaderPackage;',
packageInstance: 'new RNSelfPassportReaderPackage()',
},
dependency: {
platforms: {
ios: {
sourceDir: './ios',
podspecPath: './mobile-sdk-alpha.podspec',
},
android: {
sourceDir: './android',
manifestPath: 'src/main/AndroidManifest.xml',
packageImportPath: 'import com.selfxyz.selfSDK.RNSelfPassportReaderPackage;',
packageInstance: 'new RNSelfPassportReaderPackage()',
},
},
},
project: {
ios: {
sourceDir: './ios',
},
android: {
sourceDir: './android',
},
},
};

1020
yarn.lock

File diff suppressed because it is too large Load Diff