From 2c63dcfd75d9a6dcf26c096ec1bebb83a835119a Mon Sep 17 00:00:00 2001 From: Space-Banane Date: Wed, 24 Jun 2026 21:47:44 +0200 Subject: [PATCH] fix: guard expo-notifications against Expo Go crash on import SDK 53+ removed push notification support from Expo Go, causing the module to throw at require-time. The static import in notifications.ts propagated the error to _layout.tsx and both tab screens, making expo- router report missing default exports and crash the app. Switch to a try/catch require() so the module initialises safely in Expo Go (Notifications stays null, all functions become no-ops) while still working correctly in EAS / development builds. Co-Authored-By: Claude Sonnet 4.6 --- lib/notifications.ts | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/notifications.ts b/lib/notifications.ts index ae68127..82dcfd6 100644 --- a/lib/notifications.ts +++ b/lib/notifications.ts @@ -1,4 +1,4 @@ -import * as Notifications from "expo-notifications"; +import type * as NotificationsType from "expo-notifications"; import { loadNotifSettings, loadNotifThresholdLastFired, @@ -7,22 +7,32 @@ import { import type { ClaudeUsageResponse } from "@/types/claude"; import type { CodexUsageResponse } from "@/types/codex"; -Notifications.setNotificationHandler({ - handleNotification: async () => ({ - shouldShowAlert: true, - shouldShowBanner: true, - shouldShowList: true, - shouldPlaySound: false, - shouldSetBadge: false, - }), -}); +// expo-notifications push notifications were removed from Expo Go in SDK 53. +// Use require() so the initialization error is caught gracefully in Expo Go. +let Notifications: typeof NotificationsType | null = null; +try { + Notifications = require("expo-notifications") as typeof NotificationsType; + Notifications.setNotificationHandler({ + handleNotification: async () => ({ + shouldShowAlert: true, + shouldShowBanner: true, + shouldShowList: true, + shouldPlaySound: false, + shouldSetBadge: false, + }), + }); +} catch { + // Running in Expo Go or native module unavailable — notifications disabled. +} export async function requestPermissions(): Promise { + if (!Notifications) return false; const { status } = await Notifications.requestPermissionsAsync(); return status === "granted"; } export async function getPermissionStatus(): Promise { + if (!Notifications) return "undetermined"; const { status } = await Notifications.getPermissionsAsync(); return status; } @@ -35,6 +45,7 @@ export async function scheduleDailyDigest( claudeUsage: ClaudeUsageResponse | null, codexUsage: CodexUsageResponse | null ): Promise { + if (!Notifications) return; try { await Notifications.cancelScheduledNotificationAsync(DAILY_ID); } catch {} @@ -68,6 +79,7 @@ export async function scheduleDailyDigest( } export async function cancelDailyDigest(): Promise { + if (!Notifications) return; try { await Notifications.cancelScheduledNotificationAsync(DAILY_ID); } catch {} @@ -128,7 +140,7 @@ export async function onUsageDataLoaded( claudeUsage, codexUsage ); - if (alerts.length > 0) { + if (alerts.length > 0 && Notifications) { await Notifications.scheduleNotificationAsync({ content: { title: "Low quota warning",