Files
self/app/metro.config.cjs
turnoffthiscomputer 3d0e1b4589 feat: 2.9 (#1325)
* 2.9 release

* 2.9 release

* Remove debug console logs from generateTEEInputsRegister function in registerInputs.ts

* parse only the passport data during the dsc step

* Add ReferralScreen and integrate referral functionality
- Introduced ReferralScreen for sharing referral links via messages, WhatsApp, and clipboard.
- Updated navigation to include ReferralScreen in the home stack.
- Added new icons for sharing and messaging.
- Enhanced points utility functions to check user identity document registration and points disclosure status.
- Minor adjustments to existing components for better integration with the new referral feature.

* fix types

* fix font

* fix vertical spacing

* save current abstraction

* clean up linking

* clean up spurious ai slop comments

* add dinot bold font

* minify animations

* update fonts and add placeholder animation

* fix pipelines

* fix order

* Update dependencies and enhance Points component functionality
- Added `@react-native-masked-view/masked-view` and `react-native-linear-gradient` to dependencies for improved UI components.
- Refactored `PointHistoryList` to accept `ListHeaderComponent` and `onRefreshRef` props for better integration with parent components.
- Enhanced `Points` component to manage notification and backup point events, including user feedback through modals.
- Updated navigation to use `PointsNavBar` for a more cohesive user experience.
- Introduced new utility functions for managing incoming points and point event records.

* update lock

* update lock and project settings

* fix line height for android

* save wip referral message fix and deeplink setup

* Fix whatsapp link (#1352)

* add 2 new lines

* use path based param instead of query string

* use staging url for now

* SELF-1089: Fix black screen on Points (#1351)

* Fix black screen on Points

* Fix: black screen on Referral Page

* fix: prevent BlurView from displaying when IdDetailsScreen loses focus

* Fix Android message share (#1355)

* Referral flow (#1354)

* SELF-1139: update getUserAddress() (#1353)

* update getUserAddress()

* rename getUserAddress to getPointsAddress

* [SELF-1098, SELF-1099] polish gratification screen post referrer update history (#1356)

* fix: mark document as registered after restoring secret (#1350)

* update lock

* create useRegisterReferral hook and test

* add referral message test

* save wip register referral flow request

* use register referral from the home screen

* fix typing and sort screens

* fix linting issues

* register poitns and update tests

* use package

* fix tests

* simplify HomeScreen with hooks

* fix tests

* address tests

* abstract points logic, fix types and linting

* add test referral flow hook

* coderabbit feedback: fix refereral logic issues, remove sensitive logs

* move test referral flow button to dev settings screen

* close modal after referring and viewing gratification screen

* fix tests, remove alert, format

---------

Co-authored-by: Seshanth.S <35675963+seshanthS@users.noreply.github.com>

* add gratification bg; use safe bottom padding hook on home screen

* prep 2.7.4 as 2.9.0

* manually bump version for custom deploy

* match version code

* fix types

* formatting

* fix tests

* SELF-1144 - use real points on home screen and improve points screen (#1361)

* fix whitespace

* move effects for fetching points and incoming points to hooks, add items to deps array so that they refresh when we expect points to change.

* cleanup

* Add events for new Points Flow (#1362)

* remove deeplinkCallback from pointsSelfApp. (#1365)

* fix pipelines

* SELF-978: wire cloudbackup with points (#1360)

* wire cloudbackup with points

* wire cloudbackup with points

* Remove redundant setSelfPoints()

* add signature and simplify POST api requests (#1367)

* add signature and simplify POST api requests

* better gitleaks ignore

* update toml

* have gitguardian ignore gitleaks

* add buffer lib

* update api with 202 success code

* update scope and contract-address (#1366)

* fix navigation test

* SELF-915: Setup and add turnkey utils (#1314)

* Setup and add turnkey utils

* update CloudBackupScreen

* fix: turnkey

* add yarn.lock

* lint

* add podfile.lock

* fix deeplink

* fix tests: mock turnkey

* yarn nice

* update .gitleaksignore

* patch react-native-svg

* fix patch-package

* fix lineHeight

* points.tsx: fix lineHeight

* fix: recover with turnkey disabled state

* fix turnkey flow

* fix: address generation

* minify animations (#1368)

* fix pipelines

* fix false positives

* fix gitguardian

---------

Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz>

* enable turnkey only on success

* use prod url

* fix tests and update mocks

* update version and fastlane readme

* pointsSelfApp: update scope

* bump android version to 117

* incremenet timestamp

* abstract points css, hide explore button for now, add points guardrail

* better logic

* simplify point event list data acquisition (#1375)

* simplify point event list data acquisition

* explain

* Remove BlurView in Points.tsx

* Move Points and IncomingPoints to the Point Events Store (#1363)


* add polling for event processing.
atomically update store state

* handle failed states and use real backend api


* improve concurrency reliability of pointevents

* move points to the store


* refresh all points on pull

* add points tracking events

* fix imports

* fix headers

* fix import

* fix misspelling

* enable apps link

* remove __DEV__ logging

* remove additional referall dev mode features

* Add turnkey env

* don't allow users to refer themselves

* prettier

* trim both addresses

* fix close webview button

* fix tests and format

* lint and format

* Update point rewards in NavBar component: change earned points from 20 to 44 and from 100 to 32.

* Refactor point rewards in NavBar component: replace hardcoded values with constants for backup and notification points, and update subscription state variable names for clarity.

* Update POINT_VALUES in types.ts: adjust point rewards for disclosure, notification, and backup events to 8, 44, and 32 respectively.

* App/fix backup points (#1381)

* Enhance backup completion tracking in Points component: Introduce a ref to manage backup check flag, ensuring points are recorded only when explicitly set, preventing false triggers from other navigation flows.

* Update API endpoint in getTotalPoints function: change URL from /distribution to /points for accurate points retrieval.

* formatting

* update points url

* Clear referrer on modal dismiss in useEarnPointsFlow hook to prevent retry loop

* use points private key to sign api requests

* formatting

* save working version of referral confirmation

* fix circular dependency

* don't fetch private key if unable to fetch points key

* add url

* add debug info

* Refactor optimistic points calculation in usePointEventStore: update return value to only include incomingPoints.amount, marking the optimistic approach for future improvement.

* save clean up

* clean useReferralConfirmation logic

* fix tests

* tests pass

* standardize android compile sdk version

* fix package version

* don't log errors

* Update app/src/hooks/useReferralConfirmation.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* better test

* add turnkey entitlements

* fix linting

* remove entitlements

* prettier and fix lint

* update gradle version

* update lock file

* fix tests

* fix build failure

* bump android version to 118

* update date

* bump version for next build

* address failing pipelines due to cache issues

* Hide turnkey button (#1387)

* prep for 2.9.0 release

* fix mobile e2e test

* fix tests

* bump android version

---------

Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz>
Co-authored-by: Seshanth.S <35675963+seshanthS@users.noreply.github.com>
Co-authored-by: Leszek Stachowski <leszek.stachowski@self.xyz>
Co-authored-by: Aaron DeRuvo <aaron.deruvo@clabs.co>
Co-authored-by: seshanthS <seshanth@protonmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-11-11 10:37:05 -08:00

441 lines
15 KiB
JavaScript

// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const path = require('node:path');
const fs = require('node:fs');
const findYarnWorkspaceRoot = require('find-yarn-workspace-root');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;
const projectRoot = __dirname;
const workspaceRoot =
findYarnWorkspaceRoot(__dirname) || path.resolve(__dirname, '..');
/**
* 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',
),
disableImportExportTransform: true,
inlineRequires: true,
},
resolver: {
// 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/lottie-react-native(/|$)',
),
new RegExp('packages/mobile-sdk-alpha/node_modules/scheduler(/|$)'),
new RegExp(
'packages/mobile-sdk-alpha/node_modules/react-native-svg(/|$)',
),
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(/|$)'),
new RegExp('packages/mobile-sdk-demo/node_modules/react-native-svg(/|$)'),
],
// 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'),
process: require.resolve('process'),
'react-native-svg': path.resolve(
projectRoot,
'node_modules/react-native-svg',
),
// 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 both .js imports in TypeScript and Node.js modules
resolveRequest: (context, moduleName, platform) => {
// Handle React Native gesture handler that needs app-level resolution
const appLevelModules = {
'react-native-gesture-handler':
'react-native-gesture-handler/lib/commonjs/index.js',
};
const sdkAlphaPath = path.resolve(
workspaceRoot,
'packages/mobile-sdk-alpha',
);
// Custom resolver to handle Node.js modules and dynamic flow imports
if (moduleName.startsWith('@selfxyz/mobile-sdk-alpha/')) {
const subPath = moduleName.replace('@selfxyz/mobile-sdk-alpha/', '');
// Check if it's a flow import (onboarding/* or disclosing/*)
if (
subPath.startsWith('onboarding/') ||
subPath.startsWith('disclosing/')
) {
const flowPath = path.resolve(
sdkAlphaPath,
'dist/esm/flows',
`${subPath}.js`,
);
// Check if the file exists
if (fs.existsSync(flowPath)) {
return {
type: 'sourceFile',
filePath: flowPath,
};
}
}
}
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 @turnkey/encoding to use CommonJS instead of ESM
if (moduleName === '@turnkey/encoding') {
const filePath = path.resolve(
projectRoot,
'node_modules/@turnkey/encoding/dist/index.js',
);
return {
type: 'sourceFile',
filePath,
};
}
// Fix @turnkey/encoding submodules to use CommonJS
if (moduleName.startsWith('@turnkey/encoding/')) {
const subpath = moduleName.replace('@turnkey/encoding/', '');
const filePath = path.resolve(
projectRoot,
`node_modules/@turnkey/encoding/dist/${subpath}.js`,
);
return {
type: 'sourceFile',
filePath,
};
}
// Fix @turnkey/api-key-stamper to use CommonJS instead of ESM
if (moduleName === '@turnkey/api-key-stamper') {
const filePath = path.resolve(
projectRoot,
'node_modules/@turnkey/api-key-stamper/dist/index.js',
);
return {
type: 'sourceFile',
filePath,
};
}
// Fix @turnkey/api-key-stamper dynamic imports by resolving submodules statically
if (moduleName.startsWith('@turnkey/api-key-stamper/')) {
const subpath = moduleName.replace('@turnkey/api-key-stamper/', '');
const filePath = path.resolve(
projectRoot,
`node_modules/@turnkey/api-key-stamper/dist/${subpath}`,
);
return {
type: 'sourceFile',
filePath,
};
}
// Fix viem dynamic import resolution
if (moduleName === 'viem') {
try {
// Viem uses package exports, so we need to resolve to the actual file path
const viemPath = path.resolve(
projectRoot,
'node_modules/viem/_cjs/index.js',
);
return {
type: 'sourceFile',
filePath: viemPath,
};
} catch (error) {
console.warn('Failed to resolve viem:', error);
}
}
// 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: 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 (
Object.prototype.hasOwnProperty.call(nodeModuleRedirects, moduleName)
) {
if (nodeModuleRedirects[moduleName] === false) {
// Return empty module for disabled modules
return { type: 'empty' };
}
// Redirect to polyfill
return {
type: 'sourceFile',
filePath: nodeModuleRedirects[moduleName],
};
}
// 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
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;
}
},
},
};
module.exports = mergeConfig(defaultConfig, config);