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