diff --git a/README.md b/README.md
index a1fd2b69..67cd4b9e 100755
--- a/README.md
+++ b/README.md
@@ -54,6 +54,15 @@ Shared code (anything that can be reused, cryptography, network fetchers, react
Development build for android (produces apk that has to load bundle remotely): `eas build --platform android --profile development-simulator --local`
+Mac Catalyst builds from `mobile/`:
+
+- Local debug build: `npm run mac`
+- Local release build: `npm run mac:release`
+- Local EAS custom build: `npm run mac:eas:local`
+- EAS cloud build: `eas build --platform ios --profile mac-catalyst`
+
+The Mac Catalyst path currently builds an unsigned `.app` artifact from the existing iOS native project. Local output is written under `mobile/ios/build/Build/Products`, and the EAS profile uploads `ios/build/Build/Products/Release-maccatalyst/LayerzWallet.app`.
+
## Tests
TBD
@@ -79,4 +88,6 @@ We are also relying on Expo EAS for builds, so a generic workflow to run e2e tes
## Build
* local android build: `eas build --platform android --profile preview --local`
+* local mac build: `cd mobile && npm run mac`
+* EAS mac build: `cd mobile && eas build --platform ios --profile mac-catalyst`
* ext build: `npm run build`
diff --git a/mobile/.eas/build/mac-catalyst.yml b/mobile/.eas/build/mac-catalyst.yml
new file mode 100644
index 00000000..5619c181
--- /dev/null
+++ b/mobile/.eas/build/mac-catalyst.yml
@@ -0,0 +1,28 @@
+build:
+ name: Build Mac Catalyst app
+ steps:
+ - eas/checkout
+
+ - eas/install_node_modules
+
+ - run:
+ name: Install CocoaPods for Mac Catalyst
+ working_directory: ./ios
+ command: EXPO_ENABLE_MAC_CATALYST=1 pod install
+
+ - run:
+ name: Build Mac Catalyst app
+ command: |
+ set -euo pipefail
+
+ EXPO_ENABLE_MAC_CATALYST=1 xcodebuild \
+ -workspace ios/LayerzWallet.xcworkspace \
+ -scheme LayerzWallet \
+ -configuration Release \
+ -destination 'platform=macOS,variant=Mac Catalyst' \
+ -derivedDataPath ios/build \
+ CODE_SIGNING_ALLOWED=NO \
+ CODE_SIGNING_REQUIRED=NO \
+ COMPILER_INDEX_STORE_ENABLE=NO
+
+ - eas/find_and_upload_build_artifacts
\ No newline at end of file
diff --git a/mobile/app/_layout.tsx b/mobile/app/_layout.tsx
index 2020c083..2310956d 100644
--- a/mobile/app/_layout.tsx
+++ b/mobile/app/_layout.tsx
@@ -9,8 +9,7 @@ import 'react-native-reanimated';
import { SWRConfig } from 'swr';
import BigNumber from 'bignumber.js';
-import '../src/modules/breeze-adapter'; // needed to be imported before we can use BreezWallet
-import '../src/modules/spark-adapter'; // needed to be imported before we can use SparkWallet
+import { isMacCatalyst } from '@/src/utils/platform';
import AutoClaimMonitor from '@/components/AutoClaimMonitor';
import { ErrorBoundary } from '@/components/ErrorBoundary';
@@ -34,6 +33,13 @@ import { appendLog, applogFilePath, handleError } from '@/src/modules/error-hand
import { TransferFlowProvider } from '@/src/transfer/TransferFlowContext';
import { TransferExecution } from '@shared/types/transfer';
+if (isMacCatalyst) {
+ void import('../src/modules/unsupported-network-adapters');
+} else {
+ void import('../src/modules/breeze-adapter');
+ void import('../src/modules/spark-adapter');
+}
+
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
LogBox.ignoreLogs(['Require cycle:', 'Open debugger to view warnings.']);
diff --git a/mobile/components/ScanQrComponent.tsx b/mobile/components/ScanQrComponent.tsx
index e0d52620..d15f65f4 100644
--- a/mobile/components/ScanQrComponent.tsx
+++ b/mobile/components/ScanQrComponent.tsx
@@ -11,6 +11,7 @@ import GradientFormSheet from '@/components/GradientFormSheet';
import PlatformBlurView from '@/components/PlatformBlurView';
import { ThemedText } from '@/components/ThemedText';
import { ScanQrContext } from '@/src/hooks/ScanQrContext';
+import { isMacCatalyst } from '@/src/utils/platform';
import { NetworkContext } from '@shared/hooks/NetworkContext';
const styles = StyleSheet.create({
@@ -45,6 +46,12 @@ const styles = StyleSheet.create({
gestureHandlerRoot: {
flex: 1,
},
+ unsupportedWrapper: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ paddingHorizontal: 24,
+ },
});
// Memoized camera component to prevent re-renders during sheet interactions
@@ -142,6 +149,17 @@ export default function ScanQrComponent() {
}
const renderCameraContent = () => {
+ if (isMacCatalyst) {
+ return (
+
+ QR scanning is not supported in Mac Catalyst builds yet.
+
+ Close
+
+
+ );
+ }
+
if (!isCameraReady) {
// Camera is not ready yet
return (
diff --git a/mobile/eas.json b/mobile/eas.json
index f14a3857..b8b35f95 100644
--- a/mobile/eas.json
+++ b/mobile/eas.json
@@ -34,6 +34,15 @@
"developmentClient": true,
"distribution": "internal"
},
+ "mac-catalyst": {
+ "extends": "base",
+ "withoutCredentials": true,
+ "ios": {
+ "config": "mac-catalyst.yml",
+ "buildConfiguration": "Release",
+ "applicationArchivePath": "ios/build/Build/Products/Release-maccatalyst/LayerzWallet.app"
+ }
+ },
"production": {
"extends": "base",
"autoIncrement": true
diff --git a/mobile/package-lock.json b/mobile/package-lock.json
index 229918b2..0f528e74 100644
--- a/mobile/package-lock.json
+++ b/mobile/package-lock.json
@@ -337,6 +337,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz",
"integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.0",
@@ -1820,6 +1821,7 @@
"resolved": "https://registry.npmjs.org/@bugsnag/core/-/core-8.6.0.tgz",
"integrity": "sha512-94Jo443JegaiKV8z8NXMFdyTGubiUnwppWhq3kG2ldlYKtEvrmIaO5+JA58B6oveySvoRu3cCe2W9ysY7G7mDw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@bugsnag/cuid": "^3.0.0",
"@bugsnag/safe-json-stringify": "^6.0.0",
@@ -2140,21 +2142,21 @@
}
},
"node_modules/@emnapi/core": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz",
- "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
- "@emnapi/wasi-threads": "1.1.0",
+ "@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
- "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -2163,9 +2165,9 @@
}
},
"node_modules/@emnapi/wasi-threads": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
- "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -3634,6 +3636,7 @@
"resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-55.0.10.tgz",
"integrity": "sha512-7jdikExgIrCIF5e3P1qMwcUZ2tcxrNdVqE9Y8kNMUHqZ+ipMlin+SiZwJKHM1+am4CYGjhdyrzbnIpvEcLDYcg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@expo/dom-webview": "^55.0.5",
"anser": "^1.4.9",
@@ -5857,6 +5860,7 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0",
+ "peer": true,
"engines": {
"node": ">=8.0.0"
}
@@ -6277,6 +6281,7 @@
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
"integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"merge-options": "^3.0.4"
},
@@ -6311,27 +6316,25 @@
}
},
"node_modules/@react-native/babel-plugin-codegen": {
- "version": "0.85.1",
- "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.85.1.tgz",
- "integrity": "sha512-Klex4kTsRxoswZmo7EBXobvpg+HO6h7xeGo87CLXSKPq3qHlJ8ilpgtmzYCTK+Qr/0Mk3cz2zv3bA9VTXR+NDA==",
+ "version": "0.85.2",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.85.2.tgz",
+ "integrity": "sha512-5Dqn08kRTUIxPLYju9hExI0cR1ESX+P5tEv5yv0q0UZcisRTw0VB8iUWDIph2LdY1i5Dc8PIvuaWMRNCw3vnKg==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"@babel/traverse": "^7.29.0",
- "@react-native/codegen": "0.85.1"
+ "@react-native/codegen": "0.85.2"
},
"engines": {
"node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
}
},
"node_modules/@react-native/babel-plugin-codegen/node_modules/@react-native/codegen": {
- "version": "0.85.1",
- "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.85.1.tgz",
- "integrity": "sha512-Ge8F5VejnI7ng/NGObqBBovuLbItvmmZDFQ1Qwt/nBhHtk7l2tOffNMVNTta9Jt8TW0oXxVj6FG3hr6nx03JrQ==",
+ "version": "0.85.2",
+ "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.85.2.tgz",
+ "integrity": "sha512-XCginmxh0//++EXVOEJHBVZxHla294FzLCFF6jXwAUjvXVhqyIKyxhABfz+r4OOmaiuWk4Rtd4arqdAzeHeprg==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"@babel/core": "^7.25.2",
"@babel/parser": "^7.29.0",
@@ -6353,8 +6356,7 @@
"resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz",
"integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==",
"license": "MIT",
- "optional": true,
- "peer": true
+ "optional": true
},
"node_modules/@react-native/babel-plugin-codegen/node_modules/hermes-parser": {
"version": "0.33.3",
@@ -6362,18 +6364,16 @@
"integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"hermes-estree": "0.33.3"
}
},
"node_modules/@react-native/babel-preset": {
- "version": "0.85.1",
- "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.85.1.tgz",
- "integrity": "sha512-Mplsn13fCxQElOfWg6wIuXJP+tyO980etTQ1gQFTt5Zstj3rs33GzTLMNlo6EnT8PQghO3GxIrg/2im5GwodnA==",
+ "version": "0.85.2",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.85.2.tgz",
+ "integrity": "sha512-7d2yW23eKkVt0FbbnZLxqO7KybGLtQXOuvvcO1NUOYGtjzVh6ihNKn0TIHrhSNpMyHwYLDoiiuj95wLtcg3IwQ==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"@babel/core": "^7.25.2",
"@babel/plugin-proposal-export-default-from": "^7.24.7",
@@ -6404,7 +6404,7 @@
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/plugin-transform-typescript": "^7.25.2",
"@babel/plugin-transform-unicode-regex": "^7.24.7",
- "@react-native/babel-plugin-codegen": "0.85.1",
+ "@react-native/babel-plugin-codegen": "0.85.2",
"babel-plugin-syntax-hermes-parser": "0.33.3",
"babel-plugin-transform-flow-enums": "^0.0.2",
"react-refresh": "^0.14.0"
@@ -6422,7 +6422,6 @@
"integrity": "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"hermes-parser": "0.33.3"
}
@@ -6432,8 +6431,7 @@
"resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz",
"integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==",
"license": "MIT",
- "optional": true,
- "peer": true
+ "optional": true
},
"node_modules/@react-native/babel-preset/node_modules/hermes-parser": {
"version": "0.33.3",
@@ -6441,7 +6439,6 @@
"integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"hermes-estree": "0.33.3"
}
@@ -6594,15 +6591,14 @@
}
},
"node_modules/@react-native/metro-babel-transformer": {
- "version": "0.85.1",
- "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.85.1.tgz",
- "integrity": "sha512-oXAVv9GfGYxkqdf20o+gbJSw4yqaUZr7AZMZ4bJG8Nom/T9GmLu/Pd2kJo5U6NQYIndgfgU73pzRgL8H7YCIWw==",
+ "version": "0.85.2",
+ "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.85.2.tgz",
+ "integrity": "sha512-lU9XOGahpHvQff30H5lnvh9RYbVwC1zpSHpl84E+7BD2zj0FvW+pD7MBh7CWbmbWmegjtAb+U/2bokXcDVA+jA==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"@babel/core": "^7.25.2",
- "@react-native/babel-preset": "0.85.1",
+ "@react-native/babel-preset": "0.85.2",
"hermes-parser": "0.33.3",
"nullthrows": "^1.1.1"
},
@@ -6618,8 +6614,7 @@
"resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz",
"integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==",
"license": "MIT",
- "optional": true,
- "peer": true
+ "optional": true
},
"node_modules/@react-native/metro-babel-transformer/node_modules/hermes-parser": {
"version": "0.33.3",
@@ -6627,574 +6622,10 @@
"integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==",
"license": "MIT",
"optional": true,
- "peer": true,
"dependencies": {
"hermes-estree": "0.33.3"
}
},
- "node_modules/@react-native/metro-config": {
- "version": "0.85.1",
- "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.85.1.tgz",
- "integrity": "sha512-Na0OD2YFM7rESHJ3ETuYHnXNc5TJU/fpwlLmN2/uDTM9ZDb6EaEfFKZaXGbUm2lBYyeo/FG3Ur4glu8jLWMNgQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@react-native/js-polyfills": "0.85.1",
- "@react-native/metro-babel-transformer": "0.85.1",
- "metro-config": "^0.84.0",
- "metro-runtime": "^0.84.0"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/@react-native/js-polyfills": {
- "version": "0.85.1",
- "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.85.1.tgz",
- "integrity": "sha512-VseQZAKnDbmpZThLWviDIJ0NmuSiwiHA6vc2HNJTTVqTy2mQR0+858y9kDdDBQPYe0HH8+W1mYui2i4eUWGh4g==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/accepts": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
- "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "mime-types": "^3.0.0",
- "negotiator": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/agent-base": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
- "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/ci-info": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
- "license": "MIT",
- "optional": true,
- "peer": true
- },
- "node_modules/@react-native/metro-config/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "license": "MIT",
- "optional": true,
- "peer": true
- },
- "node_modules/@react-native/metro-config/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/hermes-estree": {
- "version": "0.35.0",
- "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz",
- "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==",
- "license": "MIT",
- "optional": true,
- "peer": true
- },
- "node_modules/@react-native/metro-config/node_modules/hermes-parser": {
- "version": "0.35.0",
- "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz",
- "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "hermes-estree": "0.35.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/https-proxy-agent": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
- "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "agent-base": "^7.1.2",
- "debug": "4"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.3.tgz",
- "integrity": "sha512-1h3lbVrE6hGf1e/764HfhPGg/bGrWMJDDh7G2rc4gFYZboVuI40BlG/y+UhtbhQDNlO/csMvrcnK0YrTlHUVew==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@babel/code-frame": "^7.29.0",
- "@babel/core": "^7.25.2",
- "@babel/generator": "^7.29.1",
- "@babel/parser": "^7.29.0",
- "@babel/template": "^7.28.6",
- "@babel/traverse": "^7.29.0",
- "@babel/types": "^7.29.0",
- "accepts": "^2.0.0",
- "chalk": "^4.0.0",
- "ci-info": "^2.0.0",
- "connect": "^3.6.5",
- "debug": "^4.4.0",
- "error-stack-parser": "^2.0.6",
- "flow-enums-runtime": "^0.0.6",
- "graceful-fs": "^4.2.4",
- "hermes-parser": "0.35.0",
- "image-size": "^1.0.2",
- "invariant": "^2.2.4",
- "jest-worker": "^29.7.0",
- "jsc-safe-url": "^0.2.2",
- "lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.84.3",
- "metro-cache": "0.84.3",
- "metro-cache-key": "0.84.3",
- "metro-config": "0.84.3",
- "metro-core": "0.84.3",
- "metro-file-map": "0.84.3",
- "metro-resolver": "0.84.3",
- "metro-runtime": "0.84.3",
- "metro-source-map": "0.84.3",
- "metro-symbolicate": "0.84.3",
- "metro-transform-plugins": "0.84.3",
- "metro-transform-worker": "0.84.3",
- "mime-types": "^3.0.1",
- "nullthrows": "^1.1.1",
- "serialize-error": "^2.1.0",
- "source-map": "^0.5.6",
- "throat": "^5.0.0",
- "ws": "^7.5.10",
- "yargs": "^17.6.2"
- },
- "bin": {
- "metro": "src/cli.js"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-babel-transformer": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.3.tgz",
- "integrity": "sha512-svAA+yMLpeMiGcz/jKJs4oHpIGEx4nBqNEJ5AGj4CYIg1efvK+A0TjR6tgIuc6tKO5e8JmN/1lglpN2+f3/z/w==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@babel/core": "^7.25.2",
- "flow-enums-runtime": "^0.0.6",
- "hermes-parser": "0.35.0",
- "metro-cache-key": "0.84.3",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-cache": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.3.tgz",
- "integrity": "sha512-0QElxwLaHqLZf+Xqio8QrjVbuXP/8sJfQBGSPiITlKDVXrVLefuzYVSH9Sj+QL6lrPj2gYZd/iwQh1yZuVKnLA==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "exponential-backoff": "^3.1.1",
- "flow-enums-runtime": "^0.0.6",
- "https-proxy-agent": "^7.0.5",
- "metro-core": "0.84.3"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-cache-key": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.3.tgz",
- "integrity": "sha512-TnSL1Fdvrw+2glTdBSRmA5TL8l/i16ECjsrUdf3E5HncA+sNx8KcwDG8r+3ct1UhfYcusJypzZqTN55FZZcwGg==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "flow-enums-runtime": "^0.0.6"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-config": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.3.tgz",
- "integrity": "sha512-JmCzZWOETR+O22q8oPBWyQppx3roU9EbkbGzD8Gf1jukQ4b5T1fTzqqHruu6K4sTiNq5zVQySmKF6bp4kVARew==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "connect": "^3.6.5",
- "flow-enums-runtime": "^0.0.6",
- "jest-validate": "^29.7.0",
- "metro": "0.84.3",
- "metro-cache": "0.84.3",
- "metro-core": "0.84.3",
- "metro-runtime": "0.84.3",
- "yaml": "^2.6.1"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-core": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.3.tgz",
- "integrity": "sha512-cc0pvAa80ai1nDmqqz0P59a+0ZqCZ/YHU/3jEekZL6spFnYDfX8iDLdn9FR6kX+67rmzKxHNrbrSRFLX2AYocw==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "flow-enums-runtime": "^0.0.6",
- "lodash.throttle": "^4.1.1",
- "metro-resolver": "0.84.3"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-file-map": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.3.tgz",
- "integrity": "sha512-1cL4m4Jv1yRUt9RJExZQLfccscdlMNOcRG6LHLtmJhf3BG9j3MujPVc7CIpKYdFl+KUl+sdjge6oO3+meKCHQA==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "debug": "^4.4.0",
- "fb-watchman": "^2.0.0",
- "flow-enums-runtime": "^0.0.6",
- "graceful-fs": "^4.2.4",
- "invariant": "^2.2.4",
- "jest-worker": "^29.7.0",
- "micromatch": "^4.0.4",
- "nullthrows": "^1.1.1",
- "walker": "^1.0.7"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-minify-terser": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.3.tgz",
- "integrity": "sha512-3ofrG2OQyJbO9RNhCfOcl8QU7EE2WrSsnN5dFkuZaJO5+4Imujr9bUXmspeNlXRsOVk0F/rVRbEFH98lFSCkBQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "flow-enums-runtime": "^0.0.6",
- "terser": "^5.15.0"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-resolver": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.3.tgz",
- "integrity": "sha512-pjEzGDtoM8DTHAIPK/9u9ZxszEiuRohYUVImWvgbnB91V4gqYJpQcoEYUugf2NIm1lrX5HNu0OvNqWmPBnGYjA==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "flow-enums-runtime": "^0.0.6"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-runtime": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.3.tgz",
- "integrity": "sha512-o7HLRfMyVk9N2dUZ9VjQfB6xxUItL9Pi9WcqxURE7MEKOH6wbGt9/E92YdYLluTOtkzYAEVfdC6h6lcxqA+hMQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@babel/runtime": "^7.25.0",
- "flow-enums-runtime": "^0.0.6"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-source-map": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.3.tgz",
- "integrity": "sha512-jS48CeSzw78M8y6VE0f9uy3lVmfbOS677j2VCxnlmlYmnahcXuC6IhoN9K6LynNvos9517yUadcfgioju38xYQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@babel/traverse": "^7.29.0",
- "@babel/types": "^7.29.0",
- "flow-enums-runtime": "^0.0.6",
- "invariant": "^2.2.4",
- "metro-symbolicate": "0.84.3",
- "nullthrows": "^1.1.1",
- "ob1": "0.84.3",
- "source-map": "^0.5.6",
- "vlq": "^1.0.0"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-symbolicate": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.3.tgz",
- "integrity": "sha512-J9Tpo8NCycYrozRvBIUyOwGAu4xkawOsAppmTscFiaegK0WvuDGwIM53GbzVSnytCHjVAF0io5GQxpkrKTuc7g==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "flow-enums-runtime": "^0.0.6",
- "invariant": "^2.2.4",
- "metro-source-map": "0.84.3",
- "nullthrows": "^1.1.1",
- "source-map": "^0.5.6",
- "vlq": "^1.0.0"
- },
- "bin": {
- "metro-symbolicate": "src/index.js"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-transform-plugins": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.3.tgz",
- "integrity": "sha512-8S3baq2XhBaafHEH5Q8sJW6tmzsEJk80qKc3RU/nZV1MsnYq94RdjTUR6AyKjQd6Rfsk1BtBxhtiNnk7mgslCg==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@babel/core": "^7.25.2",
- "@babel/generator": "^7.29.1",
- "@babel/template": "^7.28.6",
- "@babel/traverse": "^7.29.0",
- "flow-enums-runtime": "^0.0.6",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/metro-transform-worker": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.3.tgz",
- "integrity": "sha512-Wjba7PyYktNRsHbPmkx2J2UX32rAzcDXjCu49zPHeF/viJlYJhwRaNePQcHaCRqQ+kmgQT4ThprsnJfDj71ZMA==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@babel/core": "^7.25.2",
- "@babel/generator": "^7.29.1",
- "@babel/parser": "^7.29.0",
- "@babel/types": "^7.29.0",
- "flow-enums-runtime": "^0.0.6",
- "metro": "0.84.3",
- "metro-babel-transformer": "0.84.3",
- "metro-cache": "0.84.3",
- "metro-cache-key": "0.84.3",
- "metro-minify-terser": "0.84.3",
- "metro-source-map": "0.84.3",
- "metro-transform-plugins": "0.84.3",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/mime-db": {
- "version": "1.54.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
- "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/mime-types": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
- "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "mime-db": "^1.54.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/negotiator": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
- "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/ob1": {
- "version": "0.84.3",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.3.tgz",
- "integrity": "sha512-J7554Ef8bzmKaDY365Afq6PF+qtdnY/d5PKUQFrsKlZHV/N3OGZewVrvDrQDyX5V5NJjTpcAKtlrFZcDr+HvpQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "flow-enums-runtime": "^0.0.6"
- },
- "engines": {
- "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
- "license": "BSD-3-Clause",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@react-native/metro-config/node_modules/ws": {
- "version": "7.5.10",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
- "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8.3.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
"node_modules/@react-native/normalize-colors": {
"version": "0.83.4",
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.83.4.tgz",
@@ -7289,6 +6720,7 @@
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.2.2.tgz",
"integrity": "sha512-kem1Ko2BcbAjmbQIv66dNmr6EtfDut3QU0qjsVhMnLLhktwyXb6FzZYp8gTrUb6AvkAbaJoi+BF5Pl55pAUa5w==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@react-navigation/core": "^7.17.2",
"escape-string-regexp": "^4.0.0",
@@ -8353,6 +7785,7 @@
"integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
@@ -8515,6 +7948,7 @@
"integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -8618,6 +8052,7 @@
"integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.53.0",
"@typescript-eslint/types": "8.53.0",
@@ -9543,6 +8978,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -11268,6 +10704,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -13321,6 +12758,7 @@
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -13415,6 +12853,7 @@
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
@@ -13534,6 +12973,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -14144,6 +13584,7 @@
"resolved": "https://registry.npmjs.org/expo/-/expo-55.0.15.tgz",
"integrity": "sha512-sHIvqG477UU1jZHhaexXbUgsU7y+xnYZqDW1HrUkEBYiuEb5lobvWLmwea76EBVkityQx46UDtepFtarpUJQqQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/cli": "55.0.24",
@@ -14198,6 +13639,7 @@
"resolved": "https://registry.npmjs.org/expo-application/-/expo-application-55.0.14.tgz",
"integrity": "sha512-NgqDIt3eCf4aVLp1L6AcEanCYoyJeuBsGrgGSzOIvxAsOvp5X3SYKW3ROgpKUnLQEKMWlzwETpjsUGszcqkk8g==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"expo": "*"
}
@@ -14290,6 +13732,7 @@
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-55.0.14.tgz",
"integrity": "sha512-l23QVQCYBPKT5zbxxZdJeuhiunadvWdjcQ9+GC8h+02jCoLmWRk20064nCINnQTP3Hf+uLPteUiwYrJd0e446w==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@expo/config": "~55.0.15",
"@expo/env": "~2.1.1"
@@ -14304,6 +13747,7 @@
"resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-55.0.14.tgz",
"integrity": "sha512-TfAADBGZNNv9OOmdKFJCz54wDj87ufxtzQNSY+Roycpm8e5tuCnDIL7EjqUOmNTGH99Jj8ftPGFt4KGG2Ii2fg==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"expo": "*"
}
@@ -14364,6 +13808,7 @@
"resolved": "https://registry.npmjs.org/expo-device/-/expo-device-55.0.15.tgz",
"integrity": "sha512-vXy4U/IeYI+zHGG45Ap6J7EuyQmkstyo8I+/5YGr5q2zmqLBo6SWE62wii8i9hLHheHn6AtF9UPrSWAREJrE8A==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"ua-parser-js": "^0.7.33"
},
@@ -14402,6 +13847,7 @@
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-55.0.16.tgz",
"integrity": "sha512-EetQ/zVFK07Vmz4Yke0fvoES4xVwScTdd0PMoLekuMX7puE4op75pNnEdh1M0AeWzkqLrBoZIaU2ynSrKN5VZg==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"expo": "*",
"react-native": "*"
@@ -14412,6 +13858,7 @@
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-55.0.6.tgz",
"integrity": "sha512-x9czUA3UQWjIwa0ZUEs/eWJNqB4mAue/m4ltESlNPLZhHL0nWWqIfsyHmklTLFH7mVfcHSJvew6k+pR2FE1zVw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fontfaceobserver": "^2.1.0"
},
@@ -14493,6 +13940,7 @@
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-55.0.13.tgz",
"integrity": "sha512-xbOqNWQCC5RGtXSW83ZCKOjRivyxO2zBouRYy/hgbsyrHUJhztMAjlq8RKYDUL8D6QVsH9Q81SNoq4Zhcn+4HQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"expo-constants": "~55.0.14",
"invariant": "^2.2.4"
@@ -14899,6 +14347,7 @@
"resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-55.0.13.tgz",
"integrity": "sha512-I6r0JNO1Fd4o0Gu7Ixiic7s89lqgdUHq17uBH9y1f/AntoyKn71TdtYJH82RgfsBbu5qNVzrwImmvlANyOlITQ==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"expo": "*"
}
@@ -14908,6 +14357,7 @@
"resolved": "https://registry.npmjs.org/expo-server/-/expo-server-55.0.7.tgz",
"integrity": "sha512-Cc1btFyPsD9P4DT2xd1pG/uR96TLVMx0W+dPm9Gjk1uDV9xuzvMcUsY7nf9bt4U5pGyWWkCXmPJcKwWfdl51Pw==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=20.16.0"
}
@@ -15253,33 +14703,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/expo/node_modules/react-native-worklets": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.8.1.tgz",
- "integrity": "sha512-oWP/lStsAHU6oYCaWDXrda/wOHVdhusQJz1e6x9gPnXdFf4ndNDAOtWCmk2zGrAnlapfyA3rM6PCQq94mPg9cw==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@babel/plugin-transform-arrow-functions": "^7.27.1",
- "@babel/plugin-transform-class-properties": "^7.27.1",
- "@babel/plugin-transform-classes": "^7.28.4",
- "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1",
- "@babel/plugin-transform-optional-chaining": "^7.27.1",
- "@babel/plugin-transform-shorthand-properties": "^7.27.1",
- "@babel/plugin-transform-template-literals": "^7.27.1",
- "@babel/plugin-transform-unicode-regex": "^7.27.1",
- "@babel/preset-typescript": "^7.27.1",
- "convert-source-map": "^2.0.0",
- "semver": "^7.7.3"
- },
- "peerDependencies": {
- "@babel/core": "*",
- "@react-native/metro-config": "*",
- "react": "*",
- "react-native": "0.81 - 0.85"
- }
- },
"node_modules/expo/node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
@@ -15985,6 +15408,7 @@
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz",
"integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
}
@@ -17213,6 +16637,7 @@
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@@ -21850,6 +21275,7 @@
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -21943,6 +21369,7 @@
"resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
"integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"asap": "~2.0.6"
}
@@ -22349,6 +21776,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -22389,6 +21817,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -22431,6 +21860,7 @@
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.83.4.tgz",
"integrity": "sha512-H5Wco3UJyY6zZsjoBayY8RM9uiAEQ3FeG4G2NAt+lr9DO43QeqPlVe9xxxYEukMkEmeIhNjR70F6bhXuWArOMQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.83.4",
@@ -22489,6 +21919,7 @@
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.30.0.tgz",
"integrity": "sha512-5YsnKHGa0X9C8lb5oCnKm0fLUPM6CRduvUUw2Bav4RIj/C3HcFh4RIUnF8wgG6JQWCL1//gRx4v+LVWgcIQdGA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
@@ -22504,6 +21935,7 @@
"resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz",
"integrity": "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-base64-decode": "^1.0.0"
},
@@ -22526,6 +21958,7 @@
"resolved": "https://registry.npmjs.org/react-native-nitro-modules/-/react-native-nitro-modules-0.35.4.tgz",
"integrity": "sha512-4qZa+1kgR/sPRNZv+UShxyArEPpovWxw76Dfd/DtCVtkQ92wOOxGIzdYvndprabd+t+r8zNYgYEPYE74gzkuVQ==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -22552,6 +21985,7 @@
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.2.1.tgz",
"integrity": "sha512-/NcHnZMyOvsD/wYXug/YqSKw90P9edN0kEPL5lP4PFf1aQ4F1V7MKe/E0tvfkXKIajy3Qocp5EiEnlcrK/+BZg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"react-native-is-edge-to-edge": "1.2.1",
"semver": "7.7.3"
@@ -22591,6 +22025,7 @@
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -22601,6 +22036,7 @@
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.23.0.tgz",
"integrity": "sha512-XhO3aK0UeLpBn4kLecd+J+EDeRRJlI/Ro9Fze06vo1q163VeYtzfU9QS09/VyDFMWR1qxDC1iazCArTPSFFiPw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"react-freeze": "^1.0.0",
"warn-once": "^0.1.0"
@@ -22615,6 +22051,7 @@
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.3.tgz",
"integrity": "sha512-/k4KYwPBLGcx2f5d4FjE+vCScK7QOX14cl2lIASJ28u4slHHtIhL0SZKU7u9qmRBHxTCKPoPBtN6haT1NENJNA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3",
@@ -22652,6 +22089,7 @@
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
"integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.6",
"@react-native/normalize-colors": "^0.74.1",
@@ -22684,6 +22122,7 @@
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.16.0.tgz",
"integrity": "sha512-Nh13xKZWW35C0dbOskD7OX01nQQavOzHbCw9XoZmar4eXCo7AvrYJ0jlUfRVVIJzqINxHlpECYLdmAdFsl9xDA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"escape-string-regexp": "^4.0.0",
"invariant": "2.2.4"
@@ -22868,6 +22307,7 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -23655,6 +23095,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -25636,6 +25077,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -26311,6 +25753,7 @@
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@@ -26575,6 +26018,7 @@
"integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6",
@@ -26623,6 +26067,7 @@
"integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@discoveryjs/json-ext": "^0.6.1",
"@webpack-cli/configtest": "^3.0.1",
@@ -26995,6 +26440,7 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=10.0.0"
},
diff --git a/mobile/package.json b/mobile/package.json
index f520efdb..ff2ddba0 100644
--- a/mobile/package.json
+++ b/mobile/package.json
@@ -27,6 +27,10 @@
"start": "expo start",
"android": "expo run:android",
"ios": "expo run:ios",
+ "mac:pods": "cd ios && EXPO_ENABLE_MAC_CATALYST=1 pod install",
+ "mac": "npm run mac:pods && EXPO_ENABLE_MAC_CATALYST=1 xcodebuild -workspace ios/LayerzWallet.xcworkspace -scheme LayerzWallet -configuration Debug -destination 'platform=macOS,variant=Mac Catalyst' -derivedDataPath ios/build CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO COMPILER_INDEX_STORE_ENABLE=NO",
+ "mac:release": "npm run mac:pods && EXPO_ENABLE_MAC_CATALYST=1 xcodebuild -workspace ios/LayerzWallet.xcworkspace -scheme LayerzWallet -configuration Release -destination 'platform=macOS,variant=Mac Catalyst' -derivedDataPath ios/build CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO COMPILER_INDEX_STORE_ENABLE=NO",
+ "mac:eas:local": "eas build --platform ios --profile mac-catalyst --local",
"web": "expo start --web",
"test": "jest --watchAll",
"e2e": "maestro test .maestro/*",
diff --git a/mobile/patches/expo-camera+55.0.15.patch b/mobile/patches/expo-camera+55.0.15.patch
new file mode 100644
index 00000000..6956b692
--- /dev/null
+++ b/mobile/patches/expo-camera+55.0.15.patch
@@ -0,0 +1,127 @@
+diff --git a/node_modules/expo-camera/ios/CameraViewModule.swift b/node_modules/expo-camera/ios/CameraViewModule.swift
+index 1291830..39b4810 100644
+--- a/node_modules/expo-camera/ios/CameraViewModule.swift
++++ b/node_modules/expo-camera/ios/CameraViewModule.swift
+@@ -2,7 +2,9 @@
+
+ import AVFoundation
+ import ExpoModulesCore
++#if !targetEnvironment(macCatalyst)
+ import VisionKit
++#endif
+
+ let cameraEvents = ["onCameraReady", "onMountError", "onPictureSaved", "onBarcodeScanned", "onResponsiveOrientationChanged", "onAvailableLensesChanged"]
+
+@@ -31,10 +33,14 @@ public final class CameraViewModule: Module, ScannerResultHandler {
+ }
+
+ Property("isModernBarcodeScannerAvailable") { () -> Bool in
++#if targetEnvironment(macCatalyst)
++ return false
++#else
+ if #available(iOS 16.0, *) {
+ return true
+ }
+ return false
++#endif
+ }
+
+ Property("toggleRecordingAsyncAvailable") { () -> Bool in
+@@ -339,6 +345,9 @@ public final class CameraViewModule: Module, ScannerResultHandler {
+ }
+
+ AsyncFunction("launchScanner") { (options: VisionScannerOptions?) in
++#if targetEnvironment(macCatalyst)
++ throw CameraScannerUnavailableException()
++#else
+ if #available(iOS 16.0, *) {
+ try await MainActor.run {
+ guard DataScannerViewController.isSupported, DataScannerViewController.isAvailable else {
+@@ -349,14 +358,17 @@ public final class CameraViewModule: Module, ScannerResultHandler {
+ launchScanner(with: options)
+ }
+ }
++#endif
+ }
+
+ AsyncFunction("dismissScanner") {
++#if !targetEnvironment(macCatalyst)
+ if #available(iOS 16.0, *) {
+ await MainActor.run {
+ dismissScanner()
+ }
+ }
++#endif
+ }
+
+ AsyncFunction("getCameraPermissionsAsync") { (promise: Promise) in
+@@ -400,6 +412,7 @@ public final class CameraViewModule: Module, ScannerResultHandler {
+ }
+ }
+
++ #if !targetEnvironment(macCatalyst)
+ @available(iOS 16.0, *)
+ @MainActor
+ private func launchScanner(with options: VisionScannerOptions?) {
+@@ -430,6 +443,7 @@ public final class CameraViewModule: Module, ScannerResultHandler {
+ controller.stopScanning()
+ controller.dismiss(animated: true)
+ }
++ #endif
+
+ func onItemScanned(result: [String: Any]) {
+ sendEvent("onModernBarcodeScanned", result)
+diff --git a/node_modules/expo-camera/ios/Current/BarcodeScannerUtils.swift b/node_modules/expo-camera/ios/Current/BarcodeScannerUtils.swift
+index 5f18d96..87d098f 100644
+--- a/node_modules/expo-camera/ios/Current/BarcodeScannerUtils.swift
++++ b/node_modules/expo-camera/ios/Current/BarcodeScannerUtils.swift
+@@ -2,8 +2,10 @@ import AVFoundation
+ #if canImport(ZXingObjC)
+ import ZXingObjC
+ #endif
++#if !targetEnvironment(macCatalyst)
+ import VisionKit
+ import Vision
++#endif
+
+ class BarcodeScannerUtils {
+ static func getDefaultSettings() -> [String: [AVMetadataObject.ObjectType]] {
+@@ -66,6 +68,7 @@ class BarcodeScannerUtils {
+ return result
+ }
+
++ #if !targetEnvironment(macCatalyst)
+ @available(iOS 16.0, *)
+ static func visionDataScannerObjectToDictionary(item: RecognizedItem.Barcode) -> [String: Any] {
+ var result = [String: Any]()
+@@ -90,6 +93,7 @@ class BarcodeScannerUtils {
+
+ return result
+ }
++ #endif
+
+ static func addEmptyCornerPoints(to result: inout [String: Any]) {
+ result["cornerPoints"] = []
+diff --git a/node_modules/expo-camera/ios/Current/VisionScannerDelegate.swift b/node_modules/expo-camera/ios/Current/VisionScannerDelegate.swift
+index e50439a..e217b6d 100644
+--- a/node_modules/expo-camera/ios/Current/VisionScannerDelegate.swift
++++ b/node_modules/expo-camera/ios/Current/VisionScannerDelegate.swift
+@@ -1,10 +1,12 @@
+-import VisionKit
+ import ExpoModulesCore
+
+ protocol ScannerResultHandler {
+ func onItemScanned(result: [String: Any])
+ }
+
++#if !targetEnvironment(macCatalyst)
++import VisionKit
++
+ @available(iOS 16.0, *)
+ class VisionScannerDelegate: NSObject, DataScannerViewControllerDelegate {
+ private let handler: ScannerResultHandler
+@@ -27,3 +29,4 @@ class VisionScannerDelegate: NSObject, DataScannerViewControllerDelegate {
+ }
+ }
+ }
++#endif
diff --git a/mobile/react-native.config.js b/mobile/react-native.config.js
new file mode 100644
index 00000000..d9f30a73
--- /dev/null
+++ b/mobile/react-native.config.js
@@ -0,0 +1,18 @@
+const isMacCatalystBuild = process.env.EXPO_ENABLE_MAC_CATALYST === '1';
+
+module.exports = {
+ dependencies: isMacCatalystBuild
+ ? {
+ '@breeztech/breez-sdk-liquid-react-native': {
+ platforms: {
+ ios: null,
+ },
+ },
+ '@buildonspark/spark-sdk': {
+ platforms: {
+ ios: null,
+ },
+ },
+ }
+ : {},
+};
diff --git a/mobile/src/hooks/ScanQrContext.tsx b/mobile/src/hooks/ScanQrContext.tsx
index eb06f227..6133755c 100644
--- a/mobile/src/hooks/ScanQrContext.tsx
+++ b/mobile/src/hooks/ScanQrContext.tsx
@@ -2,6 +2,7 @@ import React, { createContext, ReactNode, useState, useRef } from 'react';
import { useRouter } from 'expo-router';
import { useCameraPermissions } from 'expo-camera';
import { Alert } from 'react-native';
+import { isMacCatalyst } from '@/src/utils/platform';
interface IScanQrContext {
scanQr: () => Promise;
@@ -36,6 +37,12 @@ export const ScanQrContextProvider: React.FC<{ children: ReactNode }> = (props)
// Check and request camera permissions before showing the scanner
try {
+ if (isMacCatalyst) {
+ Alert.alert('Camera Unsupported', 'QR scanning is not supported in Mac Catalyst builds yet.', [{ text: 'OK' }]);
+ resolve('');
+ return;
+ }
+
if (!permission) {
// Permissions are still loading
console.debug('ScanQr: Camera permissions loading...');
diff --git a/mobile/src/modules/scan-routing.ts b/mobile/src/modules/scan-routing.ts
index fd7093d2..4fbd49f4 100644
--- a/mobile/src/modules/scan-routing.ts
+++ b/mobile/src/modules/scan-routing.ts
@@ -173,10 +173,7 @@ export async function handleQrIntent(rawInput: string, router: Pick new Error(`${networkName} is not supported in Mac Catalyst builds yet.`);
+
+const unsupportedBreezAdapter: IBreezAdapter = {
+ api: {
+ getInfo: async () => {
+ throw unsupportedError('Liquid');
+ },
+ fetchLightningLimits: async () => {
+ throw unsupportedError('Liquid');
+ },
+ prepareReceivePayment: async () => {
+ throw unsupportedError('Liquid');
+ },
+ receivePayment: async () => {
+ throw unsupportedError('Liquid');
+ },
+ prepareSendPayment: async () => {
+ throw unsupportedError('Liquid');
+ },
+ sendPayment: async () => {
+ throw unsupportedError('Liquid');
+ },
+ getPayment: async () => {
+ throw unsupportedError('Liquid');
+ },
+ listPayments: async () => {
+ throw unsupportedError('Liquid');
+ },
+ },
+};
+
+const unsupportedSparkAdapter: ISparkAdapter = {
+ initialize: async () => {
+ throw unsupportedError('Spark');
+ },
+};
+
+global.breezAdapter = unsupportedBreezAdapter;
+global.sparkAdapter = unsupportedSparkAdapter;
diff --git a/mobile/src/utils/platform.ts b/mobile/src/utils/platform.ts
index eb58d934..4caddab7 100644
--- a/mobile/src/utils/platform.ts
+++ b/mobile/src/utils/platform.ts
@@ -1,3 +1,4 @@
import { Platform } from 'react-native';
export const isIOS26OrNewer = Platform.OS === 'ios' && (typeof Platform.Version === 'string' ? parseInt(String(Platform.Version), 10) : Number(Platform.Version)) >= 26;
+export const isMacCatalyst = Platform.OS === 'ios' && Boolean((Platform as typeof Platform & { isMacCatalyst?: boolean }).isMacCatalyst);
diff --git a/tasks/todo.md b/tasks/todo.md
new file mode 100644
index 00000000..6f593a0c
--- /dev/null
+++ b/tasks/todo.md
@@ -0,0 +1,16 @@
+# Mac Build Enablement
+
+- [x] Enable Mac Catalyst support in the iOS native project and Podfile.
+- [x] Add local commands for Mac Catalyst builds.
+- [x] Add an EAS custom build profile for Mac Catalyst artifacts.
+- [x] Document local and EAS usage.
+- [x] Validate the native configuration and build path.
+- [x] Patch ExpoCamera for Mac Catalyst and confirm the app launches locally.
+
+## Review
+
+- `EXPO_ENABLE_MAC_CATALYST=1 pod install` completes successfully after excluding the Breez Liquid native module from Mac Catalyst autolinking.
+- A clean local `npm run mac` now finishes with `EXIT:0` and emits a launchable app bundle at `mobile/ios/build/Build/Products/Debug-maccatalyst/LayerzWallet.app`.
+- The built bundle now contains `Contents/MacOS/LayerzWallet`, and `open mobile/ios/build/Build/Products/Debug-maccatalyst/LayerzWallet.app` starts the app process successfully.
+- Spark and Breez are stubbed out for Mac Catalyst so the app can boot without those unsupported native SDKs.
+- ExpoCamera is patched so Catalyst builds compile without Vision/DataScanner APIs, and the QR scanner flow now exits with an explicit unsupported message on Mac Catalyst.
\ No newline at end of file