feat(mobile): notification (#3424)

* init messaging

* use expo-notifications plugin

* unread badge

* background fetch

* update

* skip for no user

* cache messaging token

* navigate to entry

* get entry without prefetch

* update channel

* update channel for web and desktop

* remove useless dep

* check user in task

* messaging as hook

* fix condition

* rename
This commit is contained in:
Stephen Zhou 2025-04-08 10:45:11 +08:00 committed by GitHub
parent 3bbe28086a
commit 16be7cd868
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 361 additions and 13 deletions

View File

@ -1,6 +1,7 @@
import type { Credentials } from "@eneris/push-receiver/dist/types"
import type { UserModel } from "@follow/models"
import { isLinux, isMacOS, isWindows } from "~/env"
import { logger } from "~/logger"
import { apiClient } from "./api-client"
@ -30,7 +31,7 @@ export const updateNotificationsToken = async (newCredentials?: Credentials) =>
await apiClient.messaging.$post({
json: {
token: credentials.fcm.token,
channel: "desktop",
channel: isMacOS ? "macos" : isWindows ? "windows" : isLinux ? "linux" : "desktop",
},
})
} catch (error) {

View File

@ -37,7 +37,7 @@ export async function registerWebPushNotifications() {
await apiClient.messaging.$post({
json: {
token,
channel: "desktop",
channel: "web",
},
})

View File

@ -154,6 +154,12 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
},
],
"react-native-video",
[
"expo-notifications",
{
enableBackgroundRemoteNotifications: true,
},
],
],
experiments: {
typedRoutes: true,

View File

@ -37,6 +37,7 @@
"@react-native-firebase/app": "21.13.0",
"@react-native-firebase/app-check": "21.13.0",
"@react-native-firebase/crashlytics": "21.13.0",
"@react-native-firebase/messaging": "21.13.0",
"@react-native-menu/menu": "1.2.3",
"@react-native-picker/picker": "2.11.0",
"@shopify/flash-list": "1.7.3",
@ -53,6 +54,7 @@
"expo-apple-authentication": "7.1.3",
"expo-application": "6.0.2",
"expo-av": "15.0.2",
"expo-background-fetch": "13.0.6",
"expo-blur": "14.0.3",
"expo-build-properties": "0.13.2",
"expo-clipboard": "7.0.1",
@ -68,6 +70,7 @@
"expo-linking": "7.0.5",
"expo-localization": "16.0.1",
"expo-media-library": "17.0.6",
"expo-notifications": "0.29.14",
"expo-secure-store": "14.0.1",
"expo-sharing": "13.0.1",
"expo-splash-screen": "0.29.22",
@ -75,6 +78,7 @@
"expo-status-bar": "2.0.1",
"expo-symbols": "0.2.2",
"expo-system-ui": "4.0.9",
"expo-task-manager": "12.0.6",
"expo-updates": "0.27.4",
"expo-web-browser": "14.0.2",
"hono": "4.7.5",

View File

@ -6,11 +6,20 @@ import { useSheet } from "react-native-sheet-transitions"
import { useIntentHandler } from "./hooks/useIntentHandler"
import { DebugButton, EnvProfileIndicator } from "./modules/debug"
import { usePrefetchActions } from "./store/action/hooks"
import { useMessaging, useUpdateMessagingToken } from "./store/messaging/hooks"
import { useUnreadCountBadge } from "./store/unread/hooks"
import { useOnboarding, usePrefetchSessionUser } from "./store/user/hooks"
export function App({ children }: { children: React.ReactNode }) {
useIntentHandler()
useOnboarding()
useUnreadCountBadge()
// prefetch actions to detect if the user has any actions contains notifications
usePrefetchActions()
useUpdateMessagingToken()
useMessaging()
const { scale } = useSheet()
const style = useAnimatedStyle(() => ({

View File

@ -0,0 +1,32 @@
import * as BackgroundFetch from "expo-background-fetch"
import * as TaskManager from "expo-task-manager"
import { unreadSyncService } from "../store/unread/store"
import { whoami } from "../store/user/getters"
const BACKGROUND_FETCH_TASK = "background-fetch"
export async function initBackgroundFetch() {
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
// const now = Date.now()
// console.log(`Got background fetch call at date: ${new Date(now).toISOString()}`)
const user = whoami()
if (!user) {
return BackgroundFetch.BackgroundFetchResult.NoData
}
try {
const res = await unreadSyncService.updateBadgeAtBackground()
return res
? BackgroundFetch.BackgroundFetchResult.NewData
: BackgroundFetch.BackgroundFetchResult.NoData
} catch (err) {
console.error(err)
return BackgroundFetch.BackgroundFetchResult.Failed
}
})
return BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 60 * 15, // 15 minutes
})
}

View File

@ -5,6 +5,7 @@ import { initializeDb } from "../database"
import { settingSyncQueue } from "../modules/settings/sync-queue"
import { initAnalytics } from "./analytics"
import { initializeAppCheck } from "./app-check"
import { initBackgroundFetch } from "./background"
import { initCrashlytics } from "./crashlytics"
import { initializeDayjs } from "./dayjs"
import { hydrateDatabaseToStore, hydrateQueryClient, hydrateSettings } from "./hydrate"
@ -46,6 +47,7 @@ export const initializeApp = async () => {
using_indexed_db: true,
})
initCrashlytics()
initBackgroundFetch()
console.log(`Initialize done,`, `${loadingTime}ms`)
}

View File

@ -0,0 +1,35 @@
import * as Notifications from "expo-notifications"
import { Platform } from "react-native"
import { toast } from "./toast"
export async function requestNotificationPermission() {
if (Platform.OS === "android") {
Notifications.setNotificationChannelAsync("default", {
name: "default",
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
})
}
const { status: existingStatus } = await Notifications.getPermissionsAsync()
let finalStatus = existingStatus
if (existingStatus !== "granted") {
const { status } = await Notifications.requestPermissionsAsync()
finalStatus = status
}
if (finalStatus !== "granted") {
toast.error("Permission not granted for notification!")
return false
}
return true
}
export async function setBadgeCountAsyncWithPermission(badgeCount: number) {
const permissionGranted = await requestNotificationPermission()
if (!permissionGranted) {
return false
}
return await Notifications.setBadgeCountAsync(badgeCount)
}

View File

@ -14,7 +14,7 @@ import { openLink } from "@/src/lib/native"
import type { NavigationControllerView } from "@/src/lib/navigation/types"
import { EntryContentContext, useEntryContentContext } from "@/src/modules/entry-content/ctx"
import { EntryAISummary } from "@/src/modules/entry-content/EntryAISummary"
import { useEntry, usePrefetchEntryContent } from "@/src/store/entry/hooks"
import { useEntry, usePrefetchEntryDetail } from "@/src/store/entry/hooks"
import { entrySyncServices } from "@/src/store/entry/store"
import type { EntryWithTranslation } from "@/src/store/entry/types"
import { useFeed } from "@/src/store/feed/hooks"
@ -27,7 +27,7 @@ export const EntryDetailScreen: NavigationControllerView<{
entryId: string
view: FeedViewType
}> = ({ entryId, view: viewType }) => {
usePrefetchEntryContent(entryId)
usePrefetchEntryDetail(entryId)
useAutoMarkAsRead(entryId)
const entry = useEntry(entryId)
const translation = useEntryTranslation(entryId)

View File

@ -64,3 +64,9 @@ export function useActionRuleCondition({
export const useIsActionDataDirty = () => {
return useActionStore((state) => state.isDirty)
}
export const useHasNotificationActions = () => {
return useActionStore((state) => {
return state.rules.some((rule) => !!rule.result.newEntryNotification && !rule.result.disabled)
})
}

View File

@ -22,10 +22,10 @@ export const usePrefetchEntries = (props: Omit<FetchEntriesProps, "pageParam" |
enabled: !!props,
})
}
export const usePrefetchEntryContent = (entryId: string) => {
export const usePrefetchEntryDetail = (entryId: string) => {
return useQuery({
queryKey: ["entry", entryId],
queryFn: () => entrySyncServices.fetchEntryContent(entryId),
queryFn: () => entrySyncServices.fetchEntryDetail(entryId),
})
}

View File

@ -426,13 +426,15 @@ class EntrySyncServices {
return res
}
async fetchEntryContent(entryId: EntryId) {
async fetchEntryDetail(entryId: EntryId) {
const currentEntry = getEntry(entryId)
const res = currentEntry?.inboxHandle
? await apiClient.entries.inbox.$get({ query: { id: entryId } })
: await apiClient.entries.$get({ query: { id: entryId } })
const entry = honoMorph.toEntry(res.data)
if (entry?.content && currentEntry?.content !== entry.content) {
if (!currentEntry && entry) {
await entryActions.upsertMany([entry])
} else if (entry?.content && currentEntry?.content !== entry.content) {
await entryActions.updateEntryContent({ entryId, content: entry.content })
}
return entry

View File

@ -0,0 +1,83 @@
import type { FirebaseMessagingTypes } from "@react-native-firebase/messaging"
import messaging from "@react-native-firebase/messaging"
import { useMutation } from "@tanstack/react-query"
import { useEffect } from "react"
import { Platform } from "react-native"
import { apiClient } from "@/src/lib/api-fetch"
import { kv } from "@/src/lib/kv"
import { useNavigation } from "@/src/lib/navigation/hooks"
import { requestNotificationPermission } from "@/src/lib/permission"
import { EntryDetailScreen } from "@/src/screens/(stack)/entries/[entryId]"
import { useHasNotificationActions } from "../action/hooks"
import { useWhoami } from "../user/hooks"
const FIREBASE_MESSAGING_TOKEN_STORAGE_KEY = "firebase_messaging_token"
async function saveMessagingToken() {
const token = await messaging().getToken()
const storedToken = await kv.get(FIREBASE_MESSAGING_TOKEN_STORAGE_KEY)
if (storedToken === token) {
return
}
await apiClient.messaging.$post({
json: {
token,
channel: Platform.OS,
},
})
kv.set(FIREBASE_MESSAGING_TOKEN_STORAGE_KEY, token)
}
export function useUpdateMessagingToken() {
const whoami = useWhoami()
const hasNotificationActions = useHasNotificationActions()
const { mutate } = useMutation({
mutationFn: async () => {
return Promise.all([saveMessagingToken(), requestNotificationPermission()])
},
})
useEffect(() => {
if (!whoami?.id || !hasNotificationActions) return
mutate()
}, [hasNotificationActions, mutate, whoami?.id])
}
export function useMessaging() {
const navigation = useNavigation()
useEffect(() => {
function navigateToEntry(message: FirebaseMessagingTypes.RemoteMessage) {
if (
!message.data ||
typeof message.data.view !== "string" ||
typeof message.data.entryId !== "string"
) {
return
}
navigation.pushControllerView(EntryDetailScreen, {
entryId: message.data.entryId,
view: Number.parseInt(message.data.view),
})
}
async function init() {
const message = await messaging().getInitialNotification()
if (message) {
navigateToEntry(message)
}
}
init()
const unsubscribe = messaging().onNotificationOpenedApp((remoteMessage) => {
navigateToEntry(remoteMessage)
})
return () => {
unsubscribe()
}
}, [navigation])
}

View File

@ -4,3 +4,8 @@ export const getUnreadCount = (id: string) => {
const state = useUnreadStore.getState()
return state.data[id] ?? 0
}
export const getAllUnreadCount = () => {
const state = useUnreadStore.getState()
return Object.values(state.data).reduce((acc, unread) => acc + unread, 0)
}

View File

@ -2,6 +2,8 @@ import type { FeedViewType } from "@follow/constants"
import { useMutation, useQuery } from "@tanstack/react-query"
import { useCallback, useEffect } from "react"
import { setBadgeCountAsyncWithPermission } from "@/src/lib/permission"
import { useListFeedIds } from "../list/hooks"
import { useSubscriptionByView } from "../subscription/hooks"
import { unreadSyncService, useUnreadStore } from "./store"
@ -23,6 +25,13 @@ export const useAutoMarkAsRead = (entryId: string) => {
}, [entryId, mutate])
}
export function useUnreadCountBadge() {
const unreadCount = useUnreadCounts()
useEffect(() => {
setBadgeCountAsyncWithPermission(unreadCount)
}, [unreadCount])
}
export const useUnreadCount = (subscriptionId: string) => {
return useUnreadStore((state) => state.data[subscriptionId])
}
@ -32,10 +41,13 @@ export const useListUnreadCount = (listId: string) => {
return useUnreadCounts(feedIds ?? [])
}
export const useUnreadCounts = (subscriptionIds: string[]): number => {
export const useUnreadCounts = (subscriptionIds?: string[]): number => {
return useUnreadStore(
useCallback(
(state) => {
if (!subscriptionIds)
return Object.values(state.data).reduce((acc, unread) => acc + unread, 0)
let count = 0
for (const subscriptionId of subscriptionIds) {
count += state.data[subscriptionId] ?? 0

View File

@ -1,7 +1,9 @@
import type { FeedViewType } from "@follow/constants"
import * as Notifications from "expo-notifications"
import type { UnreadSchema } from "@/src/database/schemas/types"
import { apiClient } from "@/src/lib/api-fetch"
import { setBadgeCountAsyncWithPermission } from "@/src/lib/permission"
import { EntryService } from "@/src/services/entry"
import { UnreadService } from "@/src/services/unread"
@ -9,6 +11,7 @@ import { getEntry } from "../entry/getter"
import { entryActions } from "../entry/store"
import { createTransaction, createZustandStore } from "../internal/helper"
import { getSubscriptionByView } from "../subscription/getter"
import { getAllUnreadCount } from "./getter"
type SubscriptionId = string
interface UnreadStore {
@ -30,6 +33,17 @@ class UnreadSyncService {
return res.data
}
async updateBadgeAtBackground() {
await this.fetch()
const allUnreadCount = getAllUnreadCount()
const currentBadgeCount = await Notifications.getBadgeCountAsync()
if (allUnreadCount === currentBadgeCount) {
return false
}
setBadgeCountAsyncWithPermission(allUnreadCount)
return true
}
private async updateUnreadStatus(feedIds: string[]) {
await unreadActions.upsertMany(feedIds.map((id) => ({ subscriptionId: id, count: 0 })))
entryActions.markEntryReadStatusInSession({ feedIds, read: true })

View File

@ -4604,15 +4604,15 @@ declare const messagingOpenAPISchema: z.ZodObject<z.objectUtil.extendShape<Omit<
token: z.ZodString;
channel: z.ZodString;
}, "channel">, {
channel: z.ZodEnum<["desktop", "mobile"]>;
channel: z.ZodEnum<["macos", "windows", "linux", "ios", "android", "web", "desktop"]>;
}>, "strip", z.ZodTypeAny, {
userId: string | null;
token: string;
channel: "desktop" | "mobile";
channel: "macos" | "windows" | "linux" | "ios" | "android" | "web" | "desktop";
}, {
userId: string | null;
token: string;
channel: "desktop" | "mobile";
channel: "macos" | "windows" | "linux" | "ios" | "android" | "web" | "desktop";
}>;
declare const messagingRelations: drizzle_orm.Relations<"messaging", {
users: drizzle_orm.One<"user", false>;
@ -17391,7 +17391,7 @@ declare const _routes: hono_hono_base.HonoBase<Env, ({
input: {
json: {
token: string;
channel: "desktop" | "mobile";
channel: "macos" | "windows" | "linux" | "ios" | "android" | "web" | "desktop";
};
};
output: {

View File

@ -811,6 +811,9 @@ importers:
'@react-native-firebase/crashlytics':
specifier: 21.13.0
version: 21.13.0(2511037f97ab10cd056affaf5ecb511d)
'@react-native-firebase/messaging':
specifier: 21.13.0
version: 21.13.0(2511037f97ab10cd056affaf5ecb511d)
'@react-native-menu/menu':
specifier: 1.2.3
version: 1.2.3(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)
@ -859,6 +862,9 @@ importers:
expo-av:
specifier: 15.0.2
version: 15.0.2(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native-web@0.20.0(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)
expo-background-fetch:
specifier: 13.0.6
version: 13.0.6(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))
expo-blur:
specifier: 14.0.3
version: 14.0.3(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)
@ -904,6 +910,9 @@ importers:
expo-media-library:
specifier: 17.0.6
version: 17.0.6(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))
expo-notifications:
specifier: 0.29.14
version: 0.29.14(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)
expo-secure-store:
specifier: 14.0.1
version: 14.0.1(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))
@ -925,6 +934,9 @@ importers:
expo-system-ui:
specifier: 4.0.9
version: 4.0.9(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native-web@0.20.0(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))
expo-task-manager:
specifier: 12.0.6
version: 12.0.6(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))
expo-updates:
specifier: 0.27.4
version: 0.27.4(encoding@0.1.13)(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)
@ -4165,6 +4177,9 @@ packages:
'@iconify/utils@2.3.0':
resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==}
'@ide/backoff@1.0.0':
resolution: {integrity: sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==}
'@img/sharp-darwin-arm64@0.33.5':
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
@ -5417,6 +5432,15 @@ packages:
expo:
optional: true
'@react-native-firebase/messaging@21.13.0':
resolution: {integrity: sha512-ZUc44XRPjVvg0os9TdcOB7GECewJXsEzsder8gJRgCrOL6wn96uAqqOOmzAja64SQeMxvnelbfOtDtwoltLCvA==}
peerDependencies:
'@react-native-firebase/app': 21.13.0
expo: '>=47.0.0'
peerDependenciesMeta:
expo:
optional: true
'@react-native-menu/menu@1.2.3':
resolution: {integrity: sha512-sEfiVIivsa0lSelFm9Wbm/RAi+XoEHc75GGhjwvSrj9KSCVvNNXwr9F8l42e1t/lzYvVYzmkYxLG6VKxrDYJiw==}
peerDependencies:
@ -6927,6 +6951,9 @@ packages:
resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
engines: {node: '>=0.8'}
assert@2.1.0:
resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==}
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
@ -7087,6 +7114,9 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
badgin@1.2.3:
resolution: {integrity: sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==}
bail@2.0.2:
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
@ -9185,6 +9215,11 @@ packages:
react-native-web:
optional: true
expo-background-fetch@13.0.6:
resolution: {integrity: sha512-fhSpPA7U/CIuBwYbMVSbfPxczsvHKF8MWmFumfMgriDqop6bp/ccLbnpU1vPLQDPmRPS5dMdTz04KYIMdTpD9w==}
peerDependencies:
expo: '*'
expo-blur@14.0.3:
resolution: {integrity: sha512-BL3xnqBJbYm3Hg9t/HjNjdeY7N/q8eK5tsLYxswWG1yElISWZmMvrXYekl7XaVCPfyFyz8vQeaxd7q74ZY3Wrw==}
peerDependencies:
@ -9337,6 +9372,13 @@ packages:
expo-modules-core@2.2.3:
resolution: {integrity: sha512-01QqZzpP/wWlxnNly4G06MsOBUTbMDj02DQigZoXfDh80vd/rk3/uVXqnZgOdLSggTs6DnvOgAUy0H2q30XdUg==}
expo-notifications@0.29.14:
resolution: {integrity: sha512-AVduNx9mKOgcAqBfrXS1OHC9VAQZrDQLbVbcorMjPDGXW7m0Q5Q+BG6FYM/saVviF2eO8fhQRsTT40yYv5/bhQ==}
peerDependencies:
expo: '*'
react: 18.3.1
react-native: '*'
expo-secure-store@14.0.1:
resolution: {integrity: sha512-QUS+j4+UG4jRQalgnpmTvvrFnMVLqPiUZRzYPnG3+JrZ5kwVW2w6YS3WWerPoR7C6g3y/a2htRxRSylsDs+TaQ==}
peerDependencies:
@ -9383,6 +9425,12 @@ packages:
react-native-web:
optional: true
expo-task-manager@12.0.6:
resolution: {integrity: sha512-yGbS64OL95z7tAQAvryy0sGHuQgrcpvnJsdyuGL8MA9bcPtr+kytLZ4dOCDac7foQS7+FLDGgtiAR6v/64B5Pg==}
peerDependencies:
expo: '*'
react-native: '*'
expo-updates-interface@1.0.0:
resolution: {integrity: sha512-93oWtvULJOj+Pp+N/lpTcFfuREX1wNeHtp7Lwn8EbzYYmdn37MvZU3TPW2tYYCZuhzmKEXnUblYcruYoDu7IrQ==}
peerDependencies:
@ -10400,6 +10448,10 @@ packages:
is-alphanumerical@2.0.1:
resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
is-arguments@1.2.0:
resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==}
engines: {node: '>= 0.4'}
is-array-buffer@3.0.5:
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
engines: {node: '>= 0.4'}
@ -10529,6 +10581,10 @@ packages:
is-my-json-valid@2.20.6:
resolution: {integrity: sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==}
is-nan@1.3.2:
resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
engines: {node: '>= 0.4'}
is-natural-number@4.0.1:
resolution: {integrity: sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==}
@ -12003,6 +12059,10 @@ packages:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
object-is@1.1.6:
resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
engines: {node: '>= 0.4'}
object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
@ -14859,6 +14919,9 @@ packages:
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
unimodules-app-loader@5.0.1:
resolution: {integrity: sha512-JI4dUMOovvLrZ1U/mrQrR73cxGH26H7NpfBxwE0hk59CBOyHO4YYpliI3hPSGgZzt+YEy2VZR6nrspSUXY8jyw==}
uniqolor@1.1.1:
resolution: {integrity: sha512-HUwezlXCwm5bzsEXW7AP7ybezH13uWENRgYT+3dOdhJPvpYucSqvIGckMiLn+Uy2j0NVf3fPp43uZ4aun3t4Ww==}
@ -15049,6 +15112,9 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
util@0.12.5:
resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
utils-merge@1.0.1:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
@ -19006,6 +19072,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@ide/backoff@1.0.0': {}
'@img/sharp-darwin-arm64@0.33.5':
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.0.4
@ -20536,6 +20604,12 @@ snapshots:
optionalDependencies:
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
'@react-native-firebase/messaging@21.13.0(2511037f97ab10cd056affaf5ecb511d)':
dependencies:
'@react-native-firebase/app': 21.13.0(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)
optionalDependencies:
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
'@react-native-menu/menu@1.2.3(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)':
dependencies:
react: 18.3.1
@ -22350,6 +22424,14 @@ snapshots:
assert-plus@1.0.0:
optional: true
assert@2.1.0:
dependencies:
call-bind: 1.0.8
is-nan: 1.3.2
object-is: 1.1.6
object.assign: 4.1.7
util: 0.12.5
assertion-error@2.0.1: {}
ast-kit@1.4.2:
@ -22551,6 +22633,8 @@ snapshots:
babel-plugin-jest-hoist: 29.6.3
babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.10)
badgin@1.2.3: {}
bail@2.0.2: {}
balanced-match@1.0.2: {}
@ -25186,6 +25270,13 @@ snapshots:
optionalDependencies:
react-native-web: 0.20.0(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
expo-background-fetch@13.0.6(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)):
dependencies:
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
expo-task-manager: 12.0.6(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))
transitivePeerDependencies:
- react-native
expo-blur@14.0.3(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1):
dependencies:
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
@ -25360,6 +25451,21 @@ snapshots:
dependencies:
invariant: 2.2.4
expo-notifications@0.29.14(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1):
dependencies:
'@expo/image-utils': 0.6.5
'@ide/backoff': 1.0.0
abort-controller: 3.0.0
assert: 2.1.0
badgin: 1.2.3
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
expo-application: 6.0.2(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))
expo-constants: 17.0.8(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))
react: 18.3.1
react-native: 0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)
transitivePeerDependencies:
- supports-color
expo-secure-store@14.0.1(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)):
dependencies:
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
@ -25404,6 +25510,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
expo-task-manager@12.0.6(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)):
dependencies:
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
react-native: 0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)
unimodules-app-loader: 5.0.1
expo-updates-interface@1.0.0(expo@52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)):
dependencies:
expo: 52.0.44(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@expo/metro-runtime@4.0.1(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.13.5(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1))(react-native@0.77.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.3.12)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@6.0.5))(react@18.3.1)(utf-8-validate@6.0.5)
@ -26742,6 +26854,11 @@ snapshots:
is-alphabetical: 2.0.1
is-decimal: 2.0.1
is-arguments@1.2.0:
dependencies:
call-bound: 1.0.4
has-tostringtag: 1.0.2
is-array-buffer@3.0.5:
dependencies:
call-bind: 1.0.8
@ -26866,6 +26983,11 @@ snapshots:
xtend: 4.0.2
optional: true
is-nan@1.3.2:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
is-natural-number@4.0.1: {}
is-number-object@1.1.1:
@ -28725,6 +28847,11 @@ snapshots:
object-inspect@1.13.4: {}
object-is@1.1.6:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
object-keys@1.1.1: {}
object-treeify@1.1.33: {}
@ -31828,6 +31955,8 @@ snapshots:
trough: 2.2.0
vfile: 5.3.7
unimodules-app-loader@5.0.1: {}
uniqolor@1.1.1: {}
unique-filename@2.0.1:
@ -32026,6 +32155,14 @@ snapshots:
util-deprecate@1.0.2: {}
util@0.12.5:
dependencies:
inherits: 2.0.4
is-arguments: 1.2.0
is-generator-function: 1.1.0
is-typed-array: 1.1.15
which-typed-array: 1.1.19
utils-merge@1.0.1: {}
uuid@7.0.3: {}