From 4a17c7942d32205402ebcbec08d80e2579f6aa09 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Tue, 12 May 2026 19:57:53 +0200 Subject: [PATCH] fix(rebreak-native): don't crash on old dev-clients missing ExpoLocalAuthentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit appLock.ts is imported from the root layout, so an unguarded top-level `import * as LocalAuthentication from 'expo-local-authentication'` crashes the whole app at launch on a dev-client built before the dependency was added ("Cannot find native module 'ExpoLocalAuthentication'"). Load it via a guarded require; if absent → app lock reports `available: false`, everything else runs. Real builds (EAS / fresh prebuild) ship the module and work normally. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/rebreak-native/stores/appLock.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/rebreak-native/stores/appLock.ts b/apps/rebreak-native/stores/appLock.ts index eadcd4b..29a1433 100644 --- a/apps/rebreak-native/stores/appLock.ts +++ b/apps/rebreak-native/stores/appLock.ts @@ -1,6 +1,21 @@ import { create } from 'zustand'; import AsyncStorage from '@react-native-async-storage/async-storage'; -import * as LocalAuthentication from 'expo-local-authentication'; + +// expo-local-authentication ist ein NATIVE-Modul. In einem Dev-Client, der noch +// VOR dem Hinzufügen dieser Dependency gebaut wurde, fehlt der native Teil → +// `require()` wirft "Cannot find native module 'ExpoLocalAuthentication'" und +// würde die ganze App beim Start crashen (appLock wird im RootLayout importiert). +// Daher: defensiv laden. Fehlt das Modul → App-Sperre einfach „nicht verfügbar", +// der Rest der App läuft normal weiter. In jedem echten Build (EAS / frischer +// `expo prebuild`) ist das Modul drin und alles funktioniert. +type LocalAuthModule = typeof import('expo-local-authentication'); +let LocalAuthentication: LocalAuthModule | null = null; +try { + // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require + LocalAuthentication = require('expo-local-authentication') as LocalAuthModule; +} catch { + LocalAuthentication = null; +} /** * App-Sperre (Face ID / Touch ID). @@ -47,6 +62,11 @@ export const useAppLockStore = create((set, get) => ({ ready: false, init: async () => { + if (!LocalAuthentication) { + // Native-Modul fehlt (alter Dev-Client) → Sperre nicht verfügbar, App läuft weiter. + set({ enabled: false, available: false, locked: false, ready: true }); + return; + } const [storedRaw, hasHardware, isEnrolled] = await Promise.all([ AsyncStorage.getItem(STORAGE_KEY), LocalAuthentication.hasHardwareAsync(), @@ -76,6 +96,7 @@ export const useAppLockStore = create((set, get) => ({ }, authenticate: async (promptMessage) => { + if (!LocalAuthentication) return false; const result = await LocalAuthentication.authenticateAsync({ promptMessage: promptMessage ?? DEFAULT_PROMPT, // Geräte-Passcode als Fallback erlauben (Face ID schlägt 3x fehl → Passcode).