A personal media tracker built on the AT Protocol opnshelf.xyz
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: move to expo router

+2818 -3420
+2
apps/mobile/.gitignore
··· 36 36 # typescript 37 37 *.tsbuildinfo 38 38 39 + app-example 40 + 39 41 # generated native folders 40 42 /ios 41 43 /android
+50
apps/mobile/README.md
··· 1 + # Welcome to your Expo app 👋 2 + 3 + This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app). 4 + 5 + ## Get started 6 + 7 + 1. Install dependencies 8 + 9 + ```bash 10 + npm install 11 + ``` 12 + 13 + 2. Start the app 14 + 15 + ```bash 16 + npx expo start 17 + ``` 18 + 19 + In the output, you'll find options to open the app in a 20 + 21 + - [development build](https://docs.expo.dev/develop/development-builds/introduction/) 22 + - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/) 23 + - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/) 24 + - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo 25 + 26 + You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction). 27 + 28 + ## Get a fresh project 29 + 30 + When you're ready, run: 31 + 32 + ```bash 33 + npm run reset-project 34 + ``` 35 + 36 + This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing. 37 + 38 + ## Learn more 39 + 40 + To learn more about developing your project with Expo, look at the following resources: 41 + 42 + - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides). 43 + - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web. 44 + 45 + ## Join the community 46 + 47 + Join our community of developers creating universal apps. 48 + 49 + - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute. 50 + - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
+31 -25
apps/mobile/app.json
··· 1 1 { 2 2 "expo": { 3 3 "name": "OpnShelf", 4 - "slug": "opnshelf", 4 + "slug": "OpnShelf", 5 5 "version": "1.0.0", 6 + "orientation": "portrait", 7 + "icon": "./assets/images/icon.png", 6 8 "scheme": "opnshelf", 7 - "orientation": "default", 8 - "icon": "./assets/icon.png", 9 - "userInterfaceStyle": "light", 9 + "userInterfaceStyle": "automatic", 10 10 "newArchEnabled": true, 11 - "splash": { 12 - "image": "./assets/splash-icon.png", 13 - "resizeMode": "contain", 14 - "backgroundColor": "#030712" 15 - }, 16 11 "ios": { 17 - "supportsTablet": true, 18 - "bundleIdentifier": "com.rowanpaul.opnshelf", 19 - "infoPlist": { 20 - "ITSAppUsesNonExemptEncryption": false 21 - } 12 + "supportsTablet": true 22 13 }, 23 14 "android": { 24 15 "adaptiveIcon": { 25 - "foregroundImage": "./assets/adaptive-icon.png", 26 - "backgroundColor": "#030712" 16 + "backgroundColor": "#E6F4FE", 17 + "foregroundImage": "./assets/images/android-icon-foreground.png", 18 + "backgroundImage": "./assets/images/android-icon-background.png", 19 + "monochromeImage": "./assets/images/android-icon-monochrome.png" 27 20 }, 28 21 "edgeToEdgeEnabled": true, 29 - "predictiveBackGestureEnabled": false, 30 - "package": "com.rowanpaul.opnshelf" 22 + "predictiveBackGestureEnabled": false 31 23 }, 32 24 "web": { 33 - "favicon": "./assets/favicon.png" 34 - }, 35 - "extra": { 36 - "eas": { 37 - "projectId": "87d86952-59ab-4711-9f5f-f9477b2d14f6" 38 - } 25 + "output": "static", 26 + "favicon": "./assets/images/favicon.png" 39 27 }, 40 - "owner": "rowanpaul" 28 + "plugins": [ 29 + "expo-router", 30 + [ 31 + "expo-splash-screen", 32 + { 33 + "image": "./assets/images/splash-icon.png", 34 + "imageWidth": 200, 35 + "resizeMode": "contain", 36 + "backgroundColor": "#ffffff", 37 + "dark": { 38 + "backgroundColor": "#000000" 39 + } 40 + } 41 + ] 42 + ], 43 + "experiments": { 44 + "typedRoutes": true, 45 + "reactCompiler": true 46 + } 41 47 } 42 48 }
+35
apps/mobile/app/(tabs)/_layout.tsx
··· 1 + import { Tabs } from 'expo-router'; 2 + import React from 'react'; 3 + 4 + import { HapticTab } from '@/components/haptic-tab'; 5 + import { IconSymbol } from '@/components/ui/icon-symbol'; 6 + import { Colors } from '@/constants/theme'; 7 + import { useColorScheme } from '@/hooks/use-color-scheme'; 8 + 9 + export default function TabLayout() { 10 + const colorScheme = useColorScheme(); 11 + 12 + return ( 13 + <Tabs 14 + screenOptions={{ 15 + tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint, 16 + headerShown: false, 17 + tabBarButton: HapticTab, 18 + }}> 19 + <Tabs.Screen 20 + name="index" 21 + options={{ 22 + title: 'Home', 23 + tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />, 24 + }} 25 + /> 26 + <Tabs.Screen 27 + name="explore" 28 + options={{ 29 + title: 'Explore', 30 + tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />, 31 + }} 32 + /> 33 + </Tabs> 34 + ); 35 + }
+112
apps/mobile/app/(tabs)/explore.tsx
··· 1 + import { Image } from 'expo-image'; 2 + import { Platform, StyleSheet } from 'react-native'; 3 + 4 + import { Collapsible } from '@/components/ui/collapsible'; 5 + import { ExternalLink } from '@/components/external-link'; 6 + import ParallaxScrollView from '@/components/parallax-scroll-view'; 7 + import { ThemedText } from '@/components/themed-text'; 8 + import { ThemedView } from '@/components/themed-view'; 9 + import { IconSymbol } from '@/components/ui/icon-symbol'; 10 + import { Fonts } from '@/constants/theme'; 11 + 12 + export default function TabTwoScreen() { 13 + return ( 14 + <ParallaxScrollView 15 + headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }} 16 + headerImage={ 17 + <IconSymbol 18 + size={310} 19 + color="#808080" 20 + name="chevron.left.forwardslash.chevron.right" 21 + style={styles.headerImage} 22 + /> 23 + }> 24 + <ThemedView style={styles.titleContainer}> 25 + <ThemedText 26 + type="title" 27 + style={{ 28 + fontFamily: Fonts.rounded, 29 + }}> 30 + Explore 31 + </ThemedText> 32 + </ThemedView> 33 + <ThemedText>This app includes example code to help you get started.</ThemedText> 34 + <Collapsible title="File-based routing"> 35 + <ThemedText> 36 + This app has two screens:{' '} 37 + <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '} 38 + <ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText> 39 + </ThemedText> 40 + <ThemedText> 41 + The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '} 42 + sets up the tab navigator. 43 + </ThemedText> 44 + <ExternalLink href="https://docs.expo.dev/router/introduction"> 45 + <ThemedText type="link">Learn more</ThemedText> 46 + </ExternalLink> 47 + </Collapsible> 48 + <Collapsible title="Android, iOS, and web support"> 49 + <ThemedText> 50 + You can open this project on Android, iOS, and the web. To open the web version, press{' '} 51 + <ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project. 52 + </ThemedText> 53 + </Collapsible> 54 + <Collapsible title="Images"> 55 + <ThemedText> 56 + For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '} 57 + <ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for 58 + different screen densities 59 + </ThemedText> 60 + <Image 61 + source={require('@/assets/images/react-logo.png')} 62 + style={{ width: 100, height: 100, alignSelf: 'center' }} 63 + /> 64 + <ExternalLink href="https://reactnative.dev/docs/images"> 65 + <ThemedText type="link">Learn more</ThemedText> 66 + </ExternalLink> 67 + </Collapsible> 68 + <Collapsible title="Light and dark mode components"> 69 + <ThemedText> 70 + This template has light and dark mode support. The{' '} 71 + <ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect 72 + what the user&apos;s current color scheme is, and so you can adjust UI colors accordingly. 73 + </ThemedText> 74 + <ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/"> 75 + <ThemedText type="link">Learn more</ThemedText> 76 + </ExternalLink> 77 + </Collapsible> 78 + <Collapsible title="Animations"> 79 + <ThemedText> 80 + This template includes an example of an animated component. The{' '} 81 + <ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses 82 + the powerful{' '} 83 + <ThemedText type="defaultSemiBold" style={{ fontFamily: Fonts.mono }}> 84 + react-native-reanimated 85 + </ThemedText>{' '} 86 + library to create a waving hand animation. 87 + </ThemedText> 88 + {Platform.select({ 89 + ios: ( 90 + <ThemedText> 91 + The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '} 92 + component provides a parallax effect for the header image. 93 + </ThemedText> 94 + ), 95 + })} 96 + </Collapsible> 97 + </ParallaxScrollView> 98 + ); 99 + } 100 + 101 + const styles = StyleSheet.create({ 102 + headerImage: { 103 + color: '#808080', 104 + bottom: -90, 105 + left: -35, 106 + position: 'absolute', 107 + }, 108 + titleContainer: { 109 + flexDirection: 'row', 110 + gap: 8, 111 + }, 112 + });
+98
apps/mobile/app/(tabs)/index.tsx
··· 1 + import { Image } from 'expo-image'; 2 + import { Platform, StyleSheet } from 'react-native'; 3 + 4 + import { HelloWave } from '@/components/hello-wave'; 5 + import ParallaxScrollView from '@/components/parallax-scroll-view'; 6 + import { ThemedText } from '@/components/themed-text'; 7 + import { ThemedView } from '@/components/themed-view'; 8 + import { Link } from 'expo-router'; 9 + 10 + export default function HomeScreen() { 11 + return ( 12 + <ParallaxScrollView 13 + headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }} 14 + headerImage={ 15 + <Image 16 + source={require('@/assets/images/partial-react-logo.png')} 17 + style={styles.reactLogo} 18 + /> 19 + }> 20 + <ThemedView style={styles.titleContainer}> 21 + <ThemedText type="title">Welcome!</ThemedText> 22 + <HelloWave /> 23 + </ThemedView> 24 + <ThemedView style={styles.stepContainer}> 25 + <ThemedText type="subtitle">Step 1: Try it</ThemedText> 26 + <ThemedText> 27 + Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes. 28 + Press{' '} 29 + <ThemedText type="defaultSemiBold"> 30 + {Platform.select({ 31 + ios: 'cmd + d', 32 + android: 'cmd + m', 33 + web: 'F12', 34 + })} 35 + </ThemedText>{' '} 36 + to open developer tools. 37 + </ThemedText> 38 + </ThemedView> 39 + <ThemedView style={styles.stepContainer}> 40 + <Link href="/modal"> 41 + <Link.Trigger> 42 + <ThemedText type="subtitle">Step 2: Explore</ThemedText> 43 + </Link.Trigger> 44 + <Link.Preview /> 45 + <Link.Menu> 46 + <Link.MenuAction title="Action" icon="cube" onPress={() => alert('Action pressed')} /> 47 + <Link.MenuAction 48 + title="Share" 49 + icon="square.and.arrow.up" 50 + onPress={() => alert('Share pressed')} 51 + /> 52 + <Link.Menu title="More" icon="ellipsis"> 53 + <Link.MenuAction 54 + title="Delete" 55 + icon="trash" 56 + destructive 57 + onPress={() => alert('Delete pressed')} 58 + /> 59 + </Link.Menu> 60 + </Link.Menu> 61 + </Link> 62 + 63 + <ThemedText> 64 + {`Tap the Explore tab to learn more about what's included in this starter app.`} 65 + </ThemedText> 66 + </ThemedView> 67 + <ThemedView style={styles.stepContainer}> 68 + <ThemedText type="subtitle">Step 3: Get a fresh start</ThemedText> 69 + <ThemedText> 70 + {`When you're ready, run `} 71 + <ThemedText type="defaultSemiBold">npm run reset-project</ThemedText> to get a fresh{' '} 72 + <ThemedText type="defaultSemiBold">app</ThemedText> directory. This will move the current{' '} 73 + <ThemedText type="defaultSemiBold">app</ThemedText> to{' '} 74 + <ThemedText type="defaultSemiBold">app-example</ThemedText>. 75 + </ThemedText> 76 + </ThemedView> 77 + </ParallaxScrollView> 78 + ); 79 + } 80 + 81 + const styles = StyleSheet.create({ 82 + titleContainer: { 83 + flexDirection: 'row', 84 + alignItems: 'center', 85 + gap: 8, 86 + }, 87 + stepContainer: { 88 + gap: 8, 89 + marginBottom: 8, 90 + }, 91 + reactLogo: { 92 + height: 178, 93 + width: 290, 94 + bottom: 0, 95 + left: 0, 96 + position: 'absolute', 97 + }, 98 + });
+13 -96
apps/mobile/app/_layout.tsx
··· 1 + import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'; 1 2 import { Stack } from 'expo-router'; 2 3 import { StatusBar } from 'expo-status-bar'; 3 - import { View, ActivityIndicator, Text } from 'react-native'; 4 - import { Ionicons } from '@expo/vector-icons'; 5 - import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; 6 - import { configureApiClient } from '@opnshelf/api'; 7 - import { useEffect, useState } from 'react'; 8 - import { HeaderRight } from '@/components/HeaderRight'; 9 - import { loadSession } from '@/lib/session'; 10 - import { env } from '@/env'; 11 - import '../src/global.css'; 4 + import 'react-native-reanimated'; 12 5 13 - configureApiClient(env.EXPO_PUBLIC_API_URL); 6 + import { useColorScheme } from '@/hooks/use-color-scheme'; 14 7 15 - const queryClient = new QueryClient({ 16 - defaultOptions: { 17 - queries: { 18 - staleTime: 60 * 1000, 19 - }, 20 - }, 21 - }); 22 - 23 - function LoadingScreen() { 24 - return ( 25 - <View className="flex-1 justify-center items-center bg-gray-950"> 26 - <View className="items-center"> 27 - <View className="w-20 h-20 rounded-2xl bg-violet-600/20 justify-center items-center mb-6"> 28 - <Ionicons name="film" size={48} color="#a855f7" /> 29 - </View> 30 - <Text className="text-xl font-semibold text-gray-100 mb-2"> 31 - OpnShelf 32 - </Text> 33 - <Text className="text-gray-400 mb-6"> 34 - Loading... 35 - </Text> 36 - <ActivityIndicator size="large" color="#a855f7" /> 37 - </View> 38 - </View> 39 - ); 40 - } 8 + export const unstable_settings = { 9 + anchor: '(tabs)', 10 + }; 41 11 42 12 export default function RootLayout() { 43 - const [isSessionLoaded, setIsSessionLoaded] = useState(false); 44 - 45 - useEffect(() => { 46 - loadSession().finally(() => { 47 - setIsSessionLoaded(true); 48 - }); 49 - }, []); 50 - 51 - if (!isSessionLoaded) { 52 - return ( 53 - <QueryClientProvider client={queryClient}> 54 - <LoadingScreen /> 55 - </QueryClientProvider> 56 - ); 57 - } 13 + const colorScheme = useColorScheme(); 58 14 59 15 return ( 60 - <QueryClientProvider client={queryClient}> 61 - <Stack 62 - screenOptions={{ 63 - headerStyle: { backgroundColor: '#030712' }, 64 - headerTintColor: '#f9fafb', 65 - headerShadowVisible: false, 66 - contentStyle: { backgroundColor: '#030712' }, 67 - headerRight: () => <HeaderRight />, 68 - }} 69 - > 70 - <Stack.Screen 71 - name="index" 72 - options={{ title: 'OpnShelf' }} 73 - /> 74 - <Stack.Screen 75 - name="search" 76 - options={{ title: 'Search Movies' }} 77 - /> 78 - <Stack.Screen 79 - name="shelf" 80 - options={{ title: 'My Shelf' }} 81 - /> 82 - <Stack.Screen 83 - name="login" 84 - options={{ 85 - title: 'Sign In', 86 - headerRight: () => null, 87 - }} 88 - /> 89 - <Stack.Screen 90 - name="auth/complete" 91 - options={{ 92 - title: '', 93 - headerRight: () => null, 94 - headerBackVisible: false, 95 - }} 96 - /> 97 - <Stack.Screen 98 - name="movie/[movieId]/[title]" 99 - options={{ 100 - headerShown: false, 101 - }} 102 - /> 16 + <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> 17 + <Stack> 18 + <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> 19 + <Stack.Screen name="modal" options={{ presentation: 'modal', title: 'Modal' }} /> 103 20 </Stack> 104 - <StatusBar style="light" /> 105 - </QueryClientProvider> 21 + <StatusBar style="auto" /> 22 + </ThemeProvider> 106 23 ); 107 24 }
-39
apps/mobile/app/auth/complete.tsx
··· 1 - import { useEffect } from 'react'; 2 - import { useQueryClient } from '@tanstack/react-query'; 3 - import { Ionicons } from '@expo/vector-icons'; 4 - import { ActivityIndicator, Text, View } from 'react-native'; 5 - import { useRouter, useLocalSearchParams } from 'expo-router'; 6 - import { saveSession } from '@/lib/session'; 7 - 8 - export default function AuthCompleteScreen() { 9 - const queryClient = useQueryClient(); 10 - const router = useRouter(); 11 - const params = useLocalSearchParams<{ session?: string }>(); 12 - const { session } = params; 13 - 14 - useEffect(() => { 15 - async function completeAuth() { 16 - if (session) { 17 - await saveSession(session); 18 - } 19 - 20 - await queryClient.invalidateQueries({ queryKey: ['auth'] }); 21 - 22 - router.replace('/'); 23 - } 24 - 25 - completeAuth(); 26 - }, [router, queryClient, session]); 27 - 28 - return ( 29 - <View className="flex-1 bg-gray-950 justify-center items-center p-4"> 30 - <Ionicons name="film" size={48} color="#a855f7" /> 31 - <ActivityIndicator 32 - size="large" 33 - color="#a855f7" 34 - className="my-4" 35 - /> 36 - <Text className="text-gray-400">Completing sign-in...</Text> 37 - </View> 38 - ); 39 - }
-130
apps/mobile/app/index.tsx
··· 1 - import { useQuery } from '@tanstack/react-query'; 2 - import { authControllerMeOptions } from '@opnshelf/api'; 3 - import { Ionicons } from '@expo/vector-icons'; 4 - import { Image, Text, TouchableOpacity, View, useWindowDimensions } from 'react-native'; 5 - import { useRouter } from 'expo-router'; 6 - import { useIsTablet } from '@/utils'; 7 - import { Button } from '@/components/ui/button'; 8 - import { 9 - Card, 10 - CardContent, 11 - CardDescription, 12 - CardHeader, 13 - CardTitle, 14 - } from '@/components/ui/card'; 15 - 16 - export default function HomeScreen() { 17 - const { width } = useWindowDimensions(); 18 - const isTablet = useIsTablet(); 19 - const router = useRouter(); 20 - 21 - const { data: user } = useQuery({ 22 - ...authControllerMeOptions(), 23 - staleTime: 5 * 60 * 1000, 24 - retry: false, 25 - }); 26 - 27 - return ( 28 - <View className="flex-1 bg-gray-950 px-4 pt-12 pb-6"> 29 - <View className="items-center mb-12"> 30 - <View className="mb-6"> 31 - <Ionicons name="film" size={48} color="#a855f7" /> 32 - </View> 33 - <Text className="text-4xl font-bold text-gray-50 mb-4">OpnShelf</Text> 34 - <Text className="text-lg text-gray-400 text-center mb-8"> 35 - Your personal media tracker powered by AT Protocol 36 - </Text> 37 - 38 - {user && ( 39 - <View className="flex-row items-center gap-3 mb-6 bg-gray-900 py-3 px-4 rounded-lg border border-gray-800"> 40 - {user.avatar ? ( 41 - <Image 42 - source={{ uri: String(user.avatar) }} 43 - className="w-10 h-10 rounded-full" 44 - /> 45 - ) : ( 46 - <View className="w-10 h-10 rounded-full bg-gray-800 justify-center items-center"> 47 - <Ionicons name="person" size={20} color="#9ca3af" /> 48 - </View> 49 - )} 50 - <View> 51 - <Text className="text-gray-50 font-semibold"> 52 - {user.displayName ? String(user.displayName) : user.handle} 53 - </Text> 54 - <Text className="text-gray-500 text-sm">@{user.handle}</Text> 55 - </View> 56 - </View> 57 - )} 58 - 59 - <View className={`${isTablet ? 'flex-row gap-4' : 'flex-col gap-3'}`}> 60 - <Button 61 - size="lg" 62 - onPress={() => router.push('/search')} 63 - > 64 - <Ionicons name="search" size={20} color="#fff" /> 65 - <Text className="text-white text-base font-semibold ml-2"> 66 - Search Movies 67 - </Text> 68 - </Button> 69 - 70 - {user ? ( 71 - <TouchableOpacity 72 - className="flex-row items-center gap-2 bg-gray-800 py-3 px-6 rounded-lg border border-gray-700" 73 - onPress={() => router.push('/shelf')} 74 - activeOpacity={0.8} 75 - > 76 - <Ionicons name="book" size={20} color="#a855f7" /> 77 - <Text className="text-gray-50 text-base font-semibold"> 78 - My Shelf 79 - </Text> 80 - </TouchableOpacity> 81 - ) : ( 82 - <TouchableOpacity 83 - className="flex-row items-center gap-2 bg-gray-800 py-3 px-6 rounded-lg border border-gray-700" 84 - onPress={() => router.push('/login')} 85 - activeOpacity={0.8} 86 - > 87 - <Ionicons name="log-in" size={20} color="#a855f7" /> 88 - <Text className="text-gray-50 text-base font-semibold"> 89 - Sign In 90 - </Text> 91 - </TouchableOpacity> 92 - )} 93 - </View> 94 - </View> 95 - 96 - <View className={`${isTablet ? 'flex-row flex-wrap gap-4' : 'gap-6'}`}> 97 - <Card className={`${isTablet ? 'flex-1 min-w-[45%]' : ''}`}> 98 - <CardHeader> 99 - <CardTitle className="text-lg">Track Your Media</CardTitle> 100 - </CardHeader> 101 - <CardContent> 102 - <CardDescription> 103 - Keep track of movies, shows, and games you&apos;ve watched and played 104 - </CardDescription> 105 - </CardContent> 106 - </Card> 107 - <Card className={`${isTablet ? 'flex-1 min-w-[45%]' : ''}`}> 108 - <CardHeader> 109 - <CardTitle className="text-lg">Own Your Data</CardTitle> 110 - </CardHeader> 111 - <CardContent> 112 - <CardDescription> 113 - Built on AT Protocol - your data belongs to you 114 - </CardDescription> 115 - </CardContent> 116 - </Card> 117 - <Card className={`${isTablet ? 'flex-1 min-w-[45%]' : ''}`}> 118 - <CardHeader> 119 - <CardTitle className="text-lg">Discover & Share</CardTitle> 120 - </CardHeader> 121 - <CardContent> 122 - <CardDescription> 123 - See what others are watching and share your favorites 124 - </CardDescription> 125 - </CardContent> 126 - </Card> 127 - </View> 128 - </View> 129 - ); 130 - }
-182
apps/mobile/app/login.tsx
··· 1 - import { useEffect, useState } from 'react'; 2 - import { useQuery } from '@tanstack/react-query'; 3 - import { Ionicons } from '@expo/vector-icons'; 4 - import { 5 - ActivityIndicator, 6 - KeyboardAvoidingView, 7 - Platform, 8 - ScrollView, 9 - Text, 10 - TextInput, 11 - TouchableOpacity, 12 - View, 13 - } from 'react-native'; 14 - import * as WebBrowser from 'expo-web-browser'; 15 - import { useRouter, useLocalSearchParams } from 'expo-router'; 16 - import { authControllerMeOptions, getLoginUrl } from '@opnshelf/api'; 17 - import { useIsTablet } from '@/utils'; 18 - 19 - export default function LoginScreen() { 20 - const [handle, setHandle] = useState(''); 21 - const [isSubmitting, setIsSubmitting] = useState(false); 22 - const router = useRouter(); 23 - const params = useLocalSearchParams<{ 24 - error?: 'auth_failed' | 'callback_failed'; 25 - redirect?: string; 26 - reason?: 'session_expired'; 27 - }>(); 28 - const { error, redirect, reason } = params; 29 - const isTablet = useIsTablet(); 30 - 31 - const { data: user, isLoading: isAuthLoading } = useQuery({ 32 - ...authControllerMeOptions(), 33 - staleTime: 5 * 60 * 1000, 34 - retry: false, 35 - }); 36 - 37 - useEffect(() => { 38 - if (user && !isAuthLoading) { 39 - if (redirect === 'shelf') { 40 - router.replace('/shelf'); 41 - } else if (redirect === 'search') { 42 - router.replace('/search'); 43 - } else { 44 - router.replace('/'); 45 - } 46 - } 47 - }, [user, isAuthLoading, router, redirect]); 48 - 49 - const handleSubmit = async () => { 50 - setIsSubmitting(true); 51 - 52 - try { 53 - const loginUrl = `${getLoginUrl(handle || undefined)}&platform=mobile`; 54 - 55 - const result = await WebBrowser.openAuthSessionAsync( 56 - loginUrl, 57 - 'opnshelf://auth/complete' 58 - ); 59 - 60 - if (result.type === 'success') { 61 - const url = new URL(result.url); 62 - const session = url.searchParams.get('session'); 63 - router.replace({ pathname: '/auth/complete', params: { session: session || undefined } }); 64 - } else { 65 - setIsSubmitting(false); 66 - } 67 - } catch (err) { 68 - console.error('Auth error:', err); 69 - setIsSubmitting(false); 70 - } 71 - }; 72 - 73 - const errorMessages: Record<string, string> = { 74 - auth_failed: 'Authentication failed. Please try again.', 75 - callback_failed: 'Something went wrong during sign in. Please try again.', 76 - }; 77 - 78 - if (isAuthLoading) { 79 - return ( 80 - <View className="flex-1 bg-gray-950 justify-center items-center"> 81 - <ActivityIndicator size="large" color="#a855f7" /> 82 - </View> 83 - ); 84 - } 85 - 86 - return ( 87 - <KeyboardAvoidingView 88 - behavior={Platform.OS === 'ios' ? 'padding' : 'height'} 89 - className="flex-1 bg-gray-950" 90 - > 91 - <ScrollView 92 - className="flex-1" 93 - contentContainerStyle={{ flexGrow: 1, paddingHorizontal: 16, paddingTop: 48, paddingBottom: 24 }} 94 - keyboardShouldPersistTaps="handled" 95 - > 96 - <View className={`flex-1 justify-center ${isTablet ? 'items-center' : ''}`}> 97 - <View className={`items-center mb-8 ${isTablet ? 'w-full max-w-md' : ''}`}> 98 - <View className="mb-4"> 99 - <Ionicons name="film" size={48} color="#a855f7" /> 100 - </View> 101 - <Text className="text-3xl font-bold text-gray-50 mb-2"> 102 - Sign in to OpnShelf 103 - </Text> 104 - <Text className="text-base text-gray-400 text-center"> 105 - Use your ATProto account to sign in 106 - </Text> 107 - </View> 108 - 109 - {reason === 'session_expired' && ( 110 - <View className="mb-6 p-4 bg-amber-950/50 border border-amber-800 rounded-lg"> 111 - <Text className="text-amber-200 font-semibold mb-1"> 112 - You have been logged out 113 - </Text> 114 - <Text className="text-amber-300/80 text-sm"> 115 - Your session has expired. Please sign in again to continue. 116 - </Text> 117 - </View> 118 - )} 119 - 120 - {error && ( 121 - <View className="mb-6 p-4 bg-red-900/30 border border-red-800 rounded-lg flex-row items-start gap-3"> 122 - <Ionicons name="alert-circle" size={20} color="#f87171" /> 123 - <Text className="text-red-200 text-sm flex-1"> 124 - {errorMessages[error] || 'An error occurred. Please try again.'} 125 - </Text> 126 - </View> 127 - )} 128 - 129 - <View className={`gap-6 ${isTablet ? 'w-full max-w-md' : ''}`}> 130 - <View> 131 - <Text className="text-sm font-medium text-gray-300 mb-2"> 132 - Handle 133 - </Text> 134 - <TextInput 135 - className="w-full px-4 py-3 bg-gray-900 border border-gray-700 rounded-lg text-white" 136 - value={handle} 137 - onChangeText={setHandle} 138 - placeholder="username.bsky.social" 139 - placeholderTextColor="#6b7280" 140 - autoCapitalize="none" 141 - autoCorrect={false} 142 - keyboardType="email-address" 143 - editable={!isSubmitting} 144 - /> 145 - </View> 146 - 147 - <TouchableOpacity 148 - className="flex-row items-center justify-center gap-2 px-4 py-3 bg-violet-600 rounded-lg disabled:bg-violet-800" 149 - onPress={handleSubmit} 150 - disabled={isSubmitting} 151 - activeOpacity={0.8} 152 - > 153 - {isSubmitting ? ( 154 - <> 155 - <ActivityIndicator size="small" color="#fff" /> 156 - <Text className="text-white font-semibold">Redirecting...</Text> 157 - </> 158 - ) : ( 159 - <> 160 - <Ionicons name="log-in" size={20} color="#fff" /> 161 - <Text className="text-white font-semibold"> 162 - Sign in 163 - </Text> 164 - </> 165 - )} 166 - </TouchableOpacity> 167 - 168 - <Text className="text-center text-sm text-gray-400"> 169 - Don&apos;t have an account?{' '} 170 - <Text 171 - className="text-violet-400 underline" 172 - onPress={() => {}} 173 - > 174 - Sign up on Bluesky 175 - </Text> 176 - </Text> 177 - </View> 178 - </View> 179 - </ScrollView> 180 - </KeyboardAvoidingView> 181 - ); 182 - }
+29
apps/mobile/app/modal.tsx
··· 1 + import { Link } from 'expo-router'; 2 + import { StyleSheet } from 'react-native'; 3 + 4 + import { ThemedText } from '@/components/themed-text'; 5 + import { ThemedView } from '@/components/themed-view'; 6 + 7 + export default function ModalScreen() { 8 + return ( 9 + <ThemedView style={styles.container}> 10 + <ThemedText type="title">This is a modal</ThemedText> 11 + <Link href="/" dismissTo style={styles.link}> 12 + <ThemedText type="link">Go to home screen</ThemedText> 13 + </Link> 14 + </ThemedView> 15 + ); 16 + } 17 + 18 + const styles = StyleSheet.create({ 19 + container: { 20 + flex: 1, 21 + alignItems: 'center', 22 + justifyContent: 'center', 23 + padding: 20, 24 + }, 25 + link: { 26 + marginTop: 15, 27 + paddingVertical: 15, 28 + }, 29 + });
-714
apps/mobile/app/movie/[movieId]/[title].tsx
··· 1 - import { 2 - authControllerMeOptions, 3 - moviesControllerGetMovieDetailsOptions, 4 - moviesControllerGetUserMoviesOptions, 5 - moviesControllerGetUserMoviesQueryKey, 6 - moviesControllerMarkWatchedMutation, 7 - moviesControllerUnmarkWatchedMutation, 8 - moviesControllerDeleteWatchHistoryEntryMutation, 9 - moviesControllerGetMovieWatchHistory, 10 - type TmdbMovieDetailDto, 11 - type TrackedMovieDto, 12 - type WatchHistoryItemDto, 13 - } from '@opnshelf/api'; 14 - import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; 15 - import { useMemo, useState } from 'react'; 16 - import { 17 - Image, 18 - ScrollView, 19 - Text, 20 - TouchableOpacity, 21 - View, 22 - ActivityIndicator, 23 - useWindowDimensions, 24 - } from 'react-native'; 25 - import Ionicons from '@expo/vector-icons/Ionicons'; 26 - import { useRouter, useLocalSearchParams } from 'expo-router'; 27 - import { useIsLandscape } from '@/utils'; 28 - import { Button } from '@/components/ui/button'; 29 - import { 30 - Dialog, 31 - DialogContent, 32 - DialogDescription, 33 - DialogHeader, 34 - DialogTitle, 35 - DialogFooter, 36 - DialogClose, 37 - DialogScrollContent, 38 - } from '@/components/ui/dialog'; 39 - import { Badge } from '@/components/ui/badge'; 40 - import { DateTimePickerModal } from '@/components/ui/date-time-picker'; 41 - 42 - export default function MovieDetailScreen() { 43 - const params = useLocalSearchParams<{ movieId: string; title: string }>(); 44 - const { movieId, title } = params; 45 - const queryClient = useQueryClient(); 46 - const router = useRouter(); 47 - const [showHours, setShowHours] = useState(false); 48 - const [showDateModal, setShowDateModal] = useState(false); 49 - const [customDate, setCustomDate] = useState<Date | null>(null); 50 - const [showDatePicker, setShowDatePicker] = useState(false); 51 - const [showHistoryDialog, setShowHistoryDialog] = useState(false); 52 - const isLandscape = useIsLandscape(); 53 - const backdropHeight = isLandscape ? 'h-80' : 'h-64'; 54 - 55 - const formatRuntime = (minutes: number, useHours: boolean) => { 56 - if (!useHours) return `${minutes} min`; 57 - const hours = Math.floor(minutes / 60); 58 - const mins = minutes % 60; 59 - if (mins === 0) return `${hours} hours`; 60 - return `${hours}h ${mins}m`; 61 - }; 62 - 63 - const { data: user } = useQuery({ 64 - ...authControllerMeOptions(), 65 - staleTime: 5 * 60 * 1000, 66 - retry: false, 67 - }); 68 - 69 - const { data: movieData, isLoading: isMovieLoading } = useQuery({ 70 - ...moviesControllerGetMovieDetailsOptions({ 71 - path: { movieId }, 72 - }), 73 - }); 74 - 75 - const movie = movieData as TmdbMovieDetailDto | undefined; 76 - 77 - const colors = movie?.colors || { 78 - primary: '#8b5cf6', 79 - secondary: '#6366f1', 80 - accent: '#a855f7', 81 - muted: '#4c1d95', 82 - }; 83 - 84 - const { data: trackedMovies } = useQuery({ 85 - ...moviesControllerGetUserMoviesOptions({ 86 - path: { userDid: user?.did || '' }, 87 - }), 88 - enabled: !!user?.did, 89 - }); 90 - 91 - const { data: watchHistory } = useQuery<WatchHistoryItemDto[]>({ 92 - queryKey: ['watchHistory', user?.did, movieId], 93 - queryFn: async () => { 94 - if (!user?.did) return []; 95 - const { data } = await moviesControllerGetMovieWatchHistory({ 96 - path: { userDid: user.did, movieId }, 97 - }); 98 - return data || []; 99 - }, 100 - enabled: !!user?.did && !!movieId, 101 - }); 102 - 103 - const isWatched = useMemo(() => { 104 - if (!trackedMovies) return false; 105 - return trackedMovies.some((tm: TrackedMovieDto) => tm.movieId === movieId); 106 - }, [trackedMovies, movieId]); 107 - 108 - const trackedMovie = useMemo(() => { 109 - if (!trackedMovies) return null; 110 - return ( 111 - trackedMovies.find((tm: TrackedMovieDto) => tm.movieId === movieId) || null 112 - ); 113 - }, [trackedMovies, movieId]); 114 - 115 - const formattedWatchedDate = useMemo(() => { 116 - if (!trackedMovie?.watchedDate) return null; 117 - return new Date(trackedMovie.watchedDate).toLocaleString('en-US', { 118 - year: 'numeric', 119 - month: 'short', 120 - day: 'numeric', 121 - hour: '2-digit', 122 - minute: '2-digit', 123 - hour12: false, 124 - }); 125 - }, [trackedMovie]); 126 - 127 - const formatWatchDate = (dateString: string) => { 128 - return new Date(dateString).toLocaleString('en-US', { 129 - year: 'numeric', 130 - month: 'short', 131 - day: 'numeric', 132 - hour: '2-digit', 133 - minute: '2-digit', 134 - hour12: false, 135 - }); 136 - }; 137 - 138 - const markMutation = useMutation({ 139 - ...moviesControllerMarkWatchedMutation(), 140 - onSuccess: () => { 141 - queryClient.invalidateQueries({ 142 - queryKey: moviesControllerGetUserMoviesQueryKey({ 143 - path: { userDid: user?.did || '' }, 144 - }), 145 - }); 146 - queryClient.invalidateQueries({ 147 - queryKey: ['watchHistory', user?.did, movieId], 148 - }); 149 - setShowDateModal(false); 150 - setCustomDate(null); 151 - }, 152 - }); 153 - 154 - const deleteWatchEntryMutation = useMutation({ 155 - ...moviesControllerDeleteWatchHistoryEntryMutation(), 156 - onSuccess: () => { 157 - queryClient.invalidateQueries({ 158 - queryKey: moviesControllerGetUserMoviesQueryKey({ 159 - path: { userDid: user?.did || '' }, 160 - }), 161 - }); 162 - queryClient.invalidateQueries({ 163 - queryKey: ['watchHistory', user?.did, movieId], 164 - }); 165 - }, 166 - }); 167 - 168 - const unmarkMutation = useMutation({ 169 - ...moviesControllerUnmarkWatchedMutation(), 170 - onSuccess: () => { 171 - queryClient.invalidateQueries({ 172 - queryKey: moviesControllerGetUserMoviesQueryKey({ 173 - path: { userDid: user?.did || '' }, 174 - }), 175 - }); 176 - queryClient.invalidateQueries({ 177 - queryKey: ['watchHistory', user?.did, movieId], 178 - }); 179 - }, 180 - }); 181 - 182 - const handleMarkWatchedNow = () => { 183 - if (!user) { 184 - router.push('/login'); 185 - return; 186 - } 187 - 188 - markMutation.mutate({ 189 - body: { movieId }, 190 - }); 191 - }; 192 - 193 - const handleMarkWatchedWithDate = () => { 194 - if (!user) { 195 - router.push('/login'); 196 - return; 197 - } 198 - 199 - markMutation.mutate({ 200 - body: { 201 - movieId, 202 - watchedAt: customDate ? customDate.toISOString() : undefined, 203 - }, 204 - }); 205 - }; 206 - 207 - const handleUnmarkWatched = () => { 208 - unmarkMutation.mutate({ 209 - path: { movieId }, 210 - query: { mode: 'all' }, 211 - }); 212 - }; 213 - 214 - const openDateModal = () => { 215 - setCustomDate(new Date()); 216 - setShowDateModal(true); 217 - }; 218 - 219 - const isPending = 220 - markMutation.isPending && markMutation.variables?.body?.movieId === movieId; 221 - 222 - const releaseYear = movie?.release_date 223 - ? new Date(movie.release_date).getFullYear() 224 - : null; 225 - 226 - const backdropUrl = movie?.backdrop_path 227 - ? `https://image.tmdb.org/t/p/w1280${movie.backdrop_path}` 228 - : null; 229 - 230 - const posterUrl = movie?.poster_path 231 - ? `https://image.tmdb.org/t/p/w500${movie.poster_path}` 232 - : null; 233 - 234 - if (isMovieLoading) { 235 - return ( 236 - <View 237 - className="flex-1 justify-center items-center" 238 - style={{ backgroundColor: '#030712' }} 239 - > 240 - <ActivityIndicator size="large" color={colors.primary} /> 241 - </View> 242 - ); 243 - } 244 - 245 - return ( 246 - <> 247 - <ScrollView 248 - className="flex-1 bg-gray-950" 249 - contentContainerStyle={{ paddingBottom: 32 }} 250 - > 251 - <View className="relative"> 252 - {backdropUrl ? ( 253 - <Image 254 - source={{ uri: backdropUrl }} 255 - className={`w-full ${backdropHeight}`} 256 - resizeMode="cover" 257 - /> 258 - ) : ( 259 - <View 260 - className={`w-full ${backdropHeight}`} 261 - style={{ 262 - backgroundColor: colors.muted, 263 - }} 264 - /> 265 - )} 266 - 267 - <TouchableOpacity 268 - onPress={() => router.back()} 269 - className="absolute top-12 left-4 p-2 rounded-full bg-black/50" 270 - activeOpacity={0.8} 271 - > 272 - <Ionicons name="arrow-back" size={24} color="#f9fafb" /> 273 - </TouchableOpacity> 274 - 275 - <View className="absolute -bottom-16 left-4 flex-row items-end"> 276 - <View 277 - className="rounded-lg overflow-hidden shadow-lg" 278 - style={{ 279 - shadowColor: colors.primary, 280 - shadowOffset: { width: 0, height: 4 }, 281 - shadowOpacity: 0.4, 282 - shadowRadius: 8, 283 - elevation: 8, 284 - }} 285 - > 286 - {posterUrl ? ( 287 - <Image 288 - source={{ uri: posterUrl }} 289 - className="w-28 h-40" 290 - resizeMode="cover" 291 - /> 292 - ) : ( 293 - <View className="w-28 h-40 bg-gray-900 justify-center items-center"> 294 - <Text className="text-gray-600 text-xs">No poster</Text> 295 - </View> 296 - )} 297 - </View> 298 - 299 - <View className="ml-4 mb-4 flex-1"> 300 - <Text 301 - className="text-2xl font-bold text-gray-50" 302 - style={{ textShadowColor: colors.primary, textShadowRadius: 8 }} 303 - numberOfLines={2} 304 - adjustsFontSizeToFit={true} 305 - minimumFontScale={0.7} 306 - > 307 - {movie?.title || title} 308 - </Text> 309 - <View className="flex-row items-center mt-2" style={{ gap: 12 }}> 310 - {!!releaseYear && ( 311 - <View className="flex-row items-center"> 312 - <Ionicons 313 - name="calendar-outline" 314 - size={14} 315 - color={colors.accent} 316 - /> 317 - <Text className="text-gray-400 text-sm ml-1"> 318 - {releaseYear} 319 - </Text> 320 - </View> 321 - )} 322 - {movie?.runtime && ( 323 - <TouchableOpacity 324 - onPress={() => setShowHours(!showHours)} 325 - activeOpacity={0.8} 326 - className="flex-row items-center" 327 - > 328 - <Ionicons 329 - name="time-outline" 330 - size={14} 331 - color={colors.accent} 332 - /> 333 - <Text className="text-gray-400 text-sm ml-1"> 334 - {formatRuntime(movie.runtime, showHours)} 335 - </Text> 336 - </TouchableOpacity> 337 - )} 338 - </View> 339 - </View> 340 - </View> 341 - </View> 342 - 343 - <View className="mt-20 px-4"> 344 - <View className="mb-6" style={{ gap: 12 }}> 345 - {user ? ( 346 - isWatched ? ( 347 - <> 348 - <TouchableOpacity 349 - onPress={handleMarkWatchedNow} 350 - disabled={isPending} 351 - activeOpacity={0.8} 352 - className="rounded-xl py-4 px-6 items-center justify-center" 353 - style={{ 354 - backgroundColor: colors.primary, 355 - opacity: isPending ? 0.7 : 1, 356 - }} 357 - > 358 - {isPending ? ( 359 - <ActivityIndicator color="#f9fafb" /> 360 - ) : ( 361 - <View className="flex-row items-center"> 362 - <Ionicons name="refresh" size={20} color="#f9fafb" /> 363 - <Text className="text-white font-semibold text-lg ml-2"> 364 - Watch Now 365 - </Text> 366 - </View> 367 - )} 368 - </TouchableOpacity> 369 - 370 - <TouchableOpacity 371 - onPress={openDateModal} 372 - activeOpacity={0.8} 373 - className="rounded-xl py-3 px-6 items-center justify-center border border-gray-700" 374 - > 375 - <View className="flex-row items-center"> 376 - <Ionicons name="calendar" size={18} color="#9ca3af" /> 377 - <Text className="text-gray-400 font-medium ml-2"> 378 - Watch on Different Date 379 - </Text> 380 - </View> 381 - </TouchableOpacity> 382 - </> 383 - ) : ( 384 - <> 385 - <TouchableOpacity 386 - onPress={handleMarkWatchedNow} 387 - disabled={isPending} 388 - activeOpacity={0.8} 389 - className="rounded-xl py-4 px-6 items-center justify-center" 390 - style={{ 391 - backgroundColor: colors.primary, 392 - opacity: isPending ? 0.7 : 1, 393 - }} 394 - > 395 - {isPending ? ( 396 - <ActivityIndicator color="#f9fafb" /> 397 - ) : ( 398 - <View className="flex-row items-center"> 399 - <Ionicons name="add" size={20} color="#f9fafb" /> 400 - <Text className="text-white font-semibold text-lg ml-2"> 401 - Add to Shelf 402 - </Text> 403 - </View> 404 - )} 405 - </TouchableOpacity> 406 - 407 - <TouchableOpacity 408 - onPress={openDateModal} 409 - activeOpacity={0.8} 410 - className="rounded-xl py-3 px-6 items-center justify-center border border-gray-700" 411 - > 412 - <View className="flex-row items-center"> 413 - <Ionicons name="calendar" size={18} color="#9ca3af" /> 414 - <Text className="text-gray-400 font-medium ml-2"> 415 - Watch on Different Date 416 - </Text> 417 - </View> 418 - </TouchableOpacity> 419 - </> 420 - ) 421 - ) : ( 422 - <TouchableOpacity 423 - onPress={() => router.push('/login')} 424 - activeOpacity={0.8} 425 - className="rounded-xl py-4 px-6 items-center justify-center" 426 - style={{ backgroundColor: colors.primary }} 427 - > 428 - <Text className="text-white font-semibold text-lg"> 429 - Sign in to Track 430 - </Text> 431 - </TouchableOpacity> 432 - )} 433 - </View> 434 - 435 - {isWatched && ( 436 - <View className="mb-6 p-4 bg-gray-900/50 rounded-xl border border-gray-800"> 437 - <View className="flex-row items-center mb-2"> 438 - <Ionicons name="checkmark-circle" size={20} color="#22c55e" /> 439 - <Text className="text-green-500 font-semibold ml-2"> 440 - On Your Shelf 441 - </Text> 442 - </View> 443 - {formattedWatchedDate && ( 444 - <View className="flex-row items-center"> 445 - <Text className="text-sm text-gray-400"> 446 - Watched on {formattedWatchedDate} 447 - </Text> 448 - {watchHistory && watchHistory.length > 1 && ( 449 - <View className="ml-2"> 450 - <Badge variant="secondary"> 451 - {watchHistory.length} watches 452 - </Badge> 453 - </View> 454 - )} 455 - </View> 456 - )} 457 - {watchHistory && watchHistory.length > 1 && ( 458 - <TouchableOpacity 459 - onPress={() => setShowHistoryDialog(true)} 460 - className="mt-3 flex-row items-center" 461 - activeOpacity={0.7} 462 - > 463 - <Ionicons name="eye" size={16} color="#9ca3af" /> 464 - <Text className="text-sm text-gray-400 ml-2"> 465 - View all watches 466 - </Text> 467 - </TouchableOpacity> 468 - )} 469 - 470 - {watchHistory && watchHistory.length === 1 && ( 471 - <TouchableOpacity 472 - onPress={handleUnmarkWatched} 473 - disabled={unmarkMutation.isPending} 474 - className="mt-3 flex-row items-center" 475 - activeOpacity={0.7} 476 - > 477 - {unmarkMutation.isPending ? ( 478 - <ActivityIndicator size="small" color="#ef4444" /> 479 - ) : ( 480 - <> 481 - <Ionicons name="trash-outline" size={16} color="#ef4444" /> 482 - <Text className="text-sm text-red-400 ml-2"> 483 - Remove from shelf 484 - </Text> 485 - </> 486 - )} 487 - </TouchableOpacity> 488 - )} 489 - </View> 490 - )} 491 - 492 - {movie?.overview && ( 493 - <View className="mb-6"> 494 - <Text 495 - className="text-xl font-semibold mb-2" 496 - style={{ color: colors.primary }} 497 - > 498 - Overview 499 - </Text> 500 - <Text className="text-gray-300 text-base leading-relaxed"> 501 - {movie.overview} 502 - </Text> 503 - </View> 504 - )} 505 - 506 - <View className="flex-row flex-wrap gap-3 mb-6"> 507 - {movie?.release_date && ( 508 - <View 509 - className="bg-gray-900 rounded-lg p-3" 510 - style={{ flex: 1, minWidth: '45%' }} 511 - > 512 - <Text className="text-gray-500 text-xs mb-1">Release Date</Text> 513 - <Text style={{ color: colors.accent }} className="font-medium"> 514 - {new Date(movie.release_date).toLocaleDateString('en-US', { 515 - year: 'numeric', 516 - month: 'short', 517 - day: 'numeric', 518 - })} 519 - </Text> 520 - </View> 521 - )} 522 - 523 - {movie?.runtime && ( 524 - <TouchableOpacity 525 - onPress={() => setShowHours(!showHours)} 526 - activeOpacity={0.8} 527 - className="bg-gray-900 rounded-lg p-3" 528 - style={{ flex: 1, minWidth: '45%' }} 529 - > 530 - <Text className="text-gray-500 text-xs mb-1">Runtime</Text> 531 - <Text style={{ color: colors.accent }} className="font-medium"> 532 - {formatRuntime(movie.runtime, showHours)} 533 - </Text> 534 - </TouchableOpacity> 535 - )} 536 - 537 - {movie?.vote_average !== undefined && ( 538 - <View 539 - className="bg-gray-900 rounded-lg p-3" 540 - style={{ flex: 1, minWidth: '45%' }} 541 - > 542 - <Text className="text-gray-500 text-xs mb-1">Rating</Text> 543 - <Text style={{ color: colors.accent }} className="font-medium"> 544 - {movie.vote_average.toFixed(1)}/10 545 - </Text> 546 - </View> 547 - )} 548 - 549 - {movie?.vote_count !== undefined && ( 550 - <View 551 - className="bg-gray-900 rounded-lg p-3" 552 - style={{ flex: 1, minWidth: '45%' }} 553 - > 554 - <Text className="text-gray-500 text-xs mb-1">Votes</Text> 555 - <Text style={{ color: colors.accent }} className="font-medium"> 556 - {movie.vote_count.toLocaleString()} 557 - </Text> 558 - </View> 559 - )} 560 - </View> 561 - 562 - {movie?.genres && movie.genres.length > 0 && ( 563 - <View> 564 - <Text 565 - className="text-xl font-semibold mb-3" 566 - style={{ color: colors.primary }} 567 - > 568 - Genres 569 - </Text> 570 - <View className="flex-row flex-wrap gap-2"> 571 - {movie.genres.map((genre) => ( 572 - <View 573 - key={genre.id} 574 - className="px-3 py-2 rounded-full" 575 - style={{ 576 - backgroundColor: `${colors.primary}20`, 577 - borderWidth: 1, 578 - borderColor: `${colors.primary}40`, 579 - }} 580 - > 581 - <Text style={{ color: colors.accent }} className="text-sm"> 582 - {genre.name} 583 - </Text> 584 - </View> 585 - ))} 586 - </View> 587 - </View> 588 - )} 589 - </View> 590 - </ScrollView> 591 - 592 - <Dialog open={showHistoryDialog} onOpenChange={setShowHistoryDialog}> 593 - <DialogContent> 594 - <DialogClose onPress={() => setShowHistoryDialog(false)} /> 595 - <DialogHeader> 596 - <DialogTitle className="flex-row items-center gap-2"> 597 - <Ionicons name="time" size={20} color="#a855f7" /> 598 - Watch History 599 - </DialogTitle> 600 - <DialogDescription> 601 - All the times you&apos;ve watched {movie?.title} 602 - </DialogDescription> 603 - </DialogHeader> 604 - <DialogScrollContent> 605 - <View style={{ gap: 12 }}> 606 - {watchHistory && watchHistory.length > 0 ? ( 607 - watchHistory.map((watch) => ( 608 - <View 609 - key={watch.id} 610 - className="flex-row items-center gap-3 p-3 rounded-lg bg-gray-800/50" 611 - > 612 - <View className="flex-1"> 613 - <Text className="text-sm font-medium text-white"> 614 - {formatWatchDate(watch.watchedDate)} 615 - </Text> 616 - </View> 617 - <TouchableOpacity 618 - onPress={() => 619 - deleteWatchEntryMutation.mutate({ 620 - path: { trackedMovieId: watch.id }, 621 - }) 622 - } 623 - disabled={deleteWatchEntryMutation.isPending} 624 - className="p-2 rounded-lg" 625 - activeOpacity={0.7} 626 - > 627 - {deleteWatchEntryMutation.isPending && 628 - deleteWatchEntryMutation.variables?.path?.trackedMovieId === 629 - watch.id ? ( 630 - <ActivityIndicator size="small" color="#9ca3af" /> 631 - ) : ( 632 - <Ionicons name="trash-outline" size={18} color="#ef4444" /> 633 - )} 634 - </TouchableOpacity> 635 - </View> 636 - )) 637 - ) : ( 638 - <View className="items-center py-8"> 639 - <Text className="text-gray-500"> 640 - No watch history found 641 - </Text> 642 - </View> 643 - )} 644 - </View> 645 - </DialogScrollContent> 646 - <DialogFooter> 647 - <Button 648 - variant="outline" 649 - onPress={() => setShowHistoryDialog(false)} 650 - > 651 - Close 652 - </Button> 653 - </DialogFooter> 654 - </DialogContent> 655 - </Dialog> 656 - 657 - <Dialog open={showDateModal} onOpenChange={setShowDateModal}> 658 - <DialogContent> 659 - <DialogHeader> 660 - <DialogTitle>When did you watch this?</DialogTitle> 661 - <DialogDescription> 662 - Select the date and time you watched {movie?.title} 663 - </DialogDescription> 664 - </DialogHeader> 665 - <View className="py-4" style={{ gap: 16 }}> 666 - <TouchableOpacity 667 - onPress={() => setShowDatePicker(true)} 668 - className="flex-row items-center justify-between p-4 bg-gray-800 rounded-lg" 669 - activeOpacity={0.7} 670 - > 671 - <Text className="text-gray-300">Date & Time</Text> 672 - <Text className="text-white font-medium"> 673 - {customDate 674 - ? customDate.toLocaleString('en-US', { 675 - year: 'numeric', 676 - month: 'short', 677 - day: 'numeric', 678 - hour: '2-digit', 679 - minute: '2-digit', 680 - hour12: false, 681 - }) 682 - : 'Select date and time'} 683 - </Text> 684 - </TouchableOpacity> 685 - </View> 686 - <DialogFooter> 687 - <Button 688 - variant="outline" 689 - onPress={() => setShowDateModal(false)} 690 - > 691 - Cancel 692 - </Button> 693 - <Button 694 - onPress={handleMarkWatchedWithDate} 695 - isLoading={markMutation.isPending} 696 - > 697 - Add Play 698 - </Button> 699 - </DialogFooter> 700 - </DialogContent> 701 - </Dialog> 702 - 703 - <DateTimePickerModal 704 - visible={showDatePicker} 705 - date={customDate} 706 - onConfirm={(date) => { 707 - setShowDatePicker(false); 708 - setCustomDate(date); 709 - }} 710 - onCancel={() => setShowDatePicker(false)} 711 - /> 712 - </> 713 - ); 714 - }
-311
apps/mobile/app/search.tsx
··· 1 - import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; 2 - import { 3 - authControllerMeOptions, 4 - moviesControllerGetUserMoviesOptions, 5 - moviesControllerGetUserMoviesQueryKey, 6 - moviesControllerSearchMoviesOptions, 7 - moviesControllerMarkWatchedMutation, 8 - moviesControllerUnmarkWatchedMutation, 9 - } from '@opnshelf/api'; 10 - import { Ionicons } from '@expo/vector-icons'; 11 - import { 12 - ActivityIndicator, 13 - FlatList, 14 - Image, 15 - Text, 16 - TextInput, 17 - TouchableOpacity, 18 - View, 19 - useWindowDimensions, 20 - } from 'react-native'; 21 - import { useCallback, useEffect, useRef, useState } from 'react'; 22 - import { useRouter, useLocalSearchParams } from 'expo-router'; 23 - import { useNumColumns } from '@/utils'; 24 - import { Skeleton } from '@/components/ui/skeleton'; 25 - 26 - const DEBOUNCE_MS = 300; 27 - const POSTER_BASE = 'https://image.tmdb.org/t/p/w342'; 28 - 29 - type MovieItem = { 30 - id: number; 31 - title: string; 32 - poster_path?: string; 33 - release_date?: string; 34 - }; 35 - 36 - function MovieCard({ 37 - movie, 38 - isWatched, 39 - onMarkWatched, 40 - onUnmarkWatched, 41 - isLoading, 42 - onPress, 43 - cardWidth, 44 - }: { 45 - movie: MovieItem; 46 - isWatched: boolean; 47 - onMarkWatched: () => void; 48 - onUnmarkWatched: () => void; 49 - isLoading: boolean; 50 - onPress: () => void; 51 - cardWidth: number; 52 - }) { 53 - return ( 54 - <TouchableOpacity 55 - onPress={onPress} 56 - style={{ width: cardWidth }} 57 - activeOpacity={0.8} 58 - > 59 - <View className="aspect-2/3 bg-gray-900 rounded-lg overflow-hidden mb-2 relative"> 60 - {movie.poster_path ? ( 61 - <Image 62 - source={{ uri: `${POSTER_BASE}${movie.poster_path}` }} 63 - className="w-full h-full" 64 - resizeMode="cover" 65 - /> 66 - ) : ( 67 - <View className="flex-1 justify-center items-center"> 68 - <Text className="text-gray-500 text-xs">No poster</Text> 69 - </View> 70 - )} 71 - <TouchableOpacity 72 - onPress={(e) => { 73 - e.stopPropagation(); 74 - if (isWatched) { 75 - onUnmarkWatched(); 76 - } else { 77 - onMarkWatched(); 78 - } 79 - }} 80 - disabled={isLoading} 81 - className={`absolute top-2 right-2 p-2 rounded-full ${ 82 - isWatched ? 'bg-green-600' : 'bg-violet-600' 83 - }`} 84 - activeOpacity={0.7} 85 - > 86 - {isLoading ? ( 87 - <ActivityIndicator size="small" color="#fff" /> 88 - ) : isWatched ? ( 89 - <Ionicons name="checkmark" size={16} color="#fff" /> 90 - ) : ( 91 - <Ionicons name="add" size={16} color="#fff" /> 92 - )} 93 - </TouchableOpacity> 94 - </View> 95 - <Text className="text-sm font-semibold text-gray-50 mb-1" numberOfLines={2}> 96 - {movie.title} 97 - </Text> 98 - {movie.release_date ? ( 99 - <Text className="text-xs text-gray-500"> 100 - {movie.release_date.split('-')[0]} 101 - </Text> 102 - ) : null} 103 - </TouchableOpacity> 104 - ); 105 - } 106 - 107 - export default function SearchScreen() { 108 - const queryClient = useQueryClient(); 109 - const router = useRouter(); 110 - const params = useLocalSearchParams<{ q?: string }>(); 111 - const initialQ = params.q ?? ''; 112 - const [query, setQuery] = useState(initialQ); 113 - const [searchQuery, setSearchQuery] = useState(initialQ); 114 - const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null); 115 - const { width } = useWindowDimensions(); 116 - const numColumns = useNumColumns('search'); 117 - const flatListKey = `search-grid-${numColumns}-${width}`; 118 - 119 - const cardWidth = (width - 32 - (numColumns - 1) * 16) / numColumns; 120 - 121 - useEffect(() => { 122 - if (debounceRef.current) clearTimeout(debounceRef.current); 123 - const trimmed = query.trim(); 124 - if (trimmed !== searchQuery) { 125 - debounceRef.current = setTimeout( 126 - () => setSearchQuery(trimmed), 127 - DEBOUNCE_MS, 128 - ); 129 - } 130 - return () => { 131 - if (debounceRef.current) clearTimeout(debounceRef.current); 132 - }; 133 - }, [query, searchQuery]); 134 - 135 - const { data: user } = useQuery({ 136 - ...authControllerMeOptions(), 137 - staleTime: 5 * 60 * 1000, 138 - retry: false, 139 - }); 140 - 141 - const { data: trackedMovies } = useQuery({ 142 - ...moviesControllerGetUserMoviesOptions({ 143 - path: { userDid: user?.did || '' }, 144 - }), 145 - enabled: !!user?.did, 146 - }); 147 - 148 - const watchedMovieIds = new Set( 149 - trackedMovies?.map((t: { movieId: string }) => t.movieId) ?? [], 150 - ); 151 - 152 - const markMutation = useMutation({ 153 - ...moviesControllerMarkWatchedMutation(), 154 - onSuccess: () => { 155 - queryClient.invalidateQueries({ 156 - queryKey: moviesControllerGetUserMoviesQueryKey({ 157 - path: { userDid: user?.did || '' }, 158 - }), 159 - }); 160 - }, 161 - }); 162 - 163 - const unmarkMutation = useMutation({ 164 - ...moviesControllerUnmarkWatchedMutation(), 165 - onSuccess: () => { 166 - queryClient.invalidateQueries({ 167 - queryKey: moviesControllerGetUserMoviesQueryKey({ 168 - path: { userDid: user?.did || '' }, 169 - }), 170 - }); 171 - }, 172 - }); 173 - 174 - const { data, isLoading, error } = useQuery({ 175 - ...moviesControllerSearchMoviesOptions({ 176 - query: { query: searchQuery }, 177 - }), 178 - enabled: searchQuery.length > 0, 179 - }); 180 - 181 - const results = data?.results ?? []; 182 - const totalResults = data?.total_results ?? 0; 183 - 184 - const handleMarkWatched = useCallback( 185 - (movieId: string) => { 186 - if (!user) { 187 - router.push({ pathname: '/login', params: { redirect: 'search' } }); 188 - return; 189 - } 190 - markMutation.mutate({ body: { movieId } }); 191 - }, 192 - [user, router, markMutation], 193 - ); 194 - 195 - const handleUnmarkWatched = useCallback( 196 - (movieId: string) => { 197 - unmarkMutation.mutate({ path: { movieId } }); 198 - }, 199 - [unmarkMutation], 200 - ); 201 - 202 - const handleNavigateToDetail = useCallback( 203 - (movie: MovieItem) => { 204 - router.push({ 205 - pathname: '/movie/[movieId]/[title]', 206 - params: { movieId: String(movie.id), title: movie.title }, 207 - }); 208 - }, 209 - [router], 210 - ); 211 - 212 - const renderItem = useCallback( 213 - ({ item }: { item: MovieItem }) => { 214 - const movieId = String(item.id); 215 - const isWatched = watchedMovieIds.has(movieId); 216 - const isLoading = 217 - (markMutation.isPending && markMutation.variables?.body?.movieId === movieId) || 218 - (unmarkMutation.isPending && unmarkMutation.variables?.path?.movieId === movieId); 219 - 220 - return ( 221 - <MovieCard 222 - movie={item} 223 - isWatched={isWatched} 224 - onMarkWatched={() => handleMarkWatched(movieId)} 225 - onUnmarkWatched={() => handleUnmarkWatched(movieId)} 226 - isLoading={isLoading} 227 - onPress={() => handleNavigateToDetail(item)} 228 - cardWidth={cardWidth} 229 - /> 230 - ); 231 - }, 232 - [watchedMovieIds, markMutation, unmarkMutation, handleMarkWatched, handleUnmarkWatched, handleNavigateToDetail, cardWidth], 233 - ); 234 - 235 - const keyExtractor = useCallback((item: MovieItem) => String(item.id), []); 236 - 237 - return ( 238 - <View className="flex-1 bg-gray-950 px-4 pt-12 pb-6"> 239 - <Text className="text-3xl font-bold text-gray-50 mb-6"> 240 - Search Movies 241 - </Text> 242 - 243 - <View className="flex-row items-center bg-gray-900 border border-gray-800 rounded-lg mb-6"> 244 - <View className="ml-4"> 245 - <Ionicons name="search" size={20} color="#9ca3af" /> 246 - </View> 247 - <TextInput 248 - className="flex-1 py-3 px-3 pl-2 text-base text-gray-50" 249 - value={query} 250 - onChangeText={setQuery} 251 - placeholder="Search for a movie..." 252 - placeholderTextColor="#6b7280" 253 - autoCapitalize="none" 254 - autoCorrect={false} 255 - /> 256 - </View> 257 - 258 - {isLoading && ( 259 - <View className="flex-1"> 260 - <FlatList 261 - data={[...Array(numColumns * 3)]} 262 - renderItem={() => ( 263 - <View style={{ width: cardWidth }}> 264 - <Skeleton className="aspect-2/3 rounded-lg mb-2" /> 265 - <Skeleton className="h-4 w-3/4 mb-1" /> 266 - <Skeleton className="h-3 w-1/2" /> 267 - </View> 268 - )} 269 - keyExtractor={(_, index) => `search-skeleton-${index}`} 270 - numColumns={numColumns} 271 - columnWrapperClassName="gap-4 mb-4" 272 - contentContainerClassName="pb-6" 273 - /> 274 - </View> 275 - )} 276 - 277 - {error && ( 278 - <View className="bg-red-950/20 border border-red-900/50 rounded-lg p-3 mb-6"> 279 - <Text className="text-red-400"> 280 - Error: {(error as Error).message} 281 - </Text> 282 - </View> 283 - )} 284 - 285 - {data && results.length > 0 && ( 286 - <> 287 - <Text className="text-gray-400 mb-4"> 288 - Found {totalResults.toLocaleString()} results 289 - </Text> 290 - <FlatList 291 - data={results} 292 - renderItem={renderItem} 293 - keyExtractor={keyExtractor} 294 - numColumns={numColumns} 295 - columnWrapperClassName="gap-4 mb-4" 296 - contentContainerClassName="pb-6" 297 - key={flatListKey} 298 - /> 299 - </> 300 - )} 301 - 302 - {data && results.length === 0 && searchQuery.length > 0 && ( 303 - <View className="flex-1 justify-center py-12"> 304 - <Text className="text-gray-400 text-lg text-center"> 305 - No results found for &quot;{searchQuery}&quot; 306 - </Text> 307 - </View> 308 - )} 309 - </View> 310 - ); 311 - }
-413
apps/mobile/app/shelf.tsx
··· 1 - import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; 2 - import { authControllerMeOptions, moviesControllerGetUserMoviesOptions, moviesControllerGetUserMoviesQueryKey, moviesControllerUnmarkWatchedMutation } from '@opnshelf/api'; 3 - import { Ionicons } from '@expo/vector-icons'; 4 - import { 5 - ActivityIndicator, 6 - FlatList, 7 - Image, 8 - Text, 9 - TouchableOpacity, 10 - View, 11 - useWindowDimensions, 12 - } from 'react-native'; 13 - import { useCallback } from 'react'; 14 - import { useRouter } from 'expo-router'; 15 - import { useNumColumns } from '@/utils'; 16 - import { Skeleton } from '@/components/ui/skeleton'; 17 - import { Badge } from '@/components/ui/badge'; 18 - import { 19 - Card, 20 - CardHeader, 21 - CardTitle, 22 - CardDescription, 23 - CardContent, 24 - } from '@/components/ui/card'; 25 - import { Button } from '@/components/ui/button'; 26 - 27 - const POSTER_BASE = 'https://image.tmdb.org/t/p/w342'; 28 - 29 - type TrackedMovie = { 30 - id: string; 31 - movieId: string; 32 - watchedDate?: string; 33 - watchCount?: number; 34 - movie: { 35 - title: string; 36 - posterPath?: string; 37 - releaseYear?: number; 38 - }; 39 - }; 40 - 41 - function MovieCard({ 42 - tracked, 43 - onRemove, 44 - isRemoving, 45 - onPress, 46 - }: { 47 - tracked: TrackedMovie; 48 - onRemove: () => void; 49 - isRemoving: boolean; 50 - onPress: () => void; 51 - }) { 52 - const formattedWatchedDate = tracked.watchedDate 53 - ? new Date(tracked.watchedDate).toLocaleString('en-US', { 54 - month: 'short', 55 - day: 'numeric', 56 - year: 'numeric', 57 - hour: '2-digit', 58 - minute: '2-digit', 59 - hour12: false, 60 - }) 61 - : null; 62 - 63 - return ( 64 - <TouchableOpacity 65 - onPress={onPress} 66 - className="flex-row bg-gray-900/50 rounded-lg overflow-hidden border border-gray-800/50" 67 - activeOpacity={0.8} 68 - > 69 - <View className="w-20 aspect-2/3 bg-gray-900"> 70 - {tracked.movie.posterPath ? ( 71 - <Image 72 - source={{ uri: `${POSTER_BASE}${tracked.movie.posterPath}` }} 73 - className="w-full h-full" 74 - resizeMode="cover" 75 - /> 76 - ) : ( 77 - <View className="flex-1 justify-center items-center"> 78 - <Text className="text-gray-600 text-xs">No poster</Text> 79 - </View> 80 - )} 81 - </View> 82 - 83 - <View className="flex-1 p-3 justify-between"> 84 - <View> 85 - <Text className="text-base font-semibold text-gray-50 mb-1" numberOfLines={2}> 86 - {tracked.movie.title} 87 - </Text> 88 - <View className="flex-row items-center gap-2"> 89 - {tracked.movie.releaseYear && ( 90 - <Text className="text-sm text-gray-400">{tracked.movie.releaseYear}</Text> 91 - )} 92 - {formattedWatchedDate && ( 93 - <> 94 - <Text className="text-gray-600">•</Text> 95 - <View className="flex-row items-center"> 96 - <Ionicons name="checkmark-circle" size={12} color="#22c55e" /> 97 - <Text className="text-sm text-green-500 ml-1">{formattedWatchedDate}</Text> 98 - </View> 99 - {tracked.watchCount && tracked.watchCount > 1 && ( 100 - <Badge variant="secondary" className="ml-2"> 101 - {tracked.watchCount}× 102 - </Badge> 103 - )} 104 - </> 105 - )} 106 - </View> 107 - </View> 108 - 109 - <View className="flex-row items-center"> 110 - <TouchableOpacity 111 - onPress={(e) => { 112 - e.stopPropagation(); 113 - onRemove(); 114 - }} 115 - disabled={isRemoving} 116 - className="flex-row items-center gap-1 px-3 py-1.5 bg-red-600/90 rounded-full" 117 - activeOpacity={0.7} 118 - > 119 - {isRemoving ? ( 120 - <ActivityIndicator size="small" color="#fff" /> 121 - ) : ( 122 - <> 123 - <Ionicons name="trash-outline" size={14} color="#fff" /> 124 - <Text className="text-white text-sm font-medium">Remove</Text> 125 - </> 126 - )} 127 - </TouchableOpacity> 128 - </View> 129 - </View> 130 - </TouchableOpacity> 131 - ); 132 - } 133 - 134 - function GridMovieCard({ 135 - tracked, 136 - onRemove, 137 - isRemoving, 138 - onPress, 139 - }: { 140 - tracked: TrackedMovie; 141 - onRemove: () => void; 142 - isRemoving: boolean; 143 - onPress: () => void; 144 - }) { 145 - const formattedWatchedDate = tracked.watchedDate 146 - ? new Date(tracked.watchedDate).toLocaleString('en-US', { 147 - month: 'short', 148 - day: 'numeric', 149 - year: 'numeric', 150 - hour: '2-digit', 151 - minute: '2-digit', 152 - hour12: false, 153 - }) 154 - : null; 155 - 156 - return ( 157 - <TouchableOpacity 158 - onPress={onPress} 159 - className="flex-1" 160 - activeOpacity={0.8} 161 - > 162 - <View className="aspect-2/3 bg-gray-900 rounded-lg overflow-hidden mb-2 relative"> 163 - {tracked.movie.posterPath ? ( 164 - <Image 165 - source={{ uri: `${POSTER_BASE}${tracked.movie.posterPath}` }} 166 - className="w-full h-full" 167 - resizeMode="cover" 168 - /> 169 - ) : ( 170 - <View className="flex-1 justify-center items-center"> 171 - <Text className="text-gray-600 text-xs">No poster</Text> 172 - </View> 173 - )} 174 - <TouchableOpacity 175 - onPress={(e) => { 176 - e.stopPropagation(); 177 - onRemove(); 178 - }} 179 - disabled={isRemoving} 180 - className="absolute top-2 right-2 p-2 rounded-full bg-red-600/90" 181 - activeOpacity={0.7} 182 - > 183 - {isRemoving ? ( 184 - <ActivityIndicator size="small" color="#fff" /> 185 - ) : ( 186 - <Ionicons name="trash-outline" size={14} color="#fff" /> 187 - )} 188 - </TouchableOpacity> 189 - </View> 190 - <Text className="text-sm font-semibold text-gray-50 mb-1" numberOfLines={2}> 191 - {tracked.movie.title} 192 - </Text> 193 - <View className="flex-row items-center gap-1"> 194 - {tracked.movie.releaseYear && ( 195 - <Text className="text-xs text-gray-400">{tracked.movie.releaseYear}</Text> 196 - )} 197 - {formattedWatchedDate && ( 198 - <> 199 - <Text className="text-gray-600 text-xs">•</Text> 200 - <Ionicons name="checkmark-circle" size={10} color="#22c55e" /> 201 - {tracked.watchCount && tracked.watchCount > 1 && ( 202 - <Badge variant="secondary" className="ml-1"> 203 - {tracked.watchCount}× 204 - </Badge> 205 - )} 206 - </> 207 - )} 208 - </View> 209 - </TouchableOpacity> 210 - ); 211 - } 212 - 213 - export default function ShelfScreen() { 214 - const queryClient = useQueryClient(); 215 - const router = useRouter(); 216 - const { width } = useWindowDimensions(); 217 - const numColumns = useNumColumns('shelf'); 218 - const isGrid = numColumns > 1; 219 - const flatListKey = `shelf-${numColumns}-${width}`; 220 - 221 - const { data: user, isLoading: isAuthLoading } = useQuery({ 222 - ...authControllerMeOptions(), 223 - staleTime: 5 * 60 * 1000, 224 - retry: false, 225 - }); 226 - 227 - const { data: trackedMovies, isLoading: isMoviesLoading } = useQuery({ 228 - ...moviesControllerGetUserMoviesOptions({ 229 - path: { userDid: user?.did || '' }, 230 - }), 231 - enabled: !!user?.did, 232 - }); 233 - 234 - const unmarkMutation = useMutation({ 235 - ...moviesControllerUnmarkWatchedMutation(), 236 - onSuccess: () => { 237 - queryClient.invalidateQueries({ 238 - queryKey: moviesControllerGetUserMoviesQueryKey({ 239 - path: { userDid: user?.did || '' }, 240 - }), 241 - }); 242 - }, 243 - }); 244 - 245 - const handleNavigateToDetail = useCallback( 246 - (tracked: TrackedMovie) => { 247 - router.push({ 248 - pathname: '/movie/[movieId]/[title]', 249 - params: { movieId: tracked.movieId, title: tracked.movie.title }, 250 - }); 251 - }, 252 - [router], 253 - ); 254 - 255 - const renderItem = useCallback( 256 - ({ item }: { item: TrackedMovie }) => { 257 - if (isGrid) { 258 - return ( 259 - <GridMovieCard 260 - tracked={item} 261 - onRemove={() => unmarkMutation.mutate({ path: { movieId: item.movieId } })} 262 - isRemoving={unmarkMutation.isPending && unmarkMutation.variables?.path?.movieId === item.movieId} 263 - onPress={() => handleNavigateToDetail(item)} 264 - /> 265 - ); 266 - } 267 - return ( 268 - <MovieCard 269 - tracked={item} 270 - onRemove={() => unmarkMutation.mutate({ path: { movieId: item.movieId } })} 271 - isRemoving={unmarkMutation.isPending && unmarkMutation.variables?.path?.movieId === item.movieId} 272 - onPress={() => handleNavigateToDetail(item)} 273 - /> 274 - ); 275 - }, 276 - [unmarkMutation, handleNavigateToDetail, isGrid], 277 - ); 278 - 279 - const keyExtractor = useCallback((item: TrackedMovie) => item.id, []); 280 - 281 - if (isAuthLoading) { 282 - return ( 283 - <View className="flex-1 bg-gray-950 px-4 pt-12 pb-6"> 284 - <View className="flex-row items-center gap-3 mb-8"> 285 - <Skeleton className="w-8 h-8 rounded" /> 286 - <Skeleton className="w-40 h-8 rounded" /> 287 - </View> 288 - <View className={`flex-row flex-wrap gap-4`}> 289 - {[...Array(10)].map((_, index) => ( 290 - <View key={`auth-skeleton-${index}`} className={`${isGrid ? 'flex-1 min-w-0' : 'w-full'}`}> 291 - {isGrid ? ( 292 - <> 293 - <Skeleton className="aspect-2/3 rounded-lg mb-2" /> 294 - <Skeleton className="h-4 w-3/4 mb-1" /> 295 - <Skeleton className="h-3 w-1/2" /> 296 - </> 297 - ) : ( 298 - <View className="flex-row"> 299 - <Skeleton className="w-20 aspect-2/3 rounded-lg" /> 300 - <View className="flex-1 ml-3 justify-between"> 301 - <Skeleton className="h-5 w-3/4 mb-2" /> 302 - <Skeleton className="h-4 w-1/2" /> 303 - </View> 304 - </View> 305 - )} 306 - </View> 307 - ))} 308 - </View> 309 - </View> 310 - ); 311 - } 312 - 313 - if (!user) { 314 - return ( 315 - <View className="flex-1 bg-gray-950 px-4 pt-12 pb-6"> 316 - <View className="flex-1 justify-center items-center"> 317 - <Card className="w-full max-w-md"> 318 - <CardHeader className="items-center"> 319 - <Ionicons name="book" size={64} color="#a855f7" className="mb-4" /> 320 - <CardTitle className="text-3xl text-center">My Shelf</CardTitle> 321 - <CardDescription className="text-lg text-center"> 322 - Sign in to track movies you&apos;ve watched 323 - </CardDescription> 324 - </CardHeader> 325 - <CardContent> 326 - <Button 327 - size="lg" 328 - onPress={() => router.push({ pathname: '/login', params: { redirect: 'shelf' } })} 329 - > 330 - <Ionicons name="log-in" size={20} color="#fff" /> 331 - <Text className="text-white font-semibold ml-2">Sign in</Text> 332 - </Button> 333 - </CardContent> 334 - </Card> 335 - </View> 336 - </View> 337 - ); 338 - } 339 - 340 - return ( 341 - <View className="flex-1 bg-gray-950 px-4 pt-12 pb-6"> 342 - <View className="flex-row items-center gap-3 mb-8"> 343 - <Ionicons name="book" size={32} color="#a855f7" /> 344 - <Text className="text-3xl font-bold text-gray-50">My Shelf</Text> 345 - </View> 346 - 347 - {isMoviesLoading && ( 348 - <View className={`flex-row flex-wrap gap-4`}> 349 - {[...Array(10)].map((_, index) => ( 350 - <View key={`movies-skeleton-${index}`} className={`${isGrid ? 'flex-1 min-w-0' : 'w-full'}`}> 351 - {isGrid ? ( 352 - <> 353 - <Skeleton className="aspect-2/3 rounded-lg mb-2" /> 354 - <Skeleton className="h-4 w-3/4 mb-1" /> 355 - <Skeleton className="h-3 w-1/2" /> 356 - </> 357 - ) : ( 358 - <View className="flex-row"> 359 - <Skeleton className="w-20 aspect-2/3 rounded-lg" /> 360 - <View className="flex-1 ml-3 justify-between"> 361 - <Skeleton className="h-5 w-3/4 mb-2" /> 362 - <Skeleton className="h-4 w-1/2" /> 363 - </View> 364 - </View> 365 - )} 366 - </View> 367 - ))} 368 - </View> 369 - )} 370 - 371 - {trackedMovies && trackedMovies.length > 0 && ( 372 - <> 373 - <Text className="text-gray-400 mb-4"> 374 - {trackedMovies.length} movie{trackedMovies.length !== 1 ? 's' : ''}{' '} 375 - watched 376 - </Text> 377 - <FlatList 378 - data={trackedMovies as TrackedMovie[]} 379 - renderItem={renderItem} 380 - keyExtractor={keyExtractor} 381 - numColumns={numColumns} 382 - columnWrapperClassName={isGrid ? "gap-4 mb-4" : undefined} 383 - ItemSeparatorComponent={() => isGrid ? null : <View className="h-4" />} 384 - contentContainerClassName="pb-6" 385 - key={flatListKey} 386 - /> 387 - </> 388 - )} 389 - 390 - {trackedMovies && trackedMovies.length === 0 && ( 391 - <View className="flex-1 justify-center items-center py-12"> 392 - <Card className="w-full max-w-sm"> 393 - <CardHeader className="items-center"> 394 - <Ionicons name="book" size={64} color="#374151" className="mb-4" /> 395 - <CardTitle className="text-2xl text-center">Your shelf is empty</CardTitle> 396 - <CardDescription className="text-center"> 397 - Start tracking movies you&apos;ve watched 398 - </CardDescription> 399 - </CardHeader> 400 - <CardContent> 401 - <Button 402 - onPress={() => router.push('/search')} 403 - > 404 - <Ionicons name="search" size={20} color="#fff" /> 405 - <Text className="text-white font-semibold ml-2">Search for movies</Text> 406 - </Button> 407 - </CardContent> 408 - </Card> 409 - </View> 410 - )} 411 - </View> 412 - ); 413 - }
apps/mobile/assets/adaptive-icon.png

This is a binary file and will not be displayed.

apps/mobile/assets/favicon.png

This is a binary file and will not be displayed.

apps/mobile/assets/icon.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/android-icon-background.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/android-icon-foreground.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/android-icon-monochrome.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/favicon.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/icon.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/partial-react-logo.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/react-logo.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/react-logo@2x.png

This is a binary file and will not be displayed.

apps/mobile/assets/images/react-logo@3x.png

This is a binary file and will not be displayed.

apps/mobile/assets/splash-icon.png apps/mobile/assets/images/splash-icon.png
-6
apps/mobile/babel.config.js
··· 1 - module.exports = function (api) { 2 - api.cache(true); 3 - return { 4 - presets: ['babel-preset-expo'], 5 - }; 6 - };
+25
apps/mobile/components/external-link.tsx
··· 1 + import { Href, Link } from 'expo-router'; 2 + import { openBrowserAsync, WebBrowserPresentationStyle } from 'expo-web-browser'; 3 + import { type ComponentProps } from 'react'; 4 + 5 + type Props = Omit<ComponentProps<typeof Link>, 'href'> & { href: Href & string }; 6 + 7 + export function ExternalLink({ href, ...rest }: Props) { 8 + return ( 9 + <Link 10 + target="_blank" 11 + {...rest} 12 + href={href} 13 + onPress={async (event) => { 14 + if (process.env.EXPO_OS !== 'web') { 15 + // Prevent the default behavior of linking to the default browser on native. 16 + event.preventDefault(); 17 + // Open the link in an in-app browser. 18 + await openBrowserAsync(href, { 19 + presentationStyle: WebBrowserPresentationStyle.AUTOMATIC, 20 + }); 21 + } 22 + }} 23 + /> 24 + ); 25 + }
+18
apps/mobile/components/haptic-tab.tsx
··· 1 + import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs'; 2 + import { PlatformPressable } from '@react-navigation/elements'; 3 + import * as Haptics from 'expo-haptics'; 4 + 5 + export function HapticTab(props: BottomTabBarButtonProps) { 6 + return ( 7 + <PlatformPressable 8 + {...props} 9 + onPressIn={(ev) => { 10 + if (process.env.EXPO_OS === 'ios') { 11 + // Add a soft haptic feedback when pressing down on the tabs. 12 + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); 13 + } 14 + props.onPressIn?.(ev); 15 + }} 16 + /> 17 + ); 18 + }
+19
apps/mobile/components/hello-wave.tsx
··· 1 + import Animated from 'react-native-reanimated'; 2 + 3 + export function HelloWave() { 4 + return ( 5 + <Animated.Text 6 + style={{ 7 + fontSize: 28, 8 + lineHeight: 32, 9 + marginTop: -6, 10 + animationName: { 11 + '50%': { transform: [{ rotate: '25deg' }] }, 12 + }, 13 + animationIterationCount: 4, 14 + animationDuration: '300ms', 15 + }}> 16 + 👋 17 + </Animated.Text> 18 + ); 19 + }
+79
apps/mobile/components/parallax-scroll-view.tsx
··· 1 + import type { PropsWithChildren, ReactElement } from 'react'; 2 + import { StyleSheet } from 'react-native'; 3 + import Animated, { 4 + interpolate, 5 + useAnimatedRef, 6 + useAnimatedStyle, 7 + useScrollOffset, 8 + } from 'react-native-reanimated'; 9 + 10 + import { ThemedView } from '@/components/themed-view'; 11 + import { useColorScheme } from '@/hooks/use-color-scheme'; 12 + import { useThemeColor } from '@/hooks/use-theme-color'; 13 + 14 + const HEADER_HEIGHT = 250; 15 + 16 + type Props = PropsWithChildren<{ 17 + headerImage: ReactElement; 18 + headerBackgroundColor: { dark: string; light: string }; 19 + }>; 20 + 21 + export default function ParallaxScrollView({ 22 + children, 23 + headerImage, 24 + headerBackgroundColor, 25 + }: Props) { 26 + const backgroundColor = useThemeColor({}, 'background'); 27 + const colorScheme = useColorScheme() ?? 'light'; 28 + const scrollRef = useAnimatedRef<Animated.ScrollView>(); 29 + const scrollOffset = useScrollOffset(scrollRef); 30 + const headerAnimatedStyle = useAnimatedStyle(() => { 31 + return { 32 + transform: [ 33 + { 34 + translateY: interpolate( 35 + scrollOffset.value, 36 + [-HEADER_HEIGHT, 0, HEADER_HEIGHT], 37 + [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75] 38 + ), 39 + }, 40 + { 41 + scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]), 42 + }, 43 + ], 44 + }; 45 + }); 46 + 47 + return ( 48 + <Animated.ScrollView 49 + ref={scrollRef} 50 + style={{ backgroundColor, flex: 1 }} 51 + scrollEventThrottle={16}> 52 + <Animated.View 53 + style={[ 54 + styles.header, 55 + { backgroundColor: headerBackgroundColor[colorScheme] }, 56 + headerAnimatedStyle, 57 + ]}> 58 + {headerImage} 59 + </Animated.View> 60 + <ThemedView style={styles.content}>{children}</ThemedView> 61 + </Animated.ScrollView> 62 + ); 63 + } 64 + 65 + const styles = StyleSheet.create({ 66 + container: { 67 + flex: 1, 68 + }, 69 + header: { 70 + height: HEADER_HEIGHT, 71 + overflow: 'hidden', 72 + }, 73 + content: { 74 + flex: 1, 75 + padding: 32, 76 + gap: 16, 77 + overflow: 'hidden', 78 + }, 79 + });
+60
apps/mobile/components/themed-text.tsx
··· 1 + import { StyleSheet, Text, type TextProps } from 'react-native'; 2 + 3 + import { useThemeColor } from '@/hooks/use-theme-color'; 4 + 5 + export type ThemedTextProps = TextProps & { 6 + lightColor?: string; 7 + darkColor?: string; 8 + type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link'; 9 + }; 10 + 11 + export function ThemedText({ 12 + style, 13 + lightColor, 14 + darkColor, 15 + type = 'default', 16 + ...rest 17 + }: ThemedTextProps) { 18 + const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text'); 19 + 20 + return ( 21 + <Text 22 + style={[ 23 + { color }, 24 + type === 'default' ? styles.default : undefined, 25 + type === 'title' ? styles.title : undefined, 26 + type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined, 27 + type === 'subtitle' ? styles.subtitle : undefined, 28 + type === 'link' ? styles.link : undefined, 29 + style, 30 + ]} 31 + {...rest} 32 + /> 33 + ); 34 + } 35 + 36 + const styles = StyleSheet.create({ 37 + default: { 38 + fontSize: 16, 39 + lineHeight: 24, 40 + }, 41 + defaultSemiBold: { 42 + fontSize: 16, 43 + lineHeight: 24, 44 + fontWeight: '600', 45 + }, 46 + title: { 47 + fontSize: 32, 48 + fontWeight: 'bold', 49 + lineHeight: 32, 50 + }, 51 + subtitle: { 52 + fontSize: 20, 53 + fontWeight: 'bold', 54 + }, 55 + link: { 56 + lineHeight: 30, 57 + fontSize: 16, 58 + color: '#0a7ea4', 59 + }, 60 + });
+14
apps/mobile/components/themed-view.tsx
··· 1 + import { View, type ViewProps } from 'react-native'; 2 + 3 + import { useThemeColor } from '@/hooks/use-theme-color'; 4 + 5 + export type ThemedViewProps = ViewProps & { 6 + lightColor?: string; 7 + darkColor?: string; 8 + }; 9 + 10 + export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) { 11 + const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background'); 12 + 13 + return <View style={[{ backgroundColor }, style]} {...otherProps} />; 14 + }
+45
apps/mobile/components/ui/collapsible.tsx
··· 1 + import { PropsWithChildren, useState } from 'react'; 2 + import { StyleSheet, TouchableOpacity } from 'react-native'; 3 + 4 + import { ThemedText } from '@/components/themed-text'; 5 + import { ThemedView } from '@/components/themed-view'; 6 + import { IconSymbol } from '@/components/ui/icon-symbol'; 7 + import { Colors } from '@/constants/theme'; 8 + import { useColorScheme } from '@/hooks/use-color-scheme'; 9 + 10 + export function Collapsible({ children, title }: PropsWithChildren & { title: string }) { 11 + const [isOpen, setIsOpen] = useState(false); 12 + const theme = useColorScheme() ?? 'light'; 13 + 14 + return ( 15 + <ThemedView> 16 + <TouchableOpacity 17 + style={styles.heading} 18 + onPress={() => setIsOpen((value) => !value)} 19 + activeOpacity={0.8}> 20 + <IconSymbol 21 + name="chevron.right" 22 + size={18} 23 + weight="medium" 24 + color={theme === 'light' ? Colors.light.icon : Colors.dark.icon} 25 + style={{ transform: [{ rotate: isOpen ? '90deg' : '0deg' }] }} 26 + /> 27 + 28 + <ThemedText type="defaultSemiBold">{title}</ThemedText> 29 + </TouchableOpacity> 30 + {isOpen && <ThemedView style={styles.content}>{children}</ThemedView>} 31 + </ThemedView> 32 + ); 33 + } 34 + 35 + const styles = StyleSheet.create({ 36 + heading: { 37 + flexDirection: 'row', 38 + alignItems: 'center', 39 + gap: 6, 40 + }, 41 + content: { 42 + marginTop: 6, 43 + marginLeft: 24, 44 + }, 45 + });
+32
apps/mobile/components/ui/icon-symbol.ios.tsx
··· 1 + import { SymbolView, SymbolViewProps, SymbolWeight } from 'expo-symbols'; 2 + import { StyleProp, ViewStyle } from 'react-native'; 3 + 4 + export function IconSymbol({ 5 + name, 6 + size = 24, 7 + color, 8 + style, 9 + weight = 'regular', 10 + }: { 11 + name: SymbolViewProps['name']; 12 + size?: number; 13 + color: string; 14 + style?: StyleProp<ViewStyle>; 15 + weight?: SymbolWeight; 16 + }) { 17 + return ( 18 + <SymbolView 19 + weight={weight} 20 + tintColor={color} 21 + resizeMode="scaleAspectFit" 22 + name={name} 23 + style={[ 24 + { 25 + width: size, 26 + height: size, 27 + }, 28 + style, 29 + ]} 30 + /> 31 + ); 32 + }
+41
apps/mobile/components/ui/icon-symbol.tsx
··· 1 + // Fallback for using MaterialIcons on Android and web. 2 + 3 + import MaterialIcons from '@expo/vector-icons/MaterialIcons'; 4 + import { SymbolWeight, SymbolViewProps } from 'expo-symbols'; 5 + import { ComponentProps } from 'react'; 6 + import { OpaqueColorValue, type StyleProp, type TextStyle } from 'react-native'; 7 + 8 + type IconMapping = Record<SymbolViewProps['name'], ComponentProps<typeof MaterialIcons>['name']>; 9 + type IconSymbolName = keyof typeof MAPPING; 10 + 11 + /** 12 + * Add your SF Symbols to Material Icons mappings here. 13 + * - see Material Icons in the [Icons Directory](https://icons.expo.fyi). 14 + * - see SF Symbols in the [SF Symbols](https://developer.apple.com/sf-symbols/) app. 15 + */ 16 + const MAPPING = { 17 + 'house.fill': 'home', 18 + 'paperplane.fill': 'send', 19 + 'chevron.left.forwardslash.chevron.right': 'code', 20 + 'chevron.right': 'chevron-right', 21 + } as IconMapping; 22 + 23 + /** 24 + * An icon component that uses native SF Symbols on iOS, and Material Icons on Android and web. 25 + * This ensures a consistent look across platforms, and optimal resource usage. 26 + * Icon `name`s are based on SF Symbols and require manual mapping to Material Icons. 27 + */ 28 + export function IconSymbol({ 29 + name, 30 + size = 24, 31 + color, 32 + style, 33 + }: { 34 + name: IconSymbolName; 35 + size?: number; 36 + color: string | OpaqueColorValue; 37 + style?: StyleProp<TextStyle>; 38 + weight?: SymbolWeight; 39 + }) { 40 + return <MaterialIcons color={color} size={size} name={MAPPING[name]} style={style} />; 41 + }
+53
apps/mobile/constants/theme.ts
··· 1 + /** 2 + * Below are the colors that are used in the app. The colors are defined in the light and dark mode. 3 + * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc. 4 + */ 5 + 6 + import { Platform } from 'react-native'; 7 + 8 + const tintColorLight = '#0a7ea4'; 9 + const tintColorDark = '#fff'; 10 + 11 + export const Colors = { 12 + light: { 13 + text: '#11181C', 14 + background: '#fff', 15 + tint: tintColorLight, 16 + icon: '#687076', 17 + tabIconDefault: '#687076', 18 + tabIconSelected: tintColorLight, 19 + }, 20 + dark: { 21 + text: '#ECEDEE', 22 + background: '#151718', 23 + tint: tintColorDark, 24 + icon: '#9BA1A6', 25 + tabIconDefault: '#9BA1A6', 26 + tabIconSelected: tintColorDark, 27 + }, 28 + }; 29 + 30 + export const Fonts = Platform.select({ 31 + ios: { 32 + /** iOS `UIFontDescriptorSystemDesignDefault` */ 33 + sans: 'system-ui', 34 + /** iOS `UIFontDescriptorSystemDesignSerif` */ 35 + serif: 'ui-serif', 36 + /** iOS `UIFontDescriptorSystemDesignRounded` */ 37 + rounded: 'ui-rounded', 38 + /** iOS `UIFontDescriptorSystemDesignMonospaced` */ 39 + mono: 'ui-monospace', 40 + }, 41 + default: { 42 + sans: 'normal', 43 + serif: 'serif', 44 + rounded: 'normal', 45 + mono: 'monospace', 46 + }, 47 + web: { 48 + sans: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif", 49 + serif: "Georgia, 'Times New Roman', serif", 50 + rounded: "'SF Pro Rounded', 'Hiragino Maru Gothic ProN', Meiryo, 'MS PGothic', sans-serif", 51 + mono: "SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace", 52 + }, 53 + });
-24
apps/mobile/eas.json
··· 1 - { 2 - "cli": { 3 - "version": ">= 16.32.0", 4 - "appVersionSource": "remote" 5 - }, 6 - "build": { 7 - "development": { 8 - "developmentClient": true, 9 - "distribution": "internal", 10 - "ios": { 11 - "simulator": true 12 - } 13 - }, 14 - "preview": { 15 - "distribution": "internal" 16 - }, 17 - "production": { 18 - "autoIncrement": true 19 - } 20 - }, 21 - "submit": { 22 - "production": {} 23 - } 24 - }
+10
apps/mobile/eslint.config.js
··· 1 + // https://docs.expo.dev/guides/using-eslint/ 2 + const { defineConfig } = require('eslint/config'); 3 + const expoConfig = require('eslint-config-expo/flat'); 4 + 5 + module.exports = defineConfig([ 6 + expoConfig, 7 + { 8 + ignores: ['dist/*'], 9 + }, 10 + ]);
+1
apps/mobile/hooks/use-color-scheme.ts
··· 1 + export { useColorScheme } from 'react-native';
+21
apps/mobile/hooks/use-color-scheme.web.ts
··· 1 + import { useEffect, useState } from 'react'; 2 + import { useColorScheme as useRNColorScheme } from 'react-native'; 3 + 4 + /** 5 + * To support static rendering, this value needs to be re-calculated on the client side for web 6 + */ 7 + export function useColorScheme() { 8 + const [hasHydrated, setHasHydrated] = useState(false); 9 + 10 + useEffect(() => { 11 + setHasHydrated(true); 12 + }, []); 13 + 14 + const colorScheme = useRNColorScheme(); 15 + 16 + if (hasHydrated) { 17 + return colorScheme; 18 + } 19 + 20 + return 'light'; 21 + }
+21
apps/mobile/hooks/use-theme-color.ts
··· 1 + /** 2 + * Learn more about light and dark modes: 3 + * https://docs.expo.dev/guides/color-schemes/ 4 + */ 5 + 6 + import { Colors } from '@/constants/theme'; 7 + import { useColorScheme } from '@/hooks/use-color-scheme'; 8 + 9 + export function useThemeColor( 10 + props: { light?: string; dark?: string }, 11 + colorName: keyof typeof Colors.light & keyof typeof Colors.dark 12 + ) { 13 + const theme = useColorScheme() ?? 'light'; 14 + const colorFromProps = props[theme]; 15 + 16 + if (colorFromProps) { 17 + return colorFromProps; 18 + } else { 19 + return Colors[theme][colorName]; 20 + } 21 + }
-10
apps/mobile/metro.config.js
··· 1 - const { getDefaultConfig } = require('expo/metro-config'); 2 - const { withUniwindConfig } = require('uniwind/metro'); 3 - 4 - /** @type {import('expo/metro-config').MetroConfig} */ 5 - const config = getDefaultConfig(__dirname); 6 - 7 - module.exports = withUniwindConfig(config, { 8 - cssEntryFile: './src/global.css', 9 - dtsFile: './src/uniwind-types.d.ts', 10 - });
+29 -26
apps/mobile/package.json
··· 1 1 { 2 - "name": "mobile", 3 - "version": "1.0.0", 2 + "name": "opnshelf", 4 3 "main": "expo-router/entry", 4 + "version": "1.0.0", 5 5 "scripts": { 6 6 "start": "expo start", 7 - "dev": "expo start", 8 - "android": "expo run:android", 9 - "ios": "expo run:ios", 7 + "reset-project": "node ./scripts/reset-project.js", 8 + "android": "expo start --android", 9 + "ios": "expo start --ios", 10 10 "web": "expo start --web", 11 - "typecheck": "tsc --noEmit", 12 - "build:android": "eas build --local --platform android", 13 - "build:ios": "eas build --local --platform ios" 11 + "lint": "expo lint" 14 12 }, 15 13 "dependencies": { 16 - "@expo/vector-icons": "^15.0.0", 17 - "@opnshelf/api": "workspace:*", 18 - "@opnshelf/types": "workspace:*", 19 - "@tanstack/react-query": "^5.66.5", 20 - "class-variance-authority": "^0.7.1", 21 - "clsx": "^2.1.1", 14 + "@expo/vector-icons": "^15.0.3", 15 + "@react-navigation/bottom-tabs": "^7.4.0", 16 + "@react-navigation/elements": "^2.6.3", 17 + "@react-navigation/native": "^7.1.8", 22 18 "expo": "~54.0.33", 23 - "expo-dev-client": "~6.0.20", 19 + "expo-constants": "~18.0.13", 20 + "expo-font": "~14.0.11", 21 + "expo-haptics": "~15.0.8", 22 + "expo-image": "~3.0.11", 24 23 "expo-linking": "~8.0.11", 25 - "expo-router": "~4.0.22", 26 - "expo-secure-store": "^15.0.8", 24 + "expo-router": "~6.0.23", 25 + "expo-splash-screen": "~31.0.13", 27 26 "expo-status-bar": "~3.0.9", 28 - "expo-web-browser": "~15.0.0", 27 + "expo-symbols": "~1.0.8", 28 + "expo-system-ui": "~6.0.9", 29 + "expo-web-browser": "~15.0.10", 29 30 "react": "19.1.0", 31 + "react-dom": "19.1.0", 30 32 "react-native": "0.81.5", 31 - "react-native-safe-area-context": "~5.6.2", 33 + "react-native-gesture-handler": "~2.28.0", 34 + "react-native-worklets": "0.5.1", 35 + "react-native-reanimated": "~4.1.1", 36 + "react-native-safe-area-context": "~5.6.0", 32 37 "react-native-screens": "~4.16.0", 33 - "tailwind-merge": "^3.4.0", 34 - "tailwindcss": "^4.1.18", 35 - "uniwind": "^1.2.7" 38 + "react-native-web": "~0.21.0" 36 39 }, 37 40 "devDependencies": { 38 - "@types/node": "^25.2.2", 39 41 "@types/react": "~19.1.0", 40 - "typescript": "~5.9.2" 42 + "typescript": "~5.9.2", 43 + "eslint": "^9.25.0", 44 + "eslint-config-expo": "~10.0.0" 41 45 }, 42 - "private": true, 43 - "packageManager": "pnpm@10.28.2" 46 + "private": true 44 47 }
+112
apps/mobile/scripts/reset-project.js
··· 1 + #!/usr/bin/env node 2 + 3 + /** 4 + * This script is used to reset the project to a blank state. 5 + * It deletes or moves the /app, /components, /hooks, /scripts, and /constants directories to /app-example based on user input and creates a new /app directory with an index.tsx and _layout.tsx file. 6 + * You can remove the `reset-project` script from package.json and safely delete this file after running it. 7 + */ 8 + 9 + const fs = require("fs"); 10 + const path = require("path"); 11 + const readline = require("readline"); 12 + 13 + const root = process.cwd(); 14 + const oldDirs = ["app", "components", "hooks", "constants", "scripts"]; 15 + const exampleDir = "app-example"; 16 + const newAppDir = "app"; 17 + const exampleDirPath = path.join(root, exampleDir); 18 + 19 + const indexContent = `import { Text, View } from "react-native"; 20 + 21 + export default function Index() { 22 + return ( 23 + <View 24 + style={{ 25 + flex: 1, 26 + justifyContent: "center", 27 + alignItems: "center", 28 + }} 29 + > 30 + <Text>Edit app/index.tsx to edit this screen.</Text> 31 + </View> 32 + ); 33 + } 34 + `; 35 + 36 + const layoutContent = `import { Stack } from "expo-router"; 37 + 38 + export default function RootLayout() { 39 + return <Stack />; 40 + } 41 + `; 42 + 43 + const rl = readline.createInterface({ 44 + input: process.stdin, 45 + output: process.stdout, 46 + }); 47 + 48 + const moveDirectories = async (userInput) => { 49 + try { 50 + if (userInput === "y") { 51 + // Create the app-example directory 52 + await fs.promises.mkdir(exampleDirPath, { recursive: true }); 53 + console.log(`📁 /${exampleDir} directory created.`); 54 + } 55 + 56 + // Move old directories to new app-example directory or delete them 57 + for (const dir of oldDirs) { 58 + const oldDirPath = path.join(root, dir); 59 + if (fs.existsSync(oldDirPath)) { 60 + if (userInput === "y") { 61 + const newDirPath = path.join(root, exampleDir, dir); 62 + await fs.promises.rename(oldDirPath, newDirPath); 63 + console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`); 64 + } else { 65 + await fs.promises.rm(oldDirPath, { recursive: true, force: true }); 66 + console.log(`❌ /${dir} deleted.`); 67 + } 68 + } else { 69 + console.log(`➡️ /${dir} does not exist, skipping.`); 70 + } 71 + } 72 + 73 + // Create new /app directory 74 + const newAppDirPath = path.join(root, newAppDir); 75 + await fs.promises.mkdir(newAppDirPath, { recursive: true }); 76 + console.log("\n📁 New /app directory created."); 77 + 78 + // Create index.tsx 79 + const indexPath = path.join(newAppDirPath, "index.tsx"); 80 + await fs.promises.writeFile(indexPath, indexContent); 81 + console.log("📄 app/index.tsx created."); 82 + 83 + // Create _layout.tsx 84 + const layoutPath = path.join(newAppDirPath, "_layout.tsx"); 85 + await fs.promises.writeFile(layoutPath, layoutContent); 86 + console.log("📄 app/_layout.tsx created."); 87 + 88 + console.log("\n✅ Project reset complete. Next steps:"); 89 + console.log( 90 + `1. Run \`npx expo start\` to start a development server.\n2. Edit app/index.tsx to edit the main screen.${ 91 + userInput === "y" 92 + ? `\n3. Delete the /${exampleDir} directory when you're done referencing it.` 93 + : "" 94 + }` 95 + ); 96 + } catch (error) { 97 + console.error(`❌ Error during script execution: ${error.message}`); 98 + } 99 + }; 100 + 101 + rl.question( 102 + "Do you want to move existing files to /app-example instead of deleting them? (Y/n): ", 103 + (answer) => { 104 + const userInput = answer.trim().toLowerCase() || "y"; 105 + if (userInput === "y" || userInput === "n") { 106 + moveDirectories(userInput).finally(() => rl.close()); 107 + } else { 108 + console.log("❌ Invalid input. Please enter 'Y' or 'N'."); 109 + rl.close(); 110 + } 111 + } 112 + );
-82
apps/mobile/src/components/HeaderRight.tsx
··· 1 - import { useRouter } from 'expo-router'; 2 - import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'; 3 - import { authControllerMeOptions, authControllerLogoutMutation } from '@opnshelf/api'; 4 - import { Ionicons } from '@expo/vector-icons'; 5 - import { ActivityIndicator, Image, TouchableOpacity, View } from 'react-native'; 6 - 7 - export function HeaderRight() { 8 - const router = useRouter(); 9 - const queryClient = useQueryClient(); 10 - 11 - const { data: user, isLoading } = useQuery({ 12 - ...authControllerMeOptions(), 13 - staleTime: 5 * 60 * 1000, 14 - retry: false, 15 - }); 16 - 17 - const logoutMutation = useMutation({ 18 - ...authControllerLogoutMutation(), 19 - onSuccess: () => { 20 - queryClient.invalidateQueries({ queryKey: ['auth'] }); 21 - queryClient.invalidateQueries({ queryKey: ['shelf'] }); 22 - router.replace('/'); 23 - }, 24 - onError: (error) => { 25 - console.error('Logout failed:', error); 26 - }, 27 - }); 28 - 29 - const handleLogout = async () => { 30 - await logoutMutation.mutateAsync({}); 31 - }; 32 - 33 - if (isLoading) { 34 - return ( 35 - <View className="mr-4"> 36 - <ActivityIndicator size="small" color="#a855f7" /> 37 - </View> 38 - ); 39 - } 40 - 41 - if (!user) { 42 - return ( 43 - <TouchableOpacity 44 - className="mr-4 flex-row items-center gap-2" 45 - onPress={() => router.push('/login')} 46 - activeOpacity={0.7} 47 - > 48 - <Ionicons name="log-in" size={24} color="#a855f7" /> 49 - </TouchableOpacity> 50 - ); 51 - } 52 - 53 - return ( 54 - <View className="flex-row items-center gap-3 mr-4"> 55 - <TouchableOpacity 56 - onPress={() => router.push('/shelf')} 57 - activeOpacity={0.7} 58 - > 59 - <Ionicons name="book" size={24} color="#a855f7" /> 60 - </TouchableOpacity> 61 - 62 - <TouchableOpacity 63 - onPress={handleLogout} 64 - disabled={logoutMutation.isPending} 65 - activeOpacity={0.7} 66 - > 67 - {logoutMutation.isPending ? ( 68 - <ActivityIndicator size="small" color="#a855f7" /> 69 - ) : user.avatar ? ( 70 - <Image 71 - source={{ uri: String(user.avatar) }} 72 - className="w-8 h-8 rounded-full" 73 - /> 74 - ) : ( 75 - <View className="w-8 h-8 rounded-full bg-gray-800 justify-center items-center"> 76 - <Ionicons name="person" size={16} color="#9ca3af" /> 77 - </View> 78 - )} 79 - </TouchableOpacity> 80 - </View> 81 - ); 82 - }
-36
apps/mobile/src/components/ui/badge.tsx
··· 1 - import * as React from 'react'; 2 - import { Text, type TextProps } from 'react-native'; 3 - import { cva, type VariantProps } from 'class-variance-authority'; 4 - import { cn } from '@/lib/utils'; 5 - 6 - const badgeVariants = cva( 7 - 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors', 8 - { 9 - variants: { 10 - variant: { 11 - default: 12 - 'border-transparent bg-violet-600 text-white', 13 - secondary: 14 - 'border-transparent bg-gray-700 text-gray-200', 15 - destructive: 16 - 'border-transparent bg-red-600 text-white', 17 - outline: 'text-gray-50 border-gray-700', 18 - }, 19 - }, 20 - defaultVariants: { 21 - variant: 'default', 22 - }, 23 - } 24 - ); 25 - 26 - interface BadgeProps 27 - extends TextProps, 28 - VariantProps<typeof badgeVariants> {} 29 - 30 - function Badge({ className, variant, ...props }: BadgeProps) { 31 - return ( 32 - <Text className={cn(badgeVariants({ variant }), className)} {...props} /> 33 - ); 34 - } 35 - 36 - export { Badge, badgeVariants };
-98
apps/mobile/src/components/ui/button.tsx
··· 1 - import * as React from 'react'; 2 - import { 3 - TouchableOpacity, 4 - type TouchableOpacityProps, 5 - ActivityIndicator, 6 - Text, 7 - View, 8 - } from 'react-native'; 9 - import { cva, type VariantProps } from 'class-variance-authority'; 10 - import { cn } from '@/lib/utils'; 11 - 12 - const buttonVariants = cva( 13 - 'flex-row items-center justify-center rounded-lg', 14 - { 15 - variants: { 16 - variant: { 17 - default: 'bg-violet-600 active:bg-violet-700', 18 - destructive: 'bg-red-600 active:bg-red-700', 19 - outline: 'border border-gray-700 bg-transparent active:bg-gray-800', 20 - secondary: 'bg-gray-800 active:bg-gray-700 border border-gray-700', 21 - ghost: 'bg-transparent active:bg-gray-800', 22 - link: 'bg-transparent underline-offset-4', 23 - }, 24 - size: { 25 - default: 'h-11 px-4 py-2', 26 - sm: 'h-9 px-3', 27 - lg: 'h-12 px-8', 28 - icon: 'h-10 w-10', 29 - }, 30 - }, 31 - defaultVariants: { 32 - variant: 'default', 33 - size: 'default', 34 - }, 35 - } 36 - ); 37 - 38 - const buttonTextVariants = cva('font-medium', { 39 - variants: { 40 - variant: { 41 - default: 'text-white', 42 - destructive: 'text-white', 43 - outline: 'text-gray-50', 44 - secondary: 'text-gray-50', 45 - ghost: 'text-gray-50', 46 - link: 'text-violet-400 underline', 47 - }, 48 - size: { 49 - default: 'text-base', 50 - sm: 'text-sm', 51 - lg: 'text-lg', 52 - icon: 'text-base', 53 - }, 54 - }, 55 - defaultVariants: { 56 - variant: 'default', 57 - size: 'default', 58 - }, 59 - }); 60 - 61 - interface ButtonProps 62 - extends TouchableOpacityProps, 63 - VariantProps<typeof buttonVariants> { 64 - isLoading?: boolean; 65 - } 66 - 67 - const Button = React.forwardRef< 68 - React.ElementRef<typeof TouchableOpacity>, 69 - ButtonProps 70 - >( 71 - ( 72 - { className, variant, size, isLoading = false, disabled, children, ...props }, 73 - ref 74 - ) => { 75 - const isDisabled = disabled || isLoading; 76 - 77 - return ( 78 - <TouchableOpacity 79 - ref={ref} 80 - className={cn(buttonVariants({ variant, size, className }), isDisabled && 'opacity-50')} 81 - disabled={isDisabled} 82 - activeOpacity={0.8} 83 - {...props} 84 - > 85 - {isLoading ? ( 86 - <ActivityIndicator size="small" color="#fff" /> 87 - ) : typeof children === 'string' ? ( 88 - <Text className={buttonTextVariants({ variant, size })}>{children}</Text> 89 - ) : ( 90 - children 91 - )} 92 - </TouchableOpacity> 93 - ); 94 - } 95 - ); 96 - Button.displayName = 'Button'; 97 - 98 - export { Button, buttonVariants, buttonTextVariants };
-86
apps/mobile/src/components/ui/card.tsx
··· 1 - import * as React from 'react'; 2 - import { View, type ViewProps, Text, type TextProps } from 'react-native'; 3 - import { cn } from '@/lib/utils'; 4 - 5 - const Card = React.forwardRef< 6 - React.ElementRef<typeof View>, 7 - ViewProps 8 - >(({ className, ...props }, ref) => ( 9 - <View 10 - ref={ref} 11 - className={cn( 12 - 'rounded-lg border border-gray-800 bg-gray-900', 13 - className 14 - )} 15 - {...props} 16 - /> 17 - )); 18 - Card.displayName = 'Card'; 19 - 20 - const CardHeader = React.forwardRef< 21 - React.ElementRef<typeof View>, 22 - ViewProps 23 - >(({ className, ...props }, ref) => ( 24 - <View 25 - ref={ref} 26 - className={cn('flex flex-col space-y-1.5 p-6', className)} 27 - {...props} 28 - /> 29 - )); 30 - CardHeader.displayName = 'CardHeader'; 31 - 32 - const CardTitle = React.forwardRef< 33 - React.ElementRef<typeof Text>, 34 - TextProps 35 - >(({ className, ...props }, ref) => ( 36 - <Text 37 - ref={ref} 38 - className={cn( 39 - 'text-2xl font-semibold leading-none tracking-tight text-gray-50', 40 - className 41 - )} 42 - {...props} 43 - /> 44 - )); 45 - CardTitle.displayName = 'CardTitle'; 46 - 47 - const CardDescription = React.forwardRef< 48 - React.ElementRef<typeof Text>, 49 - TextProps 50 - >(({ className, ...props }, ref) => ( 51 - <Text 52 - ref={ref} 53 - className={cn('text-sm text-gray-400', className)} 54 - {...props} 55 - /> 56 - )); 57 - CardDescription.displayName = 'CardDescription'; 58 - 59 - const CardContent = React.forwardRef< 60 - React.ElementRef<typeof View>, 61 - ViewProps 62 - >(({ className, ...props }, ref) => ( 63 - <View ref={ref} className={cn('p-6 pt-0', className)} {...props} /> 64 - )); 65 - CardContent.displayName = 'CardContent'; 66 - 67 - const CardFooter = React.forwardRef< 68 - React.ElementRef<typeof View>, 69 - ViewProps 70 - >(({ className, ...props }, ref) => ( 71 - <View 72 - ref={ref} 73 - className={cn('flex flex-row items-center p-6 pt-0', className)} 74 - {...props} 75 - /> 76 - )); 77 - CardFooter.displayName = 'CardFooter'; 78 - 79 - export { 80 - Card, 81 - CardHeader, 82 - CardFooter, 83 - CardTitle, 84 - CardDescription, 85 - CardContent, 86 - };
-298
apps/mobile/src/components/ui/date-time-picker.tsx
··· 1 - import { useMemo, useState, useCallback } from 'react'; 2 - import { 3 - View, 4 - TextInput, 5 - Text, 6 - TouchableOpacity, 7 - Modal, 8 - Pressable, 9 - } from 'react-native'; 10 - import Ionicons from '@expo/vector-icons/Ionicons'; 11 - 12 - interface DateTimePickerModalProps { 13 - visible: boolean; 14 - date: Date | null; 15 - onConfirm: (date: Date) => void; 16 - onCancel: () => void; 17 - } 18 - 19 - const MONTHS = [ 20 - 'Jan', 21 - 'Feb', 22 - 'Mar', 23 - 'Apr', 24 - 'May', 25 - 'Jun', 26 - 'Jul', 27 - 'Aug', 28 - 'Sep', 29 - 'Oct', 30 - 'Nov', 31 - 'Dec', 32 - ]; 33 - 34 - export function DateTimePickerModal({ 35 - visible, 36 - date, 37 - onConfirm, 38 - onCancel, 39 - }: DateTimePickerModalProps) { 40 - const initialDate = date || new Date(); 41 - const [selectedDate, setSelectedDate] = useState(initialDate); 42 - const [currentMonth, setCurrentMonth] = useState(initialDate.getMonth()); 43 - const [currentYear, setCurrentYear] = useState(initialDate.getFullYear()); 44 - const [hourInput, setHourInput] = useState( 45 - initialDate.getHours().toString().padStart(2, '0'), 46 - ); 47 - const [minuteInput, setMinuteInput] = useState( 48 - initialDate.getMinutes().toString().padStart(2, '0'), 49 - ); 50 - 51 - const daysInMonth = useMemo(() => { 52 - return new Date(currentYear, currentMonth + 1, 0).getDate(); 53 - }, [currentMonth, currentYear]); 54 - 55 - const firstDayOfMonth = useMemo(() => { 56 - return new Date(currentYear, currentMonth, 1).getDay(); 57 - }, [currentMonth, currentYear]); 58 - 59 - const handleDayPress = useCallback( 60 - (day: number) => { 61 - const hours = parseInt(hourInput, 10) || 0; 62 - const minutes = parseInt(minuteInput, 10) || 0; 63 - 64 - const newDate = new Date(currentYear, currentMonth, day, hours, minutes, 0, 0); 65 - setSelectedDate(newDate); 66 - }, 67 - [currentMonth, currentYear, hourInput, minuteInput], 68 - ); 69 - 70 - const normalizeTimeInput = useCallback(() => { 71 - let hours = parseInt(hourInput, 10); 72 - let minutes = parseInt(minuteInput, 10); 73 - 74 - if (isNaN(hours) || hours < 0) hours = 0; 75 - if (hours > 23) hours = 23; 76 - if (isNaN(minutes) || minutes < 0) minutes = 0; 77 - if (minutes > 59) minutes = 59; 78 - 79 - const normalizedHours = hours.toString().padStart(2, '0'); 80 - const normalizedMinutes = minutes.toString().padStart(2, '0'); 81 - 82 - setHourInput(normalizedHours); 83 - setMinuteInput(normalizedMinutes); 84 - 85 - return { hours, minutes }; 86 - }, [hourInput, minuteInput]); 87 - 88 - const handleConfirm = useCallback(() => { 89 - const { hours, minutes } = normalizeTimeInput(); 90 - 91 - const finalDate = new Date(selectedDate); 92 - finalDate.setHours(hours, minutes, 0, 0); 93 - 94 - onConfirm(finalDate); 95 - }, [selectedDate, hourInput, minuteInput, onConfirm, normalizeTimeInput]); 96 - 97 - const goToPreviousMonth = useCallback(() => { 98 - if (currentMonth === 0) { 99 - setCurrentMonth(11); 100 - setCurrentYear(currentYear - 1); 101 - } else { 102 - setCurrentMonth(currentMonth - 1); 103 - } 104 - }, [currentMonth, currentYear]); 105 - 106 - const goToNextMonth = useCallback(() => { 107 - if (currentMonth === 11) { 108 - setCurrentMonth(0); 109 - setCurrentYear(currentYear + 1); 110 - } else { 111 - setCurrentMonth(currentMonth + 1); 112 - } 113 - }, [currentMonth, currentYear]); 114 - 115 - const calendarDays = useMemo(() => { 116 - const days: (number | null)[] = []; 117 - for (let i = 0; i < firstDayOfMonth; i++) { 118 - days.push(null); 119 - } 120 - for (let i = 1; i <= daysInMonth; i++) { 121 - days.push(i); 122 - } 123 - return days; 124 - }, [firstDayOfMonth, daysInMonth]); 125 - 126 - const isSelectedDay = useCallback( 127 - (day: number) => { 128 - return ( 129 - selectedDate.getDate() === day && 130 - selectedDate.getMonth() === currentMonth && 131 - selectedDate.getFullYear() === currentYear 132 - ); 133 - }, 134 - [selectedDate, currentMonth, currentYear], 135 - ); 136 - 137 - const isToday = useCallback( 138 - (day: number) => { 139 - const today = new Date(); 140 - return ( 141 - today.getDate() === day && 142 - today.getMonth() === currentMonth && 143 - today.getFullYear() === currentYear 144 - ); 145 - }, 146 - [currentMonth, currentYear], 147 - ); 148 - 149 - const isFutureDate = useCallback( 150 - (day: number) => { 151 - const checkDate = new Date(currentYear, currentMonth, day); 152 - const today = new Date(); 153 - today.setHours(0, 0, 0, 0); 154 - return checkDate > today; 155 - }, 156 - [currentMonth, currentYear], 157 - ); 158 - 159 - return ( 160 - <Modal 161 - visible={visible} 162 - transparent 163 - animationType="slide" 164 - onRequestClose={onCancel} 165 - > 166 - <Pressable 167 - className="flex-1 bg-black/70 justify-center items-center p-4" 168 - onPress={onCancel} 169 - > 170 - <Pressable 171 - className="bg-gray-900 rounded-2xl p-6 w-full max-w-sm" 172 - onPress={(e) => e.stopPropagation()} 173 - > 174 - <Text className="text-white text-xl font-semibold mb-4 text-center"> 175 - Select Date & Time 176 - </Text> 177 - 178 - {/* Month Navigation */} 179 - <View className="flex-row justify-between items-center mb-4"> 180 - <TouchableOpacity 181 - onPress={goToPreviousMonth} 182 - className="p-2" 183 - > 184 - <Ionicons name="chevron-back" size={24} color="#9ca3af" /> 185 - </TouchableOpacity> 186 - <Text className="text-white text-lg font-medium"> 187 - {MONTHS[currentMonth]} {currentYear} 188 - </Text> 189 - <TouchableOpacity onPress={goToNextMonth} className="p-2"> 190 - <Ionicons name="chevron-forward" size={24} color="#9ca3af" /> 191 - </TouchableOpacity> 192 - </View> 193 - 194 - {/* Weekday Headers */} 195 - <View className="flex-row justify-between mb-2"> 196 - {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day, index) => ( 197 - <Text 198 - key={index} 199 - className="text-gray-400 text-sm w-10 text-center" 200 - > 201 - {day} 202 - </Text> 203 - ))} 204 - </View> 205 - 206 - {/* Calendar Grid */} 207 - <View className="flex-row flex-wrap justify-between"> 208 - {calendarDays.map((day, index) => ( 209 - <TouchableOpacity 210 - key={index} 211 - onPress={() => day && !isFutureDate(day) && handleDayPress(day)} 212 - disabled={!day || isFutureDate(day || 0)} 213 - className={`w-10 h-10 justify-center items-center m-0.5 rounded-lg ${ 214 - day && isSelectedDay(day) 215 - ? 'bg-purple-600' 216 - : day && isToday(day) 217 - ? 'bg-gray-700' 218 - : '' 219 - } ${isFutureDate(day || 0) ? 'opacity-30' : ''}`} 220 - > 221 - {day && ( 222 - <Text 223 - className={`text-base ${ 224 - isSelectedDay(day) 225 - ? 'text-white font-semibold' 226 - : isFutureDate(day) 227 - ? 'text-gray-500' 228 - : 'text-white' 229 - }`} 230 - > 231 - {day} 232 - </Text> 233 - )} 234 - </TouchableOpacity> 235 - ))} 236 - </View> 237 - 238 - {/* Time Selection */} 239 - <View className="mt-6 mb-4"> 240 - <Text className="text-gray-400 text-sm mb-2 text-center"> 241 - Time (24-hour format) 242 - </Text> 243 - <View className="flex-row justify-center items-center gap-2"> 244 - <TextInput 245 - value={hourInput} 246 - onChangeText={setHourInput} 247 - onBlur={normalizeTimeInput} 248 - keyboardType="number-pad" 249 - maxLength={2} 250 - className="bg-gray-800 text-white text-center text-xl w-16 h-12 rounded-lg border border-gray-700" 251 - placeholder="HH" 252 - placeholderTextColor="#6b7280" 253 - /> 254 - <Text className="text-white text-xl">:</Text> 255 - <TextInput 256 - value={minuteInput} 257 - onChangeText={setMinuteInput} 258 - onBlur={normalizeTimeInput} 259 - keyboardType="number-pad" 260 - maxLength={2} 261 - className="bg-gray-800 text-white text-center text-xl w-16 h-12 rounded-lg border border-gray-700" 262 - placeholder="MM" 263 - placeholderTextColor="#6b7280" 264 - /> 265 - </View> 266 - </View> 267 - 268 - {/* Selected Date Display */} 269 - <Text className="text-white text-center mb-4"> 270 - {selectedDate.toLocaleDateString('en-US', { 271 - weekday: 'short', 272 - month: 'short', 273 - day: 'numeric', 274 - })}{' '} 275 - at{' '} 276 - {hourInput}:{minuteInput} 277 - </Text> 278 - 279 - {/* Buttons */} 280 - <View className="flex-row gap-3"> 281 - <TouchableOpacity 282 - onPress={onCancel} 283 - className="flex-1 bg-gray-800 py-3 rounded-xl" 284 - > 285 - <Text className="text-white text-center font-medium">Cancel</Text> 286 - </TouchableOpacity> 287 - <TouchableOpacity 288 - onPress={handleConfirm} 289 - className="flex-1 bg-purple-600 py-3 rounded-xl" 290 - > 291 - <Text className="text-white text-center font-medium">Confirm</Text> 292 - </TouchableOpacity> 293 - </View> 294 - </Pressable> 295 - </Pressable> 296 - </Modal> 297 - ); 298 - }
-167
apps/mobile/src/components/ui/dialog.tsx
··· 1 - import * as React from 'react'; 2 - import { 3 - Modal, 4 - View, 5 - type ViewProps, 6 - Text, 7 - type TextProps, 8 - TouchableOpacity, 9 - type ModalProps, 10 - ScrollView, 11 - Pressable, 12 - SafeAreaView, 13 - KeyboardAvoidingView, 14 - Platform, 15 - } from 'react-native'; 16 - import { cn } from '@/lib/utils'; 17 - import { Ionicons } from '@expo/vector-icons'; 18 - 19 - interface DialogProps extends Omit<ModalProps, 'visible'> { 20 - open: boolean; 21 - onOpenChange: (open: boolean) => void; 22 - } 23 - 24 - const Dialog = React.forwardRef< 25 - React.ElementRef<typeof Modal>, 26 - DialogProps 27 - >(({ open, onOpenChange, children, ...props }, ref) => { 28 - return ( 29 - <Modal 30 - ref={ref} 31 - visible={open} 32 - transparent 33 - animationType="fade" 34 - onRequestClose={() => onOpenChange(false)} 35 - {...props} 36 - > 37 - <SafeAreaView className="flex-1"> 38 - <KeyboardAvoidingView 39 - behavior={Platform.OS === 'ios' ? 'padding' : 'height'} 40 - className="flex-1" 41 - > 42 - <Pressable 43 - className="flex-1 bg-black/70 justify-center items-center p-4" 44 - onPress={() => onOpenChange(false)} 45 - > 46 - <Pressable onPress={(e) => e.stopPropagation()}> 47 - {children} 48 - </Pressable> 49 - </Pressable> 50 - </KeyboardAvoidingView> 51 - </SafeAreaView> 52 - </Modal> 53 - ); 54 - }); 55 - Dialog.displayName = 'Dialog'; 56 - 57 - const DialogContent = React.forwardRef< 58 - React.ElementRef<typeof View>, 59 - ViewProps 60 - >(({ className, ...props }, ref) => ( 61 - <View 62 - ref={ref} 63 - className={cn( 64 - 'w-full max-w-md bg-gray-900 rounded-2xl border border-gray-800 p-6', 65 - className 66 - )} 67 - {...props} 68 - /> 69 - )); 70 - DialogContent.displayName = 'DialogContent'; 71 - 72 - const DialogHeader = React.forwardRef< 73 - React.ElementRef<typeof View>, 74 - ViewProps 75 - >(({ className, ...props }, ref) => ( 76 - <View 77 - ref={ref} 78 - className={cn('flex flex-col space-y-1.5 mb-4', className)} 79 - {...props} 80 - /> 81 - )); 82 - DialogHeader.displayName = 'DialogHeader'; 83 - 84 - const DialogTitle = React.forwardRef< 85 - React.ElementRef<typeof Text>, 86 - TextProps 87 - >(({ className, ...props }, ref) => ( 88 - <Text 89 - ref={ref} 90 - className={cn( 91 - 'text-xl font-semibold text-white', 92 - className 93 - )} 94 - {...props} 95 - /> 96 - )); 97 - DialogTitle.displayName = 'DialogTitle'; 98 - 99 - const DialogDescription = React.forwardRef< 100 - React.ElementRef<typeof Text>, 101 - TextProps 102 - >(({ className, ...props }, ref) => ( 103 - <Text 104 - ref={ref} 105 - className={cn('text-sm text-gray-400', className)} 106 - {...props} 107 - /> 108 - )); 109 - DialogDescription.displayName = 'DialogDescription'; 110 - 111 - const DialogFooter = React.forwardRef< 112 - React.ElementRef<typeof View>, 113 - ViewProps 114 - >(({ className, ...props }, ref) => ( 115 - <View 116 - ref={ref} 117 - className={cn('flex flex-row justify-end mt-6 gap-3', className)} 118 - {...props} 119 - /> 120 - )); 121 - DialogFooter.displayName = 'DialogFooter'; 122 - 123 - const DialogClose = React.forwardRef< 124 - React.ElementRef<typeof TouchableOpacity>, 125 - React.ComponentProps<typeof TouchableOpacity> 126 - >(({ className, onPress, ...props }, ref) => { 127 - return ( 128 - <TouchableOpacity 129 - ref={ref} 130 - className={cn('absolute top-4 right-4 p-2 rounded-full', className)} 131 - onPress={onPress} 132 - activeOpacity={0.7} 133 - {...props} 134 - > 135 - <Ionicons name="close" size={24} color="#9ca3af" /> 136 - </TouchableOpacity> 137 - ); 138 - }); 139 - DialogClose.displayName = 'DialogClose'; 140 - 141 - const DialogScrollContent = React.forwardRef< 142 - React.ElementRef<typeof ScrollView>, 143 - React.ComponentProps<typeof ScrollView> 144 - >(({ className, contentContainerStyle, ...props }, ref) => ( 145 - <ScrollView 146 - ref={ref} 147 - className={cn('max-h-[50vh]', className)} 148 - showsVerticalScrollIndicator={true} 149 - contentContainerStyle={[ 150 - { flexGrow: 0 }, 151 - contentContainerStyle, 152 - ]} 153 - {...props} 154 - /> 155 - )); 156 - DialogScrollContent.displayName = 'DialogScrollContent'; 157 - 158 - export { 159 - Dialog, 160 - DialogContent, 161 - DialogHeader, 162 - DialogTitle, 163 - DialogDescription, 164 - DialogFooter, 165 - DialogClose, 166 - DialogScrollContent, 167 - };
-6
apps/mobile/src/components/ui/index.ts
··· 1 - export { Button, buttonVariants, buttonTextVariants } from './button'; 2 - export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from './card'; 3 - export { Badge, badgeVariants } from './badge'; 4 - export { Skeleton } from './skeleton'; 5 - export { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, DialogScrollContent } from './dialog'; 6 - export { Separator } from './separator';
-31
apps/mobile/src/components/ui/separator.tsx
··· 1 - import * as React from 'react'; 2 - import { View, type ViewProps } from 'react-native'; 3 - import { cn } from '@/lib/utils'; 4 - 5 - interface SeparatorProps extends ViewProps { 6 - orientation?: 'horizontal' | 'vertical'; 7 - decorative?: boolean; 8 - } 9 - 10 - const Separator = React.forwardRef< 11 - React.ElementRef<typeof View>, 12 - SeparatorProps 13 - >( 14 - ( 15 - { className, orientation = 'horizontal', decorative = true, ...props }, 16 - ref 17 - ) => ( 18 - <View 19 - ref={ref} 20 - className={cn( 21 - 'shrink-0 bg-gray-800', 22 - orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]', 23 - className 24 - )} 25 - {...props} 26 - /> 27 - ) 28 - ); 29 - Separator.displayName = 'Separator'; 30 - 31 - export { Separator };
-47
apps/mobile/src/components/ui/skeleton.tsx
··· 1 - import * as React from 'react'; 2 - import { View, type ViewProps, Animated } from 'react-native'; 3 - import { cn } from '@/lib/utils'; 4 - 5 - interface SkeletonProps extends ViewProps { 6 - show?: boolean; 7 - } 8 - 9 - function Skeleton({ className, show = true, ...props }: SkeletonProps) { 10 - const pulseAnim = React.useRef(new Animated.Value(0.4)).current; 11 - 12 - React.useEffect(() => { 13 - if (!show) return; 14 - 15 - const pulse = Animated.sequence([ 16 - Animated.timing(pulseAnim, { 17 - toValue: 0.8, 18 - duration: 800, 19 - useNativeDriver: true, 20 - }), 21 - Animated.timing(pulseAnim, { 22 - toValue: 0.4, 23 - duration: 800, 24 - useNativeDriver: true, 25 - }), 26 - ]); 27 - 28 - const loop = Animated.loop(pulse); 29 - loop.start(); 30 - 31 - return () => { 32 - loop.stop(); 33 - }; 34 - }, [pulseAnim, show]); 35 - 36 - if (!show) return null; 37 - 38 - return ( 39 - <Animated.View 40 - className={cn('rounded-md bg-gray-800', className)} 41 - style={[{ opacity: pulseAnim }]} 42 - {...props} 43 - /> 44 - ); 45 - } 46 - 47 - export { Skeleton };
-8
apps/mobile/src/env.ts
··· 1 - /** 2 - * Mobile app env. Use EXPO_PUBLIC_API_URL to point at the backend. 3 - */ 4 - const EXPO_PUBLIC_API_URL = process.env.EXPO_PUBLIC_API_URL ?? 'http://127.0.0.1:3001'; 5 - 6 - export const env = { 7 - EXPO_PUBLIC_API_URL, 8 - } as const;
-2
apps/mobile/src/global.css
··· 1 - @import 'tailwindcss'; 2 - @import 'uniwind';
-1
apps/mobile/src/hooks/index.ts
··· 1 - export * from './useOrientation';
-18
apps/mobile/src/hooks/useOrientation.ts
··· 1 - import { useDeviceSize } from '../utils'; 2 - 3 - /** 4 - * Hook to determine device orientation and capabilities 5 - * Only tablets (medium/expanded size) should support landscape 6 - */ 7 - export function useOrientation() { 8 - const deviceSize = useDeviceSize(); 9 - const isTablet = deviceSize === 'medium' || deviceSize === 'expanded'; 10 - 11 - return { 12 - isTablet, 13 - isPhone: !isTablet, 14 - supportsLandscape: isTablet, 15 - // Phones should be portrait-only, tablets can rotate 16 - shouldLockToPortrait: !isTablet, 17 - }; 18 - }
-41
apps/mobile/src/lib/session.ts
··· 1 - import * as SecureStore from 'expo-secure-store'; 2 - import { setSessionToken } from '@opnshelf/api'; 3 - 4 - const SESSION_KEY = 'auth_session'; 5 - 6 - /** 7 - * Store the session token securely and configure the API client to use it. 8 - */ 9 - export async function saveSession(token: string): Promise<void> { 10 - await SecureStore.setItemAsync(SESSION_KEY, token); 11 - setSessionToken(token); 12 - } 13 - 14 - /** 15 - * Load the session token from secure storage and configure the API client. 16 - * Call this on app startup. 17 - */ 18 - export async function loadSession(): Promise<string | null> { 19 - const token = await SecureStore.getItemAsync(SESSION_KEY); 20 - if (token) { 21 - setSessionToken(token); 22 - } 23 - return token; 24 - } 25 - 26 - /** 27 - * Clear the session token from storage and API client. 28 - * Call this on logout. 29 - */ 30 - export async function clearSession(): Promise<void> { 31 - await SecureStore.deleteItemAsync(SESSION_KEY); 32 - setSessionToken(null); 33 - } 34 - 35 - /** 36 - * Check if a session exists in storage. 37 - */ 38 - export async function hasSession(): Promise<boolean> { 39 - const token = await SecureStore.getItemAsync(SESSION_KEY); 40 - return token !== null; 41 - }
-6
apps/mobile/src/lib/utils.ts
··· 1 - import { clsx, type ClassValue } from 'clsx'; 2 - import { twMerge } from 'tailwind-merge'; 3 - 4 - export function cn(...inputs: ClassValue[]) { 5 - return twMerge(clsx(inputs)); 6 - }
-10
apps/mobile/src/uniwind-types.d.ts
··· 1 - // NOTE: This file is generated by uniwind and it should not be edited manually. 2 - /// <reference types="uniwind/types" /> 3 - 4 - declare module 'uniwind' { 5 - export interface UniwindConfig { 6 - themes: readonly ['light', 'dark'] 7 - } 8 - } 9 - 10 - export {}
-1
apps/mobile/src/uniwind.d.ts
··· 1 - /// <reference types="uniwind/types" />
-1
apps/mobile/src/utils/index.ts
··· 1 - export * from './responsive';
-108
apps/mobile/src/utils/responsive.ts
··· 1 - import { useWindowDimensions } from 'react-native'; 2 - 3 - // Breakpoints based on Material Design 3 guidelines 4 - export const BREAKPOINTS = { 5 - COMPACT: 600, 6 - MEDIUM: 840, 7 - } as const; 8 - 9 - export type DeviceSize = 'compact' | 'medium' | 'expanded'; 10 - 11 - /** 12 - * Hook to detect device size category based on screen width 13 - * - compact: < 600dp (phones in portrait) 14 - * - medium: 600-840dp (phones in landscape, small tablets) 15 - * - expanded: > 840dp (tablets, large screens) 16 - */ 17 - export function useDeviceSize(): DeviceSize { 18 - const { width } = useWindowDimensions(); 19 - 20 - if (width < BREAKPOINTS.COMPACT) { 21 - return 'compact'; 22 - } else if (width < BREAKPOINTS.MEDIUM) { 23 - return 'medium'; 24 - } 25 - return 'expanded'; 26 - } 27 - 28 - /** 29 - * Hook to check if device is a tablet (medium or expanded size) 30 - */ 31 - export function useIsTablet(): boolean { 32 - const deviceSize = useDeviceSize(); 33 - return deviceSize === 'medium' || deviceSize === 'expanded'; 34 - } 35 - 36 - /** 37 - * Hook to get the number of columns for grid layouts 38 - * - Search results: compact=2, medium=3, expanded=4 39 - * - Shelf grid: compact=1 (list), medium=2, expanded=3 40 - */ 41 - export function useNumColumns(type: 'search' | 'shelf' = 'search'): number { 42 - const deviceSize = useDeviceSize(); 43 - 44 - if (type === 'search') { 45 - switch (deviceSize) { 46 - case 'compact': 47 - return 2; 48 - case 'medium': 49 - return 3; 50 - case 'expanded': 51 - return 4; 52 - } 53 - } else { 54 - // shelf type 55 - switch (deviceSize) { 56 - case 'compact': 57 - return 1; // List view on phones 58 - case 'medium': 59 - return 2; 60 - case 'expanded': 61 - return 3; 62 - } 63 - } 64 - } 65 - 66 - /** 67 - * Hook to get responsive padding/margins based on device size 68 - */ 69 - export function useResponsiveSpacing(): { 70 - horizontalPadding: number; 71 - gap: number; 72 - } { 73 - const deviceSize = useDeviceSize(); 74 - 75 - switch (deviceSize) { 76 - case 'compact': 77 - return { horizontalPadding: 16, gap: 16 }; 78 - case 'medium': 79 - return { horizontalPadding: 24, gap: 20 }; 80 - case 'expanded': 81 - return { horizontalPadding: 32, gap: 24 }; 82 - } 83 - } 84 - 85 - /** 86 - * Hook to determine if current orientation is landscape 87 - */ 88 - export function useIsLandscape(): boolean { 89 - const { width, height } = useWindowDimensions(); 90 - return width > height; 91 - } 92 - 93 - /** 94 - * Hook to get max content width for centered layouts 95 - * Prevents text from stretching too wide on tablets 96 - */ 97 - export function useMaxContentWidth(): number | undefined { 98 - const deviceSize = useDeviceSize(); 99 - 100 - switch (deviceSize) { 101 - case 'compact': 102 - return undefined; // Full width on phones 103 - case 'medium': 104 - return 600; 105 - case 'expanded': 106 - return 800; 107 - } 108 - }
+10 -4
apps/mobile/tsconfig.json
··· 2 2 "extends": "expo/tsconfig.base", 3 3 "compilerOptions": { 4 4 "strict": true, 5 - "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 - "baseUrl": ".", 7 5 "paths": { 8 - "@/*": ["src/*"] 6 + "@/*": [ 7 + "./*" 8 + ] 9 9 } 10 - } 10 + }, 11 + "include": [ 12 + "**/*.ts", 13 + "**/*.tsx", 14 + ".expo/types/**/*.ts", 15 + "expo-env.d.ts" 16 + ] 11 17 }
+1858 -393
pnpm-lock.yaml
··· 15 15 apps/mobile: 16 16 dependencies: 17 17 '@expo/vector-icons': 18 - specifier: ^15.0.0 18 + specifier: ^15.0.3 19 19 version: 15.0.3(expo-font@14.0.11(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 20 - '@opnshelf/api': 21 - specifier: workspace:* 22 - version: link:../../packages/api 23 - '@opnshelf/types': 24 - specifier: workspace:* 25 - version: link:../../packages/types 26 - '@tanstack/react-query': 27 - specifier: ^5.66.5 28 - version: 5.90.20(react@19.1.0) 29 - class-variance-authority: 30 - specifier: ^0.7.1 31 - version: 0.7.1 32 - clsx: 33 - specifier: ^2.1.1 34 - version: 2.1.1 20 + '@react-navigation/bottom-tabs': 21 + specifier: ^7.4.0 22 + version: 7.12.0(@react-navigation/native@7.1.28(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 23 + '@react-navigation/elements': 24 + specifier: ^2.6.3 25 + version: 2.9.5(@react-navigation/native@7.1.28(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 26 + '@react-navigation/native': 27 + specifier: ^7.1.8 28 + version: 7.1.28(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 35 29 expo: 36 30 specifier: ~54.0.33 37 - version: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 38 - expo-dev-client: 39 - specifier: ~6.0.20 40 - version: 6.0.20(expo@54.0.33) 31 + version: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 32 + expo-constants: 33 + specifier: ~18.0.13 34 + version: 18.0.13(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 35 + expo-font: 36 + specifier: ~14.0.11 37 + version: 14.0.11(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 38 + expo-haptics: 39 + specifier: ~15.0.8 40 + version: 15.0.8(expo@54.0.33) 41 + expo-image: 42 + specifier: ~3.0.11 43 + version: 3.0.11(expo@54.0.33)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 41 44 expo-linking: 42 45 specifier: ~8.0.11 43 46 version: 8.0.11(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 44 47 expo-router: 45 - specifier: ~4.0.22 46 - version: 4.0.22(expo-constants@18.0.13)(expo-linking@8.0.11)(expo@54.0.33)(react-dom@19.2.4(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 47 - expo-secure-store: 48 - specifier: ^15.0.8 49 - version: 15.0.8(expo@54.0.33) 48 + specifier: ~6.0.23 49 + version: 6.0.23(7b0271988d3f94ed3d3507a5fd980a46) 50 + expo-splash-screen: 51 + specifier: ~31.0.13 52 + version: 31.0.13(expo@54.0.33) 50 53 expo-status-bar: 51 54 specifier: ~3.0.9 52 55 version: 3.0.9(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 56 + expo-symbols: 57 + specifier: ~1.0.8 58 + version: 1.0.8(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 59 + expo-system-ui: 60 + specifier: ~6.0.9 61 + version: 6.0.9(expo@54.0.33)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 53 62 expo-web-browser: 54 - specifier: ~15.0.0 63 + specifier: ~15.0.10 55 64 version: 15.0.10(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 56 65 react: 57 66 specifier: 19.1.0 58 67 version: 19.1.0 68 + react-dom: 69 + specifier: 19.1.0 70 + version: 19.1.0(react@19.1.0) 59 71 react-native: 60 72 specifier: 0.81.5 61 73 version: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 74 + react-native-gesture-handler: 75 + specifier: ~2.28.0 76 + version: 2.28.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 77 + react-native-reanimated: 78 + specifier: ~4.1.1 79 + version: 4.1.6(@babel/core@7.28.6)(react-native-worklets@0.5.1(@babel/core@7.28.6)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 62 80 react-native-safe-area-context: 63 - specifier: ~5.6.2 81 + specifier: ~5.6.0 64 82 version: 5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 65 83 react-native-screens: 66 84 specifier: ~4.16.0 67 85 version: 4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 68 - tailwind-merge: 69 - specifier: ^3.4.0 70 - version: 3.4.0 71 - tailwindcss: 72 - specifier: ^4.1.18 73 - version: 4.1.18 74 - uniwind: 75 - specifier: ^1.2.7 76 - version: 1.2.7(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@4.1.18) 86 + react-native-web: 87 + specifier: ~0.21.0 88 + version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 89 + react-native-worklets: 90 + specifier: 0.5.1 91 + version: 0.5.1(@babel/core@7.28.6)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 77 92 devDependencies: 78 - '@types/node': 79 - specifier: ^25.2.2 80 - version: 25.2.2 81 93 '@types/react': 82 94 specifier: ~19.1.0 83 95 version: 19.1.17 96 + eslint: 97 + specifier: ^9.25.0 98 + version: 9.39.2(jiti@2.6.1) 99 + eslint-config-expo: 100 + specifier: ~10.0.0 101 + version: 10.0.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 84 102 typescript: 85 103 specifier: ~5.9.2 86 104 version: 5.9.3 ··· 1065 1083 peerDependencies: 1066 1084 '@babel/core': ^7.0.0-0 1067 1085 1086 + '@babel/plugin-transform-template-literals@7.27.1': 1087 + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} 1088 + engines: {node: '>=6.9.0'} 1089 + peerDependencies: 1090 + '@babel/core': ^7.0.0-0 1091 + 1068 1092 '@babel/plugin-transform-typescript@7.28.6': 1069 1093 resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} 1070 1094 engines: {node: '>=6.9.0'} ··· 1221 1245 1222 1246 '@date-fns/tz@1.4.1': 1223 1247 resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} 1248 + 1249 + '@egjs/hammerjs@2.0.17': 1250 + resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} 1251 + engines: {node: '>=0.8.0'} 1224 1252 1225 1253 '@electric-sql/pglite-socket@0.0.20': 1226 1254 resolution: {integrity: sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg==} ··· 1537 1565 '@expo/sdk-runtime-versions@1.0.0': 1538 1566 resolution: {integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==} 1539 1567 1540 - '@expo/server@0.5.3': 1541 - resolution: {integrity: sha512-WXsWzeBs5v/h0PUfHyNLLz07rwwO5myQ1A5DGYewyyGLmsyl61yVCe8AgAlp1wkiMsqhj2hZqI2u3K10QnCMrQ==} 1542 - 1543 1568 '@expo/spawn-async@1.7.2': 1544 1569 resolution: {integrity: sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==} 1545 1570 engines: {node: '>=12'} ··· 2178 2203 resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} 2179 2204 engines: {node: ^14.21.3 || >=16} 2180 2205 2206 + '@nolyfill/is-core-module@1.0.39': 2207 + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} 2208 + engines: {node: '>=12.4.0'} 2209 + 2181 2210 '@nuxt/opencollective@0.4.1': 2182 2211 resolution: {integrity: sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==} 2183 2212 engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} ··· 2645 2674 '@types/react-dom': 2646 2675 optional: true 2647 2676 2648 - '@radix-ui/react-compose-refs@1.0.0': 2649 - resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==} 2650 - peerDependencies: 2651 - react: ^16.8 || ^17.0 || ^18.0 2652 - 2653 2677 '@radix-ui/react-compose-refs@1.1.2': 2654 2678 resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} 2655 2679 peerDependencies: ··· 3020 3044 '@types/react-dom': 3021 3045 optional: true 3022 3046 3023 - '@radix-ui/react-slot@1.0.1': 3024 - resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==} 3047 + '@radix-ui/react-slot@1.2.0': 3048 + resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==} 3025 3049 peerDependencies: 3026 - react: ^16.8 || ^17.0 || ^18.0 3050 + '@types/react': '*' 3051 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 3052 + peerDependenciesMeta: 3053 + '@types/react': 3054 + optional: true 3027 3055 3028 3056 '@radix-ui/react-slot@1.2.3': 3029 3057 resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} ··· 3270 3298 resolution: {integrity: sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w==} 3271 3299 engines: {node: '>= 20.19.4'} 3272 3300 3301 + '@react-native/normalize-colors@0.74.89': 3302 + resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==} 3303 + 3273 3304 '@react-native/normalize-colors@0.81.5': 3274 3305 resolution: {integrity: sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==} 3275 3306 ··· 3472 3503 cpu: [x64] 3473 3504 os: [win32] 3474 3505 3506 + '@rtsao/scc@1.1.0': 3507 + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} 3508 + 3475 3509 '@scarf/scarf@1.4.0': 3476 3510 resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} 3477 3511 ··· 3540 3574 zod: 3541 3575 optional: true 3542 3576 3543 - '@tailwindcss/node@4.1.17': 3544 - resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} 3545 - 3546 3577 '@tailwindcss/node@4.1.18': 3547 3578 resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} 3548 3579 3549 - '@tailwindcss/oxide-android-arm64@4.1.17': 3550 - resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} 3551 - engines: {node: '>= 10'} 3552 - cpu: [arm64] 3553 - os: [android] 3554 - 3555 3580 '@tailwindcss/oxide-android-arm64@4.1.18': 3556 3581 resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} 3557 3582 engines: {node: '>= 10'} 3558 3583 cpu: [arm64] 3559 3584 os: [android] 3560 3585 3561 - '@tailwindcss/oxide-darwin-arm64@4.1.17': 3562 - resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} 3563 - engines: {node: '>= 10'} 3564 - cpu: [arm64] 3565 - os: [darwin] 3566 - 3567 3586 '@tailwindcss/oxide-darwin-arm64@4.1.18': 3568 3587 resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} 3569 3588 engines: {node: '>= 10'} 3570 3589 cpu: [arm64] 3571 3590 os: [darwin] 3572 3591 3573 - '@tailwindcss/oxide-darwin-x64@4.1.17': 3574 - resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} 3575 - engines: {node: '>= 10'} 3576 - cpu: [x64] 3577 - os: [darwin] 3578 - 3579 3592 '@tailwindcss/oxide-darwin-x64@4.1.18': 3580 3593 resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} 3581 3594 engines: {node: '>= 10'} 3582 3595 cpu: [x64] 3583 3596 os: [darwin] 3584 3597 3585 - '@tailwindcss/oxide-freebsd-x64@4.1.17': 3586 - resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} 3587 - engines: {node: '>= 10'} 3588 - cpu: [x64] 3589 - os: [freebsd] 3590 - 3591 3598 '@tailwindcss/oxide-freebsd-x64@4.1.18': 3592 3599 resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} 3593 3600 engines: {node: '>= 10'} 3594 3601 cpu: [x64] 3595 3602 os: [freebsd] 3596 3603 3597 - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': 3598 - resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} 3599 - engines: {node: '>= 10'} 3600 - cpu: [arm] 3601 - os: [linux] 3602 - 3603 3604 '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': 3604 3605 resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} 3605 3606 engines: {node: '>= 10'} 3606 3607 cpu: [arm] 3607 3608 os: [linux] 3608 3609 3609 - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': 3610 - resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} 3611 - engines: {node: '>= 10'} 3612 - cpu: [arm64] 3613 - os: [linux] 3614 - libc: [glibc] 3615 - 3616 3610 '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': 3617 3611 resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} 3618 3612 engines: {node: '>= 10'} ··· 3620 3614 os: [linux] 3621 3615 libc: [glibc] 3622 3616 3623 - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': 3624 - resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} 3625 - engines: {node: '>= 10'} 3626 - cpu: [arm64] 3627 - os: [linux] 3628 - libc: [musl] 3629 - 3630 3617 '@tailwindcss/oxide-linux-arm64-musl@4.1.18': 3631 3618 resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} 3632 3619 engines: {node: '>= 10'} ··· 3634 3621 os: [linux] 3635 3622 libc: [musl] 3636 3623 3637 - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': 3638 - resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} 3639 - engines: {node: '>= 10'} 3640 - cpu: [x64] 3641 - os: [linux] 3642 - libc: [glibc] 3643 - 3644 3624 '@tailwindcss/oxide-linux-x64-gnu@4.1.18': 3645 3625 resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} 3646 3626 engines: {node: '>= 10'} 3647 3627 cpu: [x64] 3648 3628 os: [linux] 3649 3629 libc: [glibc] 3650 - 3651 - '@tailwindcss/oxide-linux-x64-musl@4.1.17': 3652 - resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} 3653 - engines: {node: '>= 10'} 3654 - cpu: [x64] 3655 - os: [linux] 3656 - libc: [musl] 3657 3630 3658 3631 '@tailwindcss/oxide-linux-x64-musl@4.1.18': 3659 3632 resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} ··· 3662 3635 os: [linux] 3663 3636 libc: [musl] 3664 3637 3665 - '@tailwindcss/oxide-wasm32-wasi@4.1.17': 3666 - resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} 3667 - engines: {node: '>=14.0.0'} 3668 - cpu: [wasm32] 3669 - bundledDependencies: 3670 - - '@napi-rs/wasm-runtime' 3671 - - '@emnapi/core' 3672 - - '@emnapi/runtime' 3673 - - '@tybys/wasm-util' 3674 - - '@emnapi/wasi-threads' 3675 - - tslib 3676 - 3677 3638 '@tailwindcss/oxide-wasm32-wasi@4.1.18': 3678 3639 resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} 3679 3640 engines: {node: '>=14.0.0'} ··· 3686 3647 - '@emnapi/wasi-threads' 3687 3648 - tslib 3688 3649 3689 - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': 3690 - resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} 3691 - engines: {node: '>= 10'} 3692 - cpu: [arm64] 3693 - os: [win32] 3694 - 3695 3650 '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': 3696 3651 resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} 3697 3652 engines: {node: '>= 10'} 3698 3653 cpu: [arm64] 3699 3654 os: [win32] 3700 3655 3701 - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': 3702 - resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} 3703 - engines: {node: '>= 10'} 3704 - cpu: [x64] 3705 - os: [win32] 3706 - 3707 3656 '@tailwindcss/oxide-win32-x64-msvc@4.1.18': 3708 3657 resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} 3709 3658 engines: {node: '>= 10'} 3710 3659 cpu: [x64] 3711 3660 os: [win32] 3712 - 3713 - '@tailwindcss/oxide@4.1.17': 3714 - resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} 3715 - engines: {node: '>= 10'} 3716 3661 3717 3662 '@tailwindcss/oxide@4.1.18': 3718 3663 resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} ··· 4024 3969 '@types/graceful-fs@4.1.9': 4025 3970 resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} 4026 3971 3972 + '@types/hammerjs@2.0.46': 3973 + resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} 3974 + 4027 3975 '@types/http-errors@2.0.5': 4028 3976 resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} 4029 3977 ··· 4042 3990 '@types/json-schema@7.0.15': 4043 3991 resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 4044 3992 3993 + '@types/json5@0.0.29': 3994 + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} 3995 + 4045 3996 '@types/methods@1.1.4': 4046 3997 resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} 4047 3998 ··· 4050 4001 4051 4002 '@types/node@22.19.7': 4052 4003 resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==} 4053 - 4054 - '@types/node@25.2.2': 4055 - resolution: {integrity: sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==} 4056 4004 4057 4005 '@types/qs@6.14.0': 4058 4006 resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} ··· 4501 4449 aria-query@5.3.0: 4502 4450 resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} 4503 4451 4452 + array-buffer-byte-length@1.0.2: 4453 + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} 4454 + engines: {node: '>= 0.4'} 4455 + 4504 4456 array-flatten@1.1.1: 4505 4457 resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} 4458 + 4459 + array-includes@3.1.9: 4460 + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} 4461 + engines: {node: '>= 0.4'} 4506 4462 4507 4463 array-timsort@1.0.3: 4508 4464 resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} 4509 4465 4466 + array.prototype.findlast@1.2.5: 4467 + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} 4468 + engines: {node: '>= 0.4'} 4469 + 4470 + array.prototype.findlastindex@1.2.6: 4471 + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} 4472 + engines: {node: '>= 0.4'} 4473 + 4474 + array.prototype.flat@1.3.3: 4475 + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} 4476 + engines: {node: '>= 0.4'} 4477 + 4478 + array.prototype.flatmap@1.3.3: 4479 + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} 4480 + engines: {node: '>= 0.4'} 4481 + 4482 + array.prototype.tosorted@1.1.4: 4483 + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} 4484 + engines: {node: '>= 0.4'} 4485 + 4486 + arraybuffer.prototype.slice@1.0.4: 4487 + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} 4488 + engines: {node: '>= 0.4'} 4489 + 4510 4490 asap@2.0.6: 4511 4491 resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} 4512 4492 ··· 4518 4498 resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} 4519 4499 engines: {node: '>=4'} 4520 4500 4501 + async-function@1.0.0: 4502 + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} 4503 + engines: {node: '>= 0.4'} 4504 + 4521 4505 async-limiter@1.0.1: 4522 4506 resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} 4523 4507 ··· 4527 4511 atomic-sleep@1.0.0: 4528 4512 resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} 4529 4513 engines: {node: '>=8.0.0'} 4514 + 4515 + available-typed-arrays@1.0.7: 4516 + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} 4517 + engines: {node: '>= 0.4'} 4530 4518 4531 4519 await-lock@2.2.2: 4532 4520 resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} ··· 4744 4732 4745 4733 call-bind-apply-helpers@1.0.2: 4746 4734 resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 4735 + engines: {node: '>= 0.4'} 4736 + 4737 + call-bind@1.0.8: 4738 + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} 4747 4739 engines: {node: '>= 0.4'} 4748 4740 4749 4741 call-bound@1.0.4: ··· 5059 5051 create-require@1.1.1: 5060 5052 resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} 5061 5053 5054 + cross-fetch@3.2.0: 5055 + resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} 5056 + 5062 5057 cross-spawn@7.0.6: 5063 5058 resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 5064 5059 engines: {node: '>= 8'} ··· 5074 5069 crypto-random-string@2.0.0: 5075 5070 resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} 5076 5071 engines: {node: '>=8'} 5072 + 5073 + css-in-js-utils@3.1.0: 5074 + resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} 5077 5075 5078 5076 css-select@5.2.2: 5079 5077 resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} ··· 5093 5091 csstype@3.2.3: 5094 5092 resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} 5095 5093 5096 - culori@4.0.2: 5097 - resolution: {integrity: sha512-1+BhOB8ahCn4O0cep0Sh2l9KCOfOdY+BXJnKMHFFzDEouSr/el18QwXEMRlOj9UY5nCeA8UN3a/82rUWRBeyBw==} 5098 - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 5099 - 5100 5094 data-urls@6.0.1: 5101 5095 resolution: {integrity: sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==} 5102 5096 engines: {node: '>=20'} 5097 + 5098 + data-view-buffer@1.0.2: 5099 + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} 5100 + engines: {node: '>= 0.4'} 5101 + 5102 + data-view-byte-length@1.0.2: 5103 + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} 5104 + engines: {node: '>= 0.4'} 5105 + 5106 + data-view-byte-offset@1.0.1: 5107 + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} 5108 + engines: {node: '>= 0.4'} 5103 5109 5104 5110 date-fns-jalali@4.1.0-0: 5105 5111 resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} ··· 5204 5210 defaults@1.0.4: 5205 5211 resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} 5206 5212 5213 + define-data-property@1.1.4: 5214 + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} 5215 + engines: {node: '>= 0.4'} 5216 + 5207 5217 define-lazy-prop@2.0.0: 5208 5218 resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} 5209 5219 engines: {node: '>=8'} ··· 5211 5221 define-lazy-prop@3.0.0: 5212 5222 resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} 5213 5223 engines: {node: '>=12'} 5224 + 5225 + define-properties@1.2.1: 5226 + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} 5227 + engines: {node: '>= 0.4'} 5214 5228 5215 5229 defu@6.1.4: 5216 5230 resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} ··· 5259 5273 diff@8.0.3: 5260 5274 resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} 5261 5275 engines: {node: '>=0.3.1'} 5276 + 5277 + doctrine@2.1.0: 5278 + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} 5279 + engines: {node: '>=0.10.0'} 5262 5280 5263 5281 dom-accessibility-api@0.5.16: 5264 5282 resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} ··· 5366 5384 error-stack-parser@2.1.4: 5367 5385 resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} 5368 5386 5387 + es-abstract@1.24.1: 5388 + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} 5389 + engines: {node: '>= 0.4'} 5390 + 5369 5391 es-define-property@1.0.1: 5370 5392 resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 5371 5393 engines: {node: '>= 0.4'} 5372 5394 5373 5395 es-errors@1.3.0: 5374 5396 resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 5397 + engines: {node: '>= 0.4'} 5398 + 5399 + es-iterator-helpers@1.2.2: 5400 + resolution: {integrity: sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==} 5375 5401 engines: {node: '>= 0.4'} 5376 5402 5377 5403 es-module-lexer@1.7.0: ··· 5388 5414 resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} 5389 5415 engines: {node: '>= 0.4'} 5390 5416 5417 + es-shim-unscopables@1.1.0: 5418 + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} 5419 + engines: {node: '>= 0.4'} 5420 + 5421 + es-to-primitive@1.3.0: 5422 + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} 5423 + engines: {node: '>= 0.4'} 5424 + 5391 5425 esbuild@0.27.2: 5392 5426 resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} 5393 5427 engines: {node: '>=18'} ··· 5412 5446 resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 5413 5447 engines: {node: '>=10'} 5414 5448 5449 + eslint-config-expo@10.0.0: 5450 + resolution: {integrity: sha512-/XC/DvniUWTzU7Ypb/cLDhDD4DXqEio4lug1ObD/oQ9Hcx3OVOR8Mkp4u6U4iGoZSJyIQmIk3WVHe/P1NYUXKw==} 5451 + peerDependencies: 5452 + eslint: '>=8.10' 5453 + 5415 5454 eslint-config-prettier@10.1.8: 5416 5455 resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} 5417 5456 hasBin: true 5418 5457 peerDependencies: 5419 5458 eslint: '>=7.0.0' 5420 5459 5460 + eslint-import-resolver-node@0.3.9: 5461 + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} 5462 + 5463 + eslint-import-resolver-typescript@3.10.1: 5464 + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} 5465 + engines: {node: ^14.18.0 || >=16.0.0} 5466 + peerDependencies: 5467 + eslint: '*' 5468 + eslint-plugin-import: '*' 5469 + eslint-plugin-import-x: '*' 5470 + peerDependenciesMeta: 5471 + eslint-plugin-import: 5472 + optional: true 5473 + eslint-plugin-import-x: 5474 + optional: true 5475 + 5476 + eslint-module-utils@2.12.1: 5477 + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} 5478 + engines: {node: '>=4'} 5479 + peerDependencies: 5480 + '@typescript-eslint/parser': '*' 5481 + eslint: '*' 5482 + eslint-import-resolver-node: '*' 5483 + eslint-import-resolver-typescript: '*' 5484 + eslint-import-resolver-webpack: '*' 5485 + peerDependenciesMeta: 5486 + '@typescript-eslint/parser': 5487 + optional: true 5488 + eslint: 5489 + optional: true 5490 + eslint-import-resolver-node: 5491 + optional: true 5492 + eslint-import-resolver-typescript: 5493 + optional: true 5494 + eslint-import-resolver-webpack: 5495 + optional: true 5496 + 5497 + eslint-plugin-expo@1.0.0: 5498 + resolution: {integrity: sha512-qLtunR+cNFtC+jwYCBia5c/PJurMjSLMOV78KrEOyQK02ohZapU4dCFFnS2hfrJuw0zxfsjVkjqg3QBqi933QA==} 5499 + engines: {node: '>=18.0.0'} 5500 + peerDependencies: 5501 + eslint: '>=8.10' 5502 + 5503 + eslint-plugin-import@2.32.0: 5504 + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} 5505 + engines: {node: '>=4'} 5506 + peerDependencies: 5507 + '@typescript-eslint/parser': '*' 5508 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 5509 + peerDependenciesMeta: 5510 + '@typescript-eslint/parser': 5511 + optional: true 5512 + 5421 5513 eslint-plugin-prettier@5.5.5: 5422 5514 resolution: {integrity: sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==} 5423 5515 engines: {node: ^14.18.0 || >=16.0.0} ··· 5431 5523 optional: true 5432 5524 eslint-config-prettier: 5433 5525 optional: true 5526 + 5527 + eslint-plugin-react-hooks@5.2.0: 5528 + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} 5529 + engines: {node: '>=10'} 5530 + peerDependencies: 5531 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 5532 + 5533 + eslint-plugin-react@7.37.5: 5534 + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} 5535 + engines: {node: '>=4'} 5536 + peerDependencies: 5537 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 5434 5538 5435 5539 eslint-scope@5.1.1: 5436 5540 resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} ··· 5544 5648 expo: '*' 5545 5649 react-native: '*' 5546 5650 5547 - expo-dev-client@6.0.20: 5548 - resolution: {integrity: sha512-5XjoVlj1OxakNxy55j/AUaGPrDOlQlB6XdHLLWAw61w5ffSpUDHDnuZzKzs9xY1eIaogOqTOQaAzZ2ddBkdXLA==} 5651 + expo-file-system@19.0.21: 5652 + resolution: {integrity: sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg==} 5549 5653 peerDependencies: 5550 5654 expo: '*' 5655 + react-native: '*' 5551 5656 5552 - expo-dev-launcher@6.0.20: 5553 - resolution: {integrity: sha512-a04zHEeT9sB0L5EB38fz7sNnUKJ2Ar1pXpcyl60Ki8bXPNCs9rjY7NuYrDkP/irM8+1DklMBqHpyHiLyJ/R+EA==} 5657 + expo-font@14.0.11: 5658 + resolution: {integrity: sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==} 5554 5659 peerDependencies: 5555 5660 expo: '*' 5661 + react: '*' 5662 + react-native: '*' 5556 5663 5557 - expo-dev-menu-interface@2.0.0: 5558 - resolution: {integrity: sha512-BvAMPt6x+vyXpThsyjjOYyjwfjREV4OOpQkZ0tNl+nGpsPfcY9mc6DRACoWnH9KpLzyIt3BOgh3cuy/h/OxQjw==} 5664 + expo-haptics@15.0.8: 5665 + resolution: {integrity: sha512-lftutojy8Qs8zaDzzjwM3gKHFZ8bOOEZDCkmh2Ddpe95Ra6kt2izeOfOfKuP/QEh0MZ1j9TfqippyHdRd1ZM9g==} 5559 5666 peerDependencies: 5560 5667 expo: '*' 5561 5668 5562 - expo-dev-menu@7.0.18: 5563 - resolution: {integrity: sha512-4kTdlHrnZCAWCT6tZRQHSSjZ7vECFisL4T+nsG/GJDo/jcHNaOVGV5qPV9wzlTxyMk3YOPggRw4+g7Ownrg5eA==} 5564 - peerDependencies: 5565 - expo: '*' 5566 - 5567 - expo-file-system@19.0.21: 5568 - resolution: {integrity: sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg==} 5569 - peerDependencies: 5570 - expo: '*' 5571 - react-native: '*' 5572 - 5573 - expo-font@14.0.11: 5574 - resolution: {integrity: sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==} 5669 + expo-image@3.0.11: 5670 + resolution: {integrity: sha512-4TudfUCLgYgENv+f48omnU8tjS2S0Pd9EaON5/s1ZUBRwZ7K8acEr4NfvLPSaeXvxW24iLAiyQ7sV7BXQH3RoA==} 5575 5671 peerDependencies: 5576 5672 expo: '*' 5577 5673 react: '*' 5578 5674 react-native: '*' 5579 - 5580 - expo-json-utils@0.15.0: 5581 - resolution: {integrity: sha512-duRT6oGl80IDzH2LD2yEFWNwGIC2WkozsB6HF3cDYNoNNdUvFk6uN3YiwsTsqVM/D0z6LEAQ01/SlYvN+Fw0JQ==} 5675 + react-native-web: '*' 5676 + peerDependenciesMeta: 5677 + react-native-web: 5678 + optional: true 5582 5679 5583 5680 expo-keep-awake@15.0.8: 5584 5681 resolution: {integrity: sha512-YK9M1VrnoH1vLJiQzChZgzDvVimVoriibiDIFLbQMpjYBnvyfUeHJcin/Gx1a+XgupNXy92EQJLgI/9ZuXajYQ==} ··· 5592 5689 react: '*' 5593 5690 react-native: '*' 5594 5691 5595 - expo-manifests@1.0.10: 5596 - resolution: {integrity: sha512-oxDUnURPcL4ZsOBY6X1DGWGuoZgVAFzp6PISWV7lPP2J0r8u1/ucuChBgpK7u1eLGFp6sDIPwXyEUCkI386XSQ==} 5597 - peerDependencies: 5598 - expo: '*' 5599 - 5600 5692 expo-modules-autolinking@3.0.24: 5601 5693 resolution: {integrity: sha512-TP+6HTwhL7orDvsz2VzauyQlXJcAWyU3ANsZ7JGL4DQu8XaZv/A41ZchbtAYLfozNA2Ya1Hzmhx65hXryBMjaQ==} 5602 5694 hasBin: true ··· 5607 5699 react: '*' 5608 5700 react-native: '*' 5609 5701 5610 - expo-router@4.0.22: 5611 - resolution: {integrity: sha512-cbl6pWUMMZl5sZaHSMmxhQi+kTC6Yzj0ATaD2j6MiLF6VQyr5IcWes3V0UxPtI08boTX0i+76/fnP5fZ3eGQYQ==} 5702 + expo-router@6.0.23: 5703 + resolution: {integrity: sha512-qCxVAiCrCyu0npky6azEZ6dJDMt77OmCzEbpF6RbUTlfkaCA417LvY14SBkk0xyGruSxy/7pvJOI6tuThaUVCA==} 5612 5704 peerDependencies: 5613 - '@react-navigation/drawer': ^7.1.1 5614 - '@testing-library/jest-native': '*' 5705 + '@expo/metro-runtime': ^6.1.2 5706 + '@react-navigation/drawer': ^7.5.0 5707 + '@testing-library/react-native': '>= 12.0.0' 5615 5708 expo: '*' 5616 - expo-constants: ~17.0.8 5617 - expo-linking: ~7.0.5 5709 + expo-constants: ^18.0.13 5710 + expo-linking: ^8.0.11 5711 + react: '*' 5712 + react-dom: '*' 5713 + react-native: '*' 5714 + react-native-gesture-handler: '*' 5618 5715 react-native-reanimated: '*' 5619 - react-native-safe-area-context: '*' 5716 + react-native-safe-area-context: '>= 5.4.0' 5620 5717 react-native-screens: '*' 5718 + react-native-web: '*' 5719 + react-server-dom-webpack: ~19.0.4 || ~19.1.5 || ~19.2.4 5621 5720 peerDependenciesMeta: 5622 5721 '@react-navigation/drawer': 5623 5722 optional: true 5624 - '@testing-library/jest-native': 5723 + '@testing-library/react-native': 5724 + optional: true 5725 + react-dom: 5726 + optional: true 5727 + react-native-gesture-handler: 5625 5728 optional: true 5626 5729 react-native-reanimated: 5627 5730 optional: true 5628 - 5629 - expo-secure-store@15.0.8: 5630 - resolution: {integrity: sha512-lHnzvRajBu4u+P99+0GEMijQMFCOYpWRO4dWsXSuMt77+THPIGjzNvVKrGSl6mMrLsfVaKL8BpwYZLGlgA+zAw==} 5631 - peerDependencies: 5632 - expo: '*' 5731 + react-native-web: 5732 + optional: true 5733 + react-server-dom-webpack: 5734 + optional: true 5633 5735 5634 5736 expo-server@1.0.5: 5635 5737 resolution: {integrity: sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA==} 5636 5738 engines: {node: '>=20.16.0'} 5637 5739 5740 + expo-splash-screen@31.0.13: 5741 + resolution: {integrity: sha512-1epJLC1cDlwwj089R2h8cxaU5uk4ONVAC+vzGiTZH4YARQhL4Stlz1MbR6yAS173GMosvkE6CAeihR7oIbCkDA==} 5742 + peerDependencies: 5743 + expo: '*' 5744 + 5638 5745 expo-status-bar@3.0.9: 5639 5746 resolution: {integrity: sha512-xyYyVg6V1/SSOZWh4Ni3U129XHCnFHBTcUo0dhWtFDrZbNp/duw5AGsQfb2sVeU0gxWHXSY1+5F0jnKYC7WuOw==} 5640 5747 peerDependencies: 5641 5748 react: '*' 5642 5749 react-native: '*' 5643 5750 5644 - expo-updates-interface@2.0.0: 5645 - resolution: {integrity: sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg==} 5751 + expo-symbols@1.0.8: 5752 + resolution: {integrity: sha512-7bNjK350PaQgxBf0owpmSYkdZIpdYYmaPttDBb2WIp6rIKtcEtdzdfmhsc2fTmjBURHYkg36+eCxBFXO25/1hw==} 5646 5753 peerDependencies: 5647 5754 expo: '*' 5755 + react-native: '*' 5756 + 5757 + expo-system-ui@6.0.9: 5758 + resolution: {integrity: sha512-eQTYGzw1V4RYiYHL9xDLYID3Wsec2aZS+ypEssmF64D38aDrqbDgz1a2MSlHLQp2jHXSs3FvojhZ9FVela1Zcg==} 5759 + peerDependencies: 5760 + expo: '*' 5761 + react-native: '*' 5762 + react-native-web: '*' 5763 + peerDependenciesMeta: 5764 + react-native-web: 5765 + optional: true 5648 5766 5649 5767 expo-web-browser@15.0.10: 5650 5768 resolution: {integrity: sha512-fvDhW4bhmXAeWFNFiInmsGCK83PAqAcQaFyp/3pE/jbdKmFKoRCWr46uZGIfN4msLK/OODhaQ/+US7GSJNDHJg==} ··· 5712 5830 fb-watchman@2.0.2: 5713 5831 resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} 5714 5832 5833 + fbjs-css-vars@1.0.2: 5834 + resolution: {integrity: sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==} 5835 + 5836 + fbjs@3.0.5: 5837 + resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==} 5838 + 5715 5839 fdir@6.5.0: 5716 5840 resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 5717 5841 engines: {node: '>=12.0.0'} ··· 5774 5898 fontfaceobserver@2.3.0: 5775 5899 resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} 5776 5900 5901 + for-each@0.3.5: 5902 + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} 5903 + engines: {node: '>= 0.4'} 5904 + 5777 5905 foreground-child@3.3.1: 5778 5906 resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 5779 5907 engines: {node: '>=14'} ··· 5829 5957 5830 5958 function-bind@1.1.2: 5831 5959 resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 5960 + 5961 + function.prototype.name@1.1.8: 5962 + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} 5963 + engines: {node: '>= 0.4'} 5964 + 5965 + functions-have-names@1.2.3: 5966 + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} 5832 5967 5833 5968 generate-function@2.3.1: 5834 5969 resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} 5835 5970 5971 + generator-function@2.0.1: 5972 + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} 5973 + engines: {node: '>= 0.4'} 5974 + 5836 5975 gensync@1.0.0-beta.2: 5837 5976 resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 5838 5977 engines: {node: '>=6.9.0'} ··· 5863 6002 get-stream@6.0.1: 5864 6003 resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 5865 6004 engines: {node: '>=10'} 6005 + 6006 + get-symbol-description@1.1.0: 6007 + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} 6008 + engines: {node: '>= 0.4'} 5866 6009 5867 6010 get-tsconfig@4.13.0: 5868 6011 resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} ··· 5916 6059 resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} 5917 6060 engines: {node: '>=18'} 5918 6061 6062 + globalthis@1.0.4: 6063 + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} 6064 + engines: {node: '>= 0.4'} 6065 + 5919 6066 globrex@0.1.2: 5920 6067 resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} 5921 6068 ··· 5951 6098 engines: {node: '>=0.4.7'} 5952 6099 hasBin: true 5953 6100 6101 + has-bigints@1.1.0: 6102 + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} 6103 + engines: {node: '>= 0.4'} 6104 + 5954 6105 has-flag@3.0.0: 5955 6106 resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 5956 6107 engines: {node: '>=4'} ··· 5959 6110 resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 5960 6111 engines: {node: '>=8'} 5961 6112 6113 + has-property-descriptors@1.0.2: 6114 + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} 6115 + 6116 + has-proto@1.2.0: 6117 + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} 6118 + engines: {node: '>= 0.4'} 6119 + 5962 6120 has-symbols@1.1.0: 5963 6121 resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 5964 6122 engines: {node: '>= 0.4'} ··· 5982 6140 5983 6141 hermes-parser@0.32.0: 5984 6142 resolution: {integrity: sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==} 6143 + 6144 + hoist-non-react-statics@3.3.2: 6145 + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} 5985 6146 5986 6147 hono@4.11.4: 5987 6148 resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==} ··· 6020 6181 resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 6021 6182 engines: {node: '>=10.17.0'} 6022 6183 6184 + hyphenate-style-name@1.1.0: 6185 + resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} 6186 + 6023 6187 iconv-lite@0.4.24: 6024 6188 resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} 6025 6189 engines: {node: '>=0.10.0'} ··· 6074 6238 ini@1.3.8: 6075 6239 resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} 6076 6240 6241 + inline-style-prefixer@7.0.1: 6242 + resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==} 6243 + 6244 + internal-slot@1.1.0: 6245 + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} 6246 + engines: {node: '>= 0.4'} 6247 + 6077 6248 invariant@2.2.4: 6078 6249 resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} 6079 6250 ··· 6084 6255 ipaddr.js@2.3.0: 6085 6256 resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} 6086 6257 engines: {node: '>= 10'} 6258 + 6259 + is-array-buffer@3.0.5: 6260 + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} 6261 + engines: {node: '>= 0.4'} 6087 6262 6088 6263 is-arrayish@0.2.1: 6089 6264 resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} ··· 6091 6266 is-arrayish@0.3.4: 6092 6267 resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} 6093 6268 6269 + is-async-function@2.1.1: 6270 + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} 6271 + engines: {node: '>= 0.4'} 6272 + 6273 + is-bigint@1.1.0: 6274 + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} 6275 + engines: {node: '>= 0.4'} 6276 + 6094 6277 is-binary-path@2.1.0: 6095 6278 resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 6096 6279 engines: {node: '>=8'} 6097 6280 6281 + is-boolean-object@1.2.2: 6282 + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} 6283 + engines: {node: '>= 0.4'} 6284 + 6285 + is-bun-module@2.0.0: 6286 + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} 6287 + 6288 + is-callable@1.2.7: 6289 + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} 6290 + engines: {node: '>= 0.4'} 6291 + 6098 6292 is-core-module@2.16.1: 6099 6293 resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 6100 6294 engines: {node: '>= 0.4'} 6101 6295 6296 + is-data-view@1.0.2: 6297 + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} 6298 + engines: {node: '>= 0.4'} 6299 + 6300 + is-date-object@1.1.0: 6301 + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} 6302 + engines: {node: '>= 0.4'} 6303 + 6102 6304 is-docker@2.2.1: 6103 6305 resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} 6104 6306 engines: {node: '>=8'} ··· 6113 6315 resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 6114 6316 engines: {node: '>=0.10.0'} 6115 6317 6318 + is-finalizationregistry@1.1.1: 6319 + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} 6320 + engines: {node: '>= 0.4'} 6321 + 6116 6322 is-fullwidth-code-point@3.0.0: 6117 6323 resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 6118 6324 engines: {node: '>=8'} ··· 6120 6326 is-generator-fn@2.1.0: 6121 6327 resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} 6122 6328 engines: {node: '>=6'} 6329 + 6330 + is-generator-function@1.1.2: 6331 + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} 6332 + engines: {node: '>= 0.4'} 6123 6333 6124 6334 is-glob@4.0.3: 6125 6335 resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} ··· 6138 6348 resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} 6139 6349 engines: {node: '>=8'} 6140 6350 6351 + is-map@2.0.3: 6352 + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} 6353 + engines: {node: '>= 0.4'} 6354 + 6355 + is-negative-zero@2.0.3: 6356 + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} 6357 + engines: {node: '>= 0.4'} 6358 + 6359 + is-number-object@1.1.1: 6360 + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} 6361 + engines: {node: '>= 0.4'} 6362 + 6141 6363 is-number@7.0.0: 6142 6364 resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 6143 6365 engines: {node: '>=0.12.0'} ··· 6151 6373 is-property@1.0.2: 6152 6374 resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} 6153 6375 6376 + is-regex@1.2.1: 6377 + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} 6378 + engines: {node: '>= 0.4'} 6379 + 6380 + is-set@2.0.3: 6381 + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} 6382 + engines: {node: '>= 0.4'} 6383 + 6384 + is-shared-array-buffer@1.0.4: 6385 + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} 6386 + engines: {node: '>= 0.4'} 6387 + 6154 6388 is-stream@2.0.1: 6155 6389 resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 6156 6390 engines: {node: '>=8'} 6157 6391 6392 + is-string@1.1.1: 6393 + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} 6394 + engines: {node: '>= 0.4'} 6395 + 6396 + is-symbol@1.1.1: 6397 + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} 6398 + engines: {node: '>= 0.4'} 6399 + 6400 + is-typed-array@1.1.15: 6401 + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} 6402 + engines: {node: '>= 0.4'} 6403 + 6158 6404 is-unicode-supported@0.1.0: 6159 6405 resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} 6160 6406 engines: {node: '>=10'} 6407 + 6408 + is-weakmap@2.0.2: 6409 + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} 6410 + engines: {node: '>= 0.4'} 6411 + 6412 + is-weakref@1.1.1: 6413 + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} 6414 + engines: {node: '>= 0.4'} 6415 + 6416 + is-weakset@2.0.4: 6417 + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} 6418 + engines: {node: '>= 0.4'} 6161 6419 6162 6420 is-wsl@2.2.0: 6163 6421 resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} ··· 6167 6425 resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} 6168 6426 engines: {node: '>=16'} 6169 6427 6428 + isarray@2.0.5: 6429 + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} 6430 + 6170 6431 isbot@5.1.34: 6171 6432 resolution: {integrity: sha512-aCMIBSKd/XPRYdiCQTLC8QHH4YT8B3JUADu+7COgYIZPvkeoMcUHMRjZLM9/7V8fCj+l7FSREc1lOPNjzogo/A==} 6172 6433 engines: {node: '>=18'} ··· 6204 6465 iterare@1.2.1: 6205 6466 resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} 6206 6467 engines: {node: '>=6'} 6468 + 6469 + iterator.prototype@1.1.5: 6470 + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} 6471 + engines: {node: '>= 0.4'} 6207 6472 6208 6473 jackspeak@3.4.3: 6209 6474 resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} ··· 6439 6704 json-stable-stringify-without-jsonify@1.0.1: 6440 6705 resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 6441 6706 6707 + json5@1.0.2: 6708 + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} 6709 + hasBin: true 6710 + 6442 6711 json5@2.2.3: 6443 6712 resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 6444 6713 engines: {node: '>=6'} ··· 6449 6718 6450 6719 jsonfile@6.2.0: 6451 6720 resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} 6721 + 6722 + jsx-ast-utils@3.3.5: 6723 + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} 6724 + engines: {node: '>=4.0'} 6452 6725 6453 6726 keyv@4.5.4: 6454 6727 resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} ··· 6745 7018 6746 7019 memoize-one@5.2.1: 6747 7020 resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} 7021 + 7022 + memoize-one@6.0.0: 7023 + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} 6748 7024 6749 7025 merge-descriptors@1.0.3: 6750 7026 resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} ··· 6999 7275 node-fetch-native@1.6.7: 7000 7276 resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} 7001 7277 7278 + node-fetch@2.7.0: 7279 + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} 7280 + engines: {node: 4.x || >=6.0.0} 7281 + peerDependencies: 7282 + encoding: ^0.1.0 7283 + peerDependenciesMeta: 7284 + encoding: 7285 + optional: true 7286 + 7002 7287 node-forge@1.3.3: 7003 7288 resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} 7004 7289 engines: {node: '>= 6.13.0'} ··· 7044 7329 resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} 7045 7330 engines: {node: '>= 0.4'} 7046 7331 7332 + object-keys@1.1.1: 7333 + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} 7334 + engines: {node: '>= 0.4'} 7335 + 7336 + object.assign@4.1.7: 7337 + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} 7338 + engines: {node: '>= 0.4'} 7339 + 7340 + object.entries@1.1.9: 7341 + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} 7342 + engines: {node: '>= 0.4'} 7343 + 7344 + object.fromentries@2.0.8: 7345 + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} 7346 + engines: {node: '>= 0.4'} 7347 + 7348 + object.groupby@1.0.3: 7349 + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} 7350 + engines: {node: '>= 0.4'} 7351 + 7352 + object.values@1.2.1: 7353 + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} 7354 + engines: {node: '>= 0.4'} 7355 + 7047 7356 ofetch@2.0.0-alpha.3: 7048 7357 resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==} 7049 7358 ··· 7104 7413 resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} 7105 7414 engines: {node: '>=10'} 7106 7415 7416 + own-keys@1.0.1: 7417 + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} 7418 + engines: {node: '>= 0.4'} 7419 + 7107 7420 oxc-minify@0.111.0: 7108 7421 resolution: {integrity: sha512-tooT6OU4dv8esdLxpELcBYc3R3zN+Bn0llM58RP8djBrxN57l7E5KqfTFq035kEaYl58C0fEgsOEL9G6zO6oQA==} 7109 7422 engines: {node: ^20.19.0 || >=22.12.0} ··· 7338 7651 resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} 7339 7652 engines: {node: '>=14.19.0'} 7340 7653 7654 + possible-typed-array-names@1.1.0: 7655 + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} 7656 + engines: {node: '>= 0.4'} 7657 + 7658 + postcss-value-parser@4.2.0: 7659 + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 7660 + 7341 7661 postcss@8.4.49: 7342 7662 resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} 7343 7663 engines: {node: ^10 || ^12 || >=14} ··· 7436 7756 resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} 7437 7757 engines: {node: '>=0.4.0'} 7438 7758 7759 + promise@7.3.1: 7760 + resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} 7761 + 7439 7762 promise@8.3.0: 7440 7763 resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} 7441 7764 ··· 7530 7853 7531 7854 react-devtools-core@6.1.5: 7532 7855 resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} 7856 + 7857 + react-dom@19.1.0: 7858 + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} 7859 + peerDependencies: 7860 + react: ^19.1.0 7533 7861 7534 7862 react-dom@19.2.4: 7535 7863 resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} ··· 7545 7873 peerDependencies: 7546 7874 react: '>=17.0.0' 7547 7875 7548 - react-helmet-async@1.3.0: 7549 - resolution: {integrity: sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==} 7550 - peerDependencies: 7551 - react: ^16.6.0 || ^17.0.0 || ^18.0.0 7552 - react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 7553 - 7554 7876 react-is@16.13.1: 7555 7877 resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} 7556 7878 ··· 7563 7885 react-is@19.2.4: 7564 7886 resolution: {integrity: sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==} 7565 7887 7566 - react-native-helmet-async@2.0.4: 7567 - resolution: {integrity: sha512-m3CkXWss6B1dd6mCMleLpzDCJJGGaHOLQsUzZv8kAASJmMfmVT4d2fx375iXKTRWT25ThBfae3dECuX5cq/8hg==} 7888 + react-native-gesture-handler@2.28.0: 7889 + resolution: {integrity: sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==} 7568 7890 peerDependencies: 7569 - react: ^16.6.0 || ^17.0.0 || ^18.0.0 7891 + react: '*' 7892 + react-native: '*' 7570 7893 7571 7894 react-native-is-edge-to-edge@1.2.1: 7572 7895 resolution: {integrity: sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==} ··· 7574 7897 react: '*' 7575 7898 react-native: '*' 7576 7899 7900 + react-native-reanimated@4.1.6: 7901 + resolution: {integrity: sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ==} 7902 + peerDependencies: 7903 + '@babel/core': ^7.0.0-0 7904 + react: '*' 7905 + react-native: '*' 7906 + react-native-worklets: '>=0.5.0' 7907 + 7577 7908 react-native-safe-area-context@5.6.2: 7578 7909 resolution: {integrity: sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==} 7579 7910 peerDependencies: ··· 7583 7914 react-native-screens@4.16.0: 7584 7915 resolution: {integrity: sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==} 7585 7916 peerDependencies: 7917 + react: '*' 7918 + react-native: '*' 7919 + 7920 + react-native-web@0.21.2: 7921 + resolution: {integrity: sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==} 7922 + peerDependencies: 7923 + react: ^18.0.0 || ^19.0.0 7924 + react-dom: ^18.0.0 || ^19.0.0 7925 + 7926 + react-native-worklets@0.5.1: 7927 + resolution: {integrity: sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==} 7928 + peerDependencies: 7929 + '@babel/core': ^7.0.0-0 7586 7930 react: '*' 7587 7931 react-native: '*' 7588 7932 ··· 7678 8022 reflect-metadata@0.2.2: 7679 8023 resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} 7680 8024 8025 + reflect.getprototypeof@1.0.10: 8026 + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} 8027 + engines: {node: '>= 0.4'} 8028 + 7681 8029 regenerate-unicode-properties@10.2.2: 7682 8030 resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} 7683 8031 engines: {node: '>=4'} ··· 7690 8038 7691 8039 regexp-to-ast@0.5.0: 7692 8040 resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==} 8041 + 8042 + regexp.prototype.flags@1.5.4: 8043 + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} 8044 + engines: {node: '>= 0.4'} 7693 8045 7694 8046 regexpu-core@6.4.0: 7695 8047 resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} ··· 7751 8103 resolve@1.7.1: 7752 8104 resolution: {integrity: sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==} 7753 8105 8106 + resolve@2.0.0-next.5: 8107 + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} 8108 + hasBin: true 8109 + 7754 8110 restore-cursor@2.0.0: 7755 8111 resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} 7756 8112 engines: {node: '>=4'} ··· 7790 8146 rxjs@7.8.2: 7791 8147 resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} 7792 8148 8149 + safe-array-concat@1.1.3: 8150 + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} 8151 + engines: {node: '>=0.4'} 8152 + 7793 8153 safe-buffer@5.2.1: 7794 8154 resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 7795 8155 8156 + safe-push-apply@1.0.0: 8157 + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} 8158 + engines: {node: '>= 0.4'} 8159 + 8160 + safe-regex-test@1.1.0: 8161 + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} 8162 + engines: {node: '>= 0.4'} 8163 + 7796 8164 safe-stable-stringify@2.5.0: 7797 8165 resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} 7798 8166 engines: {node: '>=10'} ··· 7828 8196 7829 8197 semver@7.6.3: 7830 8198 resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} 8199 + engines: {node: '>=10'} 8200 + hasBin: true 8201 + 8202 + semver@7.7.2: 8203 + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} 7831 8204 engines: {node: '>=10'} 7832 8205 hasBin: true 7833 8206 ··· 7875 8248 server-only@0.0.1: 7876 8249 resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} 7877 8250 8251 + set-function-length@1.2.2: 8252 + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} 8253 + engines: {node: '>= 0.4'} 8254 + 8255 + set-function-name@2.0.2: 8256 + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} 8257 + engines: {node: '>= 0.4'} 8258 + 8259 + set-proto@1.0.0: 8260 + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} 8261 + engines: {node: '>= 0.4'} 8262 + 8263 + setimmediate@1.0.5: 8264 + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} 8265 + 7878 8266 setprototypeof@1.2.0: 7879 8267 resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} 7880 8268 ··· 8004 8392 engines: {node: '>=20.16.0'} 8005 8393 hasBin: true 8006 8394 8395 + stable-hash@0.0.5: 8396 + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} 8397 + 8007 8398 stack-utils@2.0.6: 8008 8399 resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} 8009 8400 engines: {node: '>=10'} ··· 8029 8420 std-env@3.10.0: 8030 8421 resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} 8031 8422 8423 + stop-iteration-iterator@1.1.0: 8424 + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} 8425 + engines: {node: '>= 0.4'} 8426 + 8032 8427 stream-buffers@2.2.0: 8033 8428 resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==} 8034 8429 engines: {node: '>= 0.10.0'} ··· 8053 8448 resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 8054 8449 engines: {node: '>=12'} 8055 8450 8451 + string.prototype.matchall@4.0.12: 8452 + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} 8453 + engines: {node: '>= 0.4'} 8454 + 8455 + string.prototype.repeat@1.0.0: 8456 + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} 8457 + 8458 + string.prototype.trim@1.2.10: 8459 + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} 8460 + engines: {node: '>= 0.4'} 8461 + 8462 + string.prototype.trimend@1.0.9: 8463 + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} 8464 + engines: {node: '>= 0.4'} 8465 + 8466 + string.prototype.trimstart@1.0.8: 8467 + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} 8468 + engines: {node: '>= 0.4'} 8469 + 8056 8470 string_decoder@1.3.0: 8057 8471 resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 8058 8472 ··· 8102 8516 structured-headers@0.4.1: 8103 8517 resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==} 8104 8518 8519 + styleq@0.1.3: 8520 + resolution: {integrity: sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==} 8521 + 8105 8522 sucrase@3.35.1: 8106 8523 resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} 8107 8524 engines: {node: '>=16 || 14 >=14.17'} ··· 8157 8574 8158 8575 tailwind-merge@3.4.0: 8159 8576 resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} 8160 - 8161 - tailwindcss@4.1.17: 8162 - resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} 8163 8577 8164 8578 tailwindcss@4.1.18: 8165 8579 resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} ··· 8294 8708 resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} 8295 8709 engines: {node: '>=16'} 8296 8710 8711 + tr46@0.0.3: 8712 + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 8713 + 8297 8714 tr46@6.0.0: 8298 8715 resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} 8299 8716 engines: {node: '>=20'} ··· 8372 8789 resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} 8373 8790 engines: {node: '>=10.13.0'} 8374 8791 8792 + tsconfig-paths@3.15.0: 8793 + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} 8794 + 8375 8795 tsconfig-paths@4.2.0: 8376 8796 resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} 8377 8797 engines: {node: '>=6'} ··· 8452 8872 resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} 8453 8873 engines: {node: '>= 0.6'} 8454 8874 8875 + typed-array-buffer@1.0.3: 8876 + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} 8877 + engines: {node: '>= 0.4'} 8878 + 8879 + typed-array-byte-length@1.0.3: 8880 + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} 8881 + engines: {node: '>= 0.4'} 8882 + 8883 + typed-array-byte-offset@1.0.4: 8884 + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} 8885 + engines: {node: '>= 0.4'} 8886 + 8887 + typed-array-length@1.0.7: 8888 + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} 8889 + engines: {node: '>= 0.4'} 8890 + 8455 8891 typedarray@0.0.6: 8456 8892 resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} 8457 8893 ··· 8467 8903 engines: {node: '>=14.17'} 8468 8904 hasBin: true 8469 8905 8906 + ua-parser-js@1.0.41: 8907 + resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==} 8908 + hasBin: true 8909 + 8470 8910 ufo@1.6.3: 8471 8911 resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} 8472 8912 ··· 8486 8926 uint8arrays@3.0.0: 8487 8927 resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==} 8488 8928 8929 + unbox-primitive@1.1.0: 8930 + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} 8931 + engines: {node: '>= 0.4'} 8932 + 8489 8933 undici-types@6.21.0: 8490 8934 resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 8491 8935 8492 - undici-types@7.16.0: 8493 - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} 8494 - 8495 8936 undici@6.23.0: 8496 8937 resolution: {integrity: sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==} 8497 8938 engines: {node: '>=18.17'} ··· 8529 8970 universalify@2.0.1: 8530 8971 resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} 8531 8972 engines: {node: '>= 10.0.0'} 8532 - 8533 - uniwind@1.2.7: 8534 - resolution: {integrity: sha512-4aclu1rpqh9XSSyw8/3buNud7BAw7sPadX70WYXYp+9csgTGTqt9o/QaPPfpliULUSaG8ONDY1+gC4ylz+coyg==} 8535 - peerDependencies: 8536 - react: '>=19.0.0' 8537 - react-native: '>=0.81.0' 8538 - tailwindcss: '>=4' 8539 8973 8540 8974 unpipe@1.0.0: 8541 8975 resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} ··· 8705 9139 resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 8706 9140 engines: {node: '>= 0.8'} 8707 9141 9142 + vaul@1.1.2: 9143 + resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} 9144 + peerDependencies: 9145 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc 9146 + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc 9147 + 8708 9148 vite-node@3.2.4: 8709 9149 resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} 8710 9150 engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} ··· 8813 9253 8814 9254 web-vitals@5.1.0: 8815 9255 resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} 9256 + 9257 + webidl-conversions@3.0.1: 9258 + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} 8816 9259 8817 9260 webidl-conversions@5.0.0: 8818 9261 resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} ··· 8867 9310 resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} 8868 9311 engines: {node: '>=20'} 8869 9312 9313 + whatwg-url@5.0.0: 9314 + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} 9315 + 9316 + which-boxed-primitive@1.1.1: 9317 + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} 9318 + engines: {node: '>= 0.4'} 9319 + 9320 + which-builtin-type@1.2.1: 9321 + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} 9322 + engines: {node: '>= 0.4'} 9323 + 9324 + which-collection@1.0.2: 9325 + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} 9326 + engines: {node: '>= 0.4'} 9327 + 9328 + which-typed-array@1.1.20: 9329 + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} 9330 + engines: {node: '>= 0.4'} 9331 + 8870 9332 which@2.0.2: 8871 9333 resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 8872 9334 engines: {node: '>= 8'} ··· 10059 10521 '@babel/core': 7.28.6 10060 10522 '@babel/helper-plugin-utils': 7.28.6 10061 10523 10524 + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.6)': 10525 + dependencies: 10526 + '@babel/core': 7.28.6 10527 + '@babel/helper-plugin-utils': 7.28.6 10528 + 10062 10529 '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.28.6)': 10063 10530 dependencies: 10064 10531 '@babel/core': 7.28.6 ··· 10208 10675 '@csstools/css-tokenizer@3.0.4': {} 10209 10676 10210 10677 '@date-fns/tz@1.4.1': {} 10678 + 10679 + '@egjs/hammerjs@2.0.17': 10680 + dependencies: 10681 + '@types/hammerjs': 2.0.46 10211 10682 10212 10683 '@electric-sql/pglite-socket@0.0.20(@electric-sql/pglite@0.3.15)': 10213 10684 dependencies: ··· 10363 10834 optionalDependencies: 10364 10835 '@noble/hashes': 1.8.0 10365 10836 10366 - '@expo/cli@54.0.23(expo-router@4.0.22)(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))': 10837 + '@expo/cli@54.0.23(expo-router@6.0.23)(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))': 10367 10838 dependencies: 10368 10839 '@0no-co/graphql.web': 1.2.0 10369 10840 '@expo/code-signing-certificates': 0.0.6 ··· 10397 10868 connect: 3.7.0 10398 10869 debug: 4.4.3 10399 10870 env-editor: 0.4.2 10400 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 10871 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 10401 10872 expo-server: 1.0.5 10402 10873 freeport-async: 2.0.0 10403 10874 getenv: 2.0.0 ··· 10430 10901 wrap-ansi: 7.0.0 10431 10902 ws: 8.19.0 10432 10903 optionalDependencies: 10433 - expo-router: 4.0.22(expo-constants@18.0.13)(expo-linking@8.0.11)(expo@54.0.33)(react-dom@19.2.4(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 10904 + expo-router: 6.0.23(7b0271988d3f94ed3d3507a5fd980a46) 10434 10905 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 10435 10906 transitivePeerDependencies: 10436 10907 - bufferutil ··· 10563 11034 postcss: 8.4.49 10564 11035 resolve-from: 5.0.0 10565 11036 optionalDependencies: 10566 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 11037 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 10567 11038 transitivePeerDependencies: 10568 11039 - bufferutil 10569 11040 - supports-color ··· 10623 11094 '@expo/json-file': 10.0.8 10624 11095 '@react-native/normalize-colors': 0.81.5 10625 11096 debug: 4.4.3 10626 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 11097 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 10627 11098 resolve-from: 5.0.0 10628 11099 semver: 7.7.3 10629 11100 xml2js: 0.6.0 ··· 10633 11104 '@expo/schema-utils@0.1.8': {} 10634 11105 10635 11106 '@expo/sdk-runtime-versions@1.0.0': {} 10636 - 10637 - '@expo/server@0.5.3': 10638 - dependencies: 10639 - abort-controller: 3.0.0 10640 - debug: 4.4.3 10641 - source-map-support: 0.5.21 10642 - undici: 6.23.0 10643 - transitivePeerDependencies: 10644 - - supports-color 10645 11107 10646 11108 '@expo/spawn-async@1.7.2': 10647 11109 dependencies: ··· 11520 11982 11521 11983 '@noble/hashes@1.8.0': {} 11522 11984 11985 + '@nolyfill/is-core-module@1.0.39': {} 11986 + 11523 11987 '@nuxt/opencollective@0.4.1': 11524 11988 dependencies: 11525 11989 consola: 3.4.2 ··· 11868 12332 '@types/react': 19.2.10 11869 12333 '@types/react-dom': 19.2.3(@types/react@19.2.10) 11870 12334 12335 + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12336 + dependencies: 12337 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12338 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12339 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12340 + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.17)(react@19.1.0) 12341 + react: 19.1.0 12342 + react-dom: 19.1.0(react@19.1.0) 12343 + optionalDependencies: 12344 + '@types/react': 19.1.17 12345 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12346 + 11871 12347 '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 11872 12348 dependencies: 11873 12349 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) ··· 11880 12356 '@types/react': 19.2.10 11881 12357 '@types/react-dom': 19.2.3(@types/react@19.2.10) 11882 12358 11883 - '@radix-ui/react-compose-refs@1.0.0(react@19.1.0)': 12359 + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.17)(react@19.1.0)': 11884 12360 dependencies: 11885 - '@babel/runtime': 7.28.6 11886 12361 react: 19.1.0 12362 + optionalDependencies: 12363 + '@types/react': 19.1.17 11887 12364 11888 12365 '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.10)(react@19.2.4)': 11889 12366 dependencies: ··· 11905 12382 '@types/react': 19.2.10 11906 12383 '@types/react-dom': 19.2.3(@types/react@19.2.10) 11907 12384 12385 + '@radix-ui/react-context@1.1.2(@types/react@19.1.17)(react@19.1.0)': 12386 + dependencies: 12387 + react: 19.1.0 12388 + optionalDependencies: 12389 + '@types/react': 19.1.17 12390 + 11908 12391 '@radix-ui/react-context@1.1.2(@types/react@19.2.10)(react@19.2.4)': 11909 12392 dependencies: 11910 12393 react: 19.2.4 11911 12394 optionalDependencies: 11912 12395 '@types/react': 19.2.10 11913 12396 12397 + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12398 + dependencies: 12399 + '@radix-ui/primitive': 1.1.3 12400 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12401 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12402 + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12403 + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.17)(react@19.1.0) 12404 + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12405 + '@radix-ui/react-id': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12406 + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12407 + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12408 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12409 + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.17)(react@19.1.0) 12410 + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.17)(react@19.1.0) 12411 + aria-hidden: 1.2.6 12412 + react: 19.1.0 12413 + react-dom: 19.1.0(react@19.1.0) 12414 + react-remove-scroll: 2.7.2(@types/react@19.1.17)(react@19.1.0) 12415 + optionalDependencies: 12416 + '@types/react': 19.1.17 12417 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12418 + 11914 12419 '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 11915 12420 dependencies: 11916 12421 '@radix-ui/primitive': 1.1.3 ··· 11933 12438 '@types/react': 19.2.10 11934 12439 '@types/react-dom': 19.2.3(@types/react@19.2.10) 11935 12440 12441 + '@radix-ui/react-direction@1.1.1(@types/react@19.1.17)(react@19.1.0)': 12442 + dependencies: 12443 + react: 19.1.0 12444 + optionalDependencies: 12445 + '@types/react': 19.1.17 12446 + 11936 12447 '@radix-ui/react-direction@1.1.1(@types/react@19.2.10)(react@19.2.4)': 11937 12448 dependencies: 11938 12449 react: 19.2.4 11939 12450 optionalDependencies: 11940 12451 '@types/react': 19.2.10 11941 12452 12453 + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12454 + dependencies: 12455 + '@radix-ui/primitive': 1.1.3 12456 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12457 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12458 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12459 + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12460 + react: 19.1.0 12461 + react-dom: 19.1.0(react@19.1.0) 12462 + optionalDependencies: 12463 + '@types/react': 19.1.17 12464 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12465 + 11942 12466 '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 11943 12467 dependencies: 11944 12468 '@radix-ui/primitive': 1.1.3 ··· 11967 12491 '@types/react': 19.2.10 11968 12492 '@types/react-dom': 19.2.3(@types/react@19.2.10) 11969 12493 12494 + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.1.17)(react@19.1.0)': 12495 + dependencies: 12496 + react: 19.1.0 12497 + optionalDependencies: 12498 + '@types/react': 19.1.17 12499 + 11970 12500 '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.10)(react@19.2.4)': 11971 12501 dependencies: 11972 12502 react: 19.2.4 11973 12503 optionalDependencies: 11974 12504 '@types/react': 19.2.10 11975 12505 12506 + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12507 + dependencies: 12508 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12509 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12510 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12511 + react: 19.1.0 12512 + react-dom: 19.1.0(react@19.1.0) 12513 + optionalDependencies: 12514 + '@types/react': 19.1.17 12515 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12516 + 11976 12517 '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 11977 12518 dependencies: 11978 12519 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) ··· 12014 12555 optionalDependencies: 12015 12556 '@types/react': 19.2.10 12016 12557 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12558 + 12559 + '@radix-ui/react-id@1.1.1(@types/react@19.1.17)(react@19.1.0)': 12560 + dependencies: 12561 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12562 + react: 19.1.0 12563 + optionalDependencies: 12564 + '@types/react': 19.1.17 12017 12565 12018 12566 '@radix-ui/react-id@1.1.1(@types/react@19.2.10)(react@19.2.4)': 12019 12567 dependencies: ··· 12174 12722 '@types/react': 19.2.10 12175 12723 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12176 12724 12725 + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12726 + dependencies: 12727 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12728 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12729 + react: 19.1.0 12730 + react-dom: 19.1.0(react@19.1.0) 12731 + optionalDependencies: 12732 + '@types/react': 19.1.17 12733 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12734 + 12177 12735 '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 12178 12736 dependencies: 12179 12737 '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) ··· 12184 12742 '@types/react': 19.2.10 12185 12743 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12186 12744 12745 + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12746 + dependencies: 12747 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12748 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12749 + react: 19.1.0 12750 + react-dom: 19.1.0(react@19.1.0) 12751 + optionalDependencies: 12752 + '@types/react': 19.1.17 12753 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12754 + 12187 12755 '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 12188 12756 dependencies: 12189 12757 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) ··· 12194 12762 '@types/react': 19.2.10 12195 12763 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12196 12764 12765 + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12766 + dependencies: 12767 + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.17)(react@19.1.0) 12768 + react: 19.1.0 12769 + react-dom: 19.1.0(react@19.1.0) 12770 + optionalDependencies: 12771 + '@types/react': 19.1.17 12772 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12773 + 12197 12774 '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 12198 12775 dependencies: 12199 12776 '@radix-ui/react-slot': 1.2.3(@types/react@19.2.10)(react@19.2.4) ··· 12230 12807 optionalDependencies: 12231 12808 '@types/react': 19.2.10 12232 12809 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12810 + 12811 + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12812 + dependencies: 12813 + '@radix-ui/primitive': 1.1.3 12814 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12815 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12816 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12817 + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12818 + '@radix-ui/react-id': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12819 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12820 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12821 + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.17)(react@19.1.0) 12822 + react: 19.1.0 12823 + react-dom: 19.1.0(react@19.1.0) 12824 + optionalDependencies: 12825 + '@types/react': 19.1.17 12826 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12233 12827 12234 12828 '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 12235 12829 dependencies: ··· 12322 12916 '@types/react': 19.2.10 12323 12917 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12324 12918 12325 - '@radix-ui/react-slot@1.0.1(react@19.1.0)': 12919 + '@radix-ui/react-slot@1.2.0(@types/react@19.1.17)(react@19.1.0)': 12326 12920 dependencies: 12327 - '@babel/runtime': 7.28.6 12328 - '@radix-ui/react-compose-refs': 1.0.0(react@19.1.0) 12921 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12329 12922 react: 19.1.0 12923 + optionalDependencies: 12924 + '@types/react': 19.1.17 12925 + 12926 + '@radix-ui/react-slot@1.2.3(@types/react@19.1.17)(react@19.1.0)': 12927 + dependencies: 12928 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12929 + react: 19.1.0 12930 + optionalDependencies: 12931 + '@types/react': 19.1.17 12330 12932 12331 12933 '@radix-ui/react-slot@1.2.3(@types/react@19.2.10)(react@19.2.4)': 12332 12934 dependencies: ··· 12349 12951 optionalDependencies: 12350 12952 '@types/react': 19.2.10 12351 12953 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12954 + 12955 + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 12956 + dependencies: 12957 + '@radix-ui/primitive': 1.1.3 12958 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.17)(react@19.1.0) 12959 + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12960 + '@radix-ui/react-id': 1.1.1(@types/react@19.1.17)(react@19.1.0) 12961 + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12962 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12963 + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 12964 + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.17)(react@19.1.0) 12965 + react: 19.1.0 12966 + react-dom: 19.1.0(react@19.1.0) 12967 + optionalDependencies: 12968 + '@types/react': 19.1.17 12969 + '@types/react-dom': 19.2.3(@types/react@19.1.17) 12352 12970 12353 12971 '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': 12354 12972 dependencies: ··· 12447 13065 '@types/react': 19.2.10 12448 13066 '@types/react-dom': 19.2.3(@types/react@19.2.10) 12449 13067 13068 + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.17)(react@19.1.0)': 13069 + dependencies: 13070 + react: 19.1.0 13071 + optionalDependencies: 13072 + '@types/react': 19.1.17 13073 + 12450 13074 '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.10)(react@19.2.4)': 12451 13075 dependencies: 12452 13076 react: 19.2.4 12453 13077 optionalDependencies: 12454 13078 '@types/react': 19.2.10 12455 13079 13080 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.17)(react@19.1.0)': 13081 + dependencies: 13082 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.17)(react@19.1.0) 13083 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.0) 13084 + react: 19.1.0 13085 + optionalDependencies: 13086 + '@types/react': 19.1.17 13087 + 12456 13088 '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.10)(react@19.2.4)': 12457 13089 dependencies: 12458 13090 '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.10)(react@19.2.4) ··· 12461 13093 optionalDependencies: 12462 13094 '@types/react': 19.2.10 12463 13095 13096 + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.17)(react@19.1.0)': 13097 + dependencies: 13098 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.0) 13099 + react: 19.1.0 13100 + optionalDependencies: 13101 + '@types/react': 19.1.17 13102 + 12464 13103 '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.10)(react@19.2.4)': 12465 13104 dependencies: 12466 13105 '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.10)(react@19.2.4) ··· 12468 13107 optionalDependencies: 12469 13108 '@types/react': 19.2.10 12470 13109 13110 + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.17)(react@19.1.0)': 13111 + dependencies: 13112 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.0) 13113 + react: 19.1.0 13114 + optionalDependencies: 13115 + '@types/react': 19.1.17 13116 + 12471 13117 '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.10)(react@19.2.4)': 12472 13118 dependencies: 12473 13119 '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.10)(react@19.2.4) ··· 12482 13128 optionalDependencies: 12483 13129 '@types/react': 19.2.10 12484 13130 13131 + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.17)(react@19.1.0)': 13132 + dependencies: 13133 + react: 19.1.0 13134 + optionalDependencies: 13135 + '@types/react': 19.1.17 13136 + 12485 13137 '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.10)(react@19.2.4)': 12486 13138 dependencies: 12487 13139 react: 19.2.4 ··· 12626 13278 '@react-native/gradle-plugin@0.81.5': {} 12627 13279 12628 13280 '@react-native/js-polyfills@0.81.5': {} 13281 + 13282 + '@react-native/normalize-colors@0.74.89': {} 12629 13283 12630 13284 '@react-native/normalize-colors@0.81.5': {} 12631 13285 ··· 12779 13433 12780 13434 '@rollup/rollup-win32-x64-msvc@4.57.0': 12781 13435 optional: true 13436 + 13437 + '@rtsao/scc@1.1.0': {} 12782 13438 12783 13439 '@scarf/scarf@1.4.0': {} 12784 13440 ··· 12840 13496 valibot: 1.2.0(typescript@5.9.3) 12841 13497 zod: 4.3.6 12842 13498 12843 - '@tailwindcss/node@4.1.17': 12844 - dependencies: 12845 - '@jridgewell/remapping': 2.3.5 12846 - enhanced-resolve: 5.18.4 12847 - jiti: 2.6.1 12848 - lightningcss: 1.30.2 12849 - magic-string: 0.30.21 12850 - source-map-js: 1.2.1 12851 - tailwindcss: 4.1.17 12852 - 12853 13499 '@tailwindcss/node@4.1.18': 12854 13500 dependencies: 12855 13501 '@jridgewell/remapping': 2.3.5 ··· 12860 13506 source-map-js: 1.2.1 12861 13507 tailwindcss: 4.1.18 12862 13508 12863 - '@tailwindcss/oxide-android-arm64@4.1.17': 12864 - optional: true 12865 - 12866 13509 '@tailwindcss/oxide-android-arm64@4.1.18': 12867 13510 optional: true 12868 13511 12869 - '@tailwindcss/oxide-darwin-arm64@4.1.17': 12870 - optional: true 12871 - 12872 13512 '@tailwindcss/oxide-darwin-arm64@4.1.18': 12873 13513 optional: true 12874 13514 12875 - '@tailwindcss/oxide-darwin-x64@4.1.17': 12876 - optional: true 12877 - 12878 13515 '@tailwindcss/oxide-darwin-x64@4.1.18': 12879 13516 optional: true 12880 13517 12881 - '@tailwindcss/oxide-freebsd-x64@4.1.17': 12882 - optional: true 12883 - 12884 13518 '@tailwindcss/oxide-freebsd-x64@4.1.18': 12885 13519 optional: true 12886 13520 12887 - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': 12888 - optional: true 12889 - 12890 13521 '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': 12891 13522 optional: true 12892 13523 12893 - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': 12894 - optional: true 12895 - 12896 13524 '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': 12897 13525 optional: true 12898 13526 12899 - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': 12900 - optional: true 12901 - 12902 13527 '@tailwindcss/oxide-linux-arm64-musl@4.1.18': 12903 13528 optional: true 12904 13529 12905 - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': 12906 - optional: true 12907 - 12908 13530 '@tailwindcss/oxide-linux-x64-gnu@4.1.18': 12909 13531 optional: true 12910 13532 12911 - '@tailwindcss/oxide-linux-x64-musl@4.1.17': 12912 - optional: true 12913 - 12914 13533 '@tailwindcss/oxide-linux-x64-musl@4.1.18': 12915 13534 optional: true 12916 13535 12917 - '@tailwindcss/oxide-wasm32-wasi@4.1.17': 12918 - optional: true 12919 - 12920 13536 '@tailwindcss/oxide-wasm32-wasi@4.1.18': 12921 13537 optional: true 12922 13538 12923 - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': 12924 - optional: true 12925 - 12926 13539 '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': 12927 13540 optional: true 12928 13541 12929 - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': 12930 - optional: true 12931 - 12932 13542 '@tailwindcss/oxide-win32-x64-msvc@4.1.18': 12933 13543 optional: true 12934 13544 12935 - '@tailwindcss/oxide@4.1.17': 12936 - optionalDependencies: 12937 - '@tailwindcss/oxide-android-arm64': 4.1.17 12938 - '@tailwindcss/oxide-darwin-arm64': 4.1.17 12939 - '@tailwindcss/oxide-darwin-x64': 4.1.17 12940 - '@tailwindcss/oxide-freebsd-x64': 4.1.17 12941 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 12942 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 12943 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 12944 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 12945 - '@tailwindcss/oxide-linux-x64-musl': 4.1.17 12946 - '@tailwindcss/oxide-wasm32-wasi': 4.1.17 12947 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 12948 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 12949 - 12950 13545 '@tailwindcss/oxide@4.1.18': 12951 13546 optionalDependencies: 12952 13547 '@tailwindcss/oxide-android-arm64': 4.1.18 ··· 13054 13649 '@tanstack/query-devtools': 5.92.0 13055 13650 '@tanstack/react-query': 5.90.20(react@19.2.4) 13056 13651 react: 19.2.4 13057 - 13058 - '@tanstack/react-query@5.90.20(react@19.1.0)': 13059 - dependencies: 13060 - '@tanstack/query-core': 5.90.20 13061 - react: 19.1.0 13062 13652 13063 13653 '@tanstack/react-query@5.90.20(react@19.2.4)': 13064 13654 dependencies: ··· 13404 13994 dependencies: 13405 13995 '@types/node': 22.19.7 13406 13996 13997 + '@types/hammerjs@2.0.46': {} 13998 + 13407 13999 '@types/http-errors@2.0.5': {} 13408 14000 13409 14001 '@types/istanbul-lib-coverage@2.0.6': {} ··· 13423 14015 13424 14016 '@types/json-schema@7.0.15': {} 13425 14017 14018 + '@types/json5@0.0.29': {} 14019 + 13426 14020 '@types/methods@1.1.4': {} 13427 14021 13428 14022 '@types/node@16.9.1': {} ··· 13431 14025 dependencies: 13432 14026 undici-types: 6.21.0 13433 14027 13434 - '@types/node@25.2.2': 13435 - dependencies: 13436 - undici-types: 7.16.0 13437 - 13438 14028 '@types/qs@6.14.0': {} 13439 14029 13440 14030 '@types/range-parser@1.2.7': {} 14031 + 14032 + '@types/react-dom@19.2.3(@types/react@19.1.17)': 14033 + dependencies: 14034 + '@types/react': 19.1.17 14035 + optional: true 13441 14036 13442 14037 '@types/react-dom@19.2.3(@types/react@19.2.10)': 13443 14038 dependencies: ··· 13900 14495 dependencies: 13901 14496 dequal: 2.0.3 13902 14497 14498 + array-buffer-byte-length@1.0.2: 14499 + dependencies: 14500 + call-bound: 1.0.4 14501 + is-array-buffer: 3.0.5 14502 + 13903 14503 array-flatten@1.1.1: {} 13904 14504 14505 + array-includes@3.1.9: 14506 + dependencies: 14507 + call-bind: 1.0.8 14508 + call-bound: 1.0.4 14509 + define-properties: 1.2.1 14510 + es-abstract: 1.24.1 14511 + es-object-atoms: 1.1.1 14512 + get-intrinsic: 1.3.0 14513 + is-string: 1.1.1 14514 + math-intrinsics: 1.1.0 14515 + 13905 14516 array-timsort@1.0.3: {} 13906 14517 14518 + array.prototype.findlast@1.2.5: 14519 + dependencies: 14520 + call-bind: 1.0.8 14521 + define-properties: 1.2.1 14522 + es-abstract: 1.24.1 14523 + es-errors: 1.3.0 14524 + es-object-atoms: 1.1.1 14525 + es-shim-unscopables: 1.1.0 14526 + 14527 + array.prototype.findlastindex@1.2.6: 14528 + dependencies: 14529 + call-bind: 1.0.8 14530 + call-bound: 1.0.4 14531 + define-properties: 1.2.1 14532 + es-abstract: 1.24.1 14533 + es-errors: 1.3.0 14534 + es-object-atoms: 1.1.1 14535 + es-shim-unscopables: 1.1.0 14536 + 14537 + array.prototype.flat@1.3.3: 14538 + dependencies: 14539 + call-bind: 1.0.8 14540 + define-properties: 1.2.1 14541 + es-abstract: 1.24.1 14542 + es-shim-unscopables: 1.1.0 14543 + 14544 + array.prototype.flatmap@1.3.3: 14545 + dependencies: 14546 + call-bind: 1.0.8 14547 + define-properties: 1.2.1 14548 + es-abstract: 1.24.1 14549 + es-shim-unscopables: 1.1.0 14550 + 14551 + array.prototype.tosorted@1.1.4: 14552 + dependencies: 14553 + call-bind: 1.0.8 14554 + define-properties: 1.2.1 14555 + es-abstract: 1.24.1 14556 + es-errors: 1.3.0 14557 + es-shim-unscopables: 1.1.0 14558 + 14559 + arraybuffer.prototype.slice@1.0.4: 14560 + dependencies: 14561 + array-buffer-byte-length: 1.0.2 14562 + call-bind: 1.0.8 14563 + define-properties: 1.2.1 14564 + es-abstract: 1.24.1 14565 + es-errors: 1.3.0 14566 + get-intrinsic: 1.3.0 14567 + is-array-buffer: 3.0.5 14568 + 13907 14569 asap@2.0.6: {} 13908 14570 13909 14571 assertion-error@2.0.1: {} ··· 13911 14573 ast-types@0.16.1: 13912 14574 dependencies: 13913 14575 tslib: 2.8.1 14576 + 14577 + async-function@1.0.0: {} 13914 14578 13915 14579 async-limiter@1.0.1: {} 13916 14580 13917 14581 asynckit@0.4.0: {} 13918 14582 13919 14583 atomic-sleep@1.0.0: {} 14584 + 14585 + available-typed-arrays@1.0.7: 14586 + dependencies: 14587 + possible-typed-array-names: 1.1.0 13920 14588 13921 14589 await-lock@2.2.2: {} 13922 14590 ··· 14076 14744 resolve-from: 5.0.0 14077 14745 optionalDependencies: 14078 14746 '@babel/runtime': 7.28.6 14079 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 14747 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 14080 14748 transitivePeerDependencies: 14081 14749 - '@babel/core' 14082 14750 - supports-color ··· 14251 14919 dependencies: 14252 14920 es-errors: 1.3.0 14253 14921 function-bind: 1.1.2 14922 + 14923 + call-bind@1.0.8: 14924 + dependencies: 14925 + call-bind-apply-helpers: 1.0.2 14926 + es-define-property: 1.0.1 14927 + get-intrinsic: 1.3.0 14928 + set-function-length: 1.2.2 14254 14929 14255 14930 call-bound@1.0.4: 14256 14931 dependencies: ··· 14576 15251 14577 15252 create-require@1.1.1: {} 14578 15253 15254 + cross-fetch@3.2.0: 15255 + dependencies: 15256 + node-fetch: 2.7.0 15257 + transitivePeerDependencies: 15258 + - encoding 15259 + 14579 15260 cross-spawn@7.0.6: 14580 15261 dependencies: 14581 15262 path-key: 3.1.1 ··· 14588 15269 14589 15270 crypto-random-string@2.0.0: {} 14590 15271 15272 + css-in-js-utils@3.1.0: 15273 + dependencies: 15274 + hyphenate-style-name: 1.1.0 15275 + 14591 15276 css-select@5.2.2: 14592 15277 dependencies: 14593 15278 boolbase: 1.0.0 ··· 14612 15297 14613 15298 csstype@3.2.3: {} 14614 15299 14615 - culori@4.0.2: {} 14616 - 14617 15300 data-urls@6.0.1: 14618 15301 dependencies: 14619 15302 whatwg-mimetype: 5.0.0 14620 15303 whatwg-url: 15.1.0 14621 15304 15305 + data-view-buffer@1.0.2: 15306 + dependencies: 15307 + call-bound: 1.0.4 15308 + es-errors: 1.3.0 15309 + is-data-view: 1.0.2 15310 + 15311 + data-view-byte-length@1.0.2: 15312 + dependencies: 15313 + call-bound: 1.0.4 15314 + es-errors: 1.3.0 15315 + is-data-view: 1.0.2 15316 + 15317 + data-view-byte-offset@1.0.1: 15318 + dependencies: 15319 + call-bound: 1.0.4 15320 + es-errors: 1.3.0 15321 + is-data-view: 1.0.2 15322 + 14622 15323 date-fns-jalali@4.1.0-0: {} 14623 15324 14624 15325 date-fns@4.1.0: {} ··· 14672 15373 dependencies: 14673 15374 clone: 1.0.4 14674 15375 15376 + define-data-property@1.1.4: 15377 + dependencies: 15378 + es-define-property: 1.0.1 15379 + es-errors: 1.3.0 15380 + gopd: 1.2.0 15381 + 14675 15382 define-lazy-prop@2.0.0: {} 14676 15383 14677 15384 define-lazy-prop@3.0.0: {} 15385 + 15386 + define-properties@1.2.1: 15387 + dependencies: 15388 + define-data-property: 1.1.4 15389 + has-property-descriptors: 1.0.2 15390 + object-keys: 1.1.1 14678 15391 14679 15392 defu@6.1.4: {} 14680 15393 ··· 14704 15417 diff@4.0.4: {} 14705 15418 14706 15419 diff@8.0.3: {} 15420 + 15421 + doctrine@2.1.0: 15422 + dependencies: 15423 + esutils: 2.0.3 14707 15424 14708 15425 dom-accessibility-api@0.5.16: {} 14709 15426 ··· 14799 15516 dependencies: 14800 15517 stackframe: 1.3.4 14801 15518 15519 + es-abstract@1.24.1: 15520 + dependencies: 15521 + array-buffer-byte-length: 1.0.2 15522 + arraybuffer.prototype.slice: 1.0.4 15523 + available-typed-arrays: 1.0.7 15524 + call-bind: 1.0.8 15525 + call-bound: 1.0.4 15526 + data-view-buffer: 1.0.2 15527 + data-view-byte-length: 1.0.2 15528 + data-view-byte-offset: 1.0.1 15529 + es-define-property: 1.0.1 15530 + es-errors: 1.3.0 15531 + es-object-atoms: 1.1.1 15532 + es-set-tostringtag: 2.1.0 15533 + es-to-primitive: 1.3.0 15534 + function.prototype.name: 1.1.8 15535 + get-intrinsic: 1.3.0 15536 + get-proto: 1.0.1 15537 + get-symbol-description: 1.1.0 15538 + globalthis: 1.0.4 15539 + gopd: 1.2.0 15540 + has-property-descriptors: 1.0.2 15541 + has-proto: 1.2.0 15542 + has-symbols: 1.1.0 15543 + hasown: 2.0.2 15544 + internal-slot: 1.1.0 15545 + is-array-buffer: 3.0.5 15546 + is-callable: 1.2.7 15547 + is-data-view: 1.0.2 15548 + is-negative-zero: 2.0.3 15549 + is-regex: 1.2.1 15550 + is-set: 2.0.3 15551 + is-shared-array-buffer: 1.0.4 15552 + is-string: 1.1.1 15553 + is-typed-array: 1.1.15 15554 + is-weakref: 1.1.1 15555 + math-intrinsics: 1.1.0 15556 + object-inspect: 1.13.4 15557 + object-keys: 1.1.1 15558 + object.assign: 4.1.7 15559 + own-keys: 1.0.1 15560 + regexp.prototype.flags: 1.5.4 15561 + safe-array-concat: 1.1.3 15562 + safe-push-apply: 1.0.0 15563 + safe-regex-test: 1.1.0 15564 + set-proto: 1.0.0 15565 + stop-iteration-iterator: 1.1.0 15566 + string.prototype.trim: 1.2.10 15567 + string.prototype.trimend: 1.0.9 15568 + string.prototype.trimstart: 1.0.8 15569 + typed-array-buffer: 1.0.3 15570 + typed-array-byte-length: 1.0.3 15571 + typed-array-byte-offset: 1.0.4 15572 + typed-array-length: 1.0.7 15573 + unbox-primitive: 1.1.0 15574 + which-typed-array: 1.1.20 15575 + 14802 15576 es-define-property@1.0.1: {} 14803 15577 14804 15578 es-errors@1.3.0: {} 14805 15579 15580 + es-iterator-helpers@1.2.2: 15581 + dependencies: 15582 + call-bind: 1.0.8 15583 + call-bound: 1.0.4 15584 + define-properties: 1.2.1 15585 + es-abstract: 1.24.1 15586 + es-errors: 1.3.0 15587 + es-set-tostringtag: 2.1.0 15588 + function-bind: 1.1.2 15589 + get-intrinsic: 1.3.0 15590 + globalthis: 1.0.4 15591 + gopd: 1.2.0 15592 + has-property-descriptors: 1.0.2 15593 + has-proto: 1.2.0 15594 + has-symbols: 1.1.0 15595 + internal-slot: 1.1.0 15596 + iterator.prototype: 1.1.5 15597 + safe-array-concat: 1.1.3 15598 + 14806 15599 es-module-lexer@1.7.0: {} 14807 15600 14808 15601 es-module-lexer@2.0.0: {} ··· 14817 15610 get-intrinsic: 1.3.0 14818 15611 has-tostringtag: 1.0.2 14819 15612 hasown: 2.0.2 15613 + 15614 + es-shim-unscopables@1.1.0: 15615 + dependencies: 15616 + hasown: 2.0.2 15617 + 15618 + es-to-primitive@1.3.0: 15619 + dependencies: 15620 + is-callable: 1.2.7 15621 + is-date-object: 1.1.0 15622 + is-symbol: 1.1.1 14820 15623 14821 15624 esbuild@0.27.2: 14822 15625 optionalDependencies: ··· 14857 15660 14858 15661 escape-string-regexp@4.0.0: {} 14859 15662 15663 + eslint-config-expo@10.0.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): 15664 + dependencies: 15665 + '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 15666 + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 15667 + eslint: 9.39.2(jiti@2.6.1) 15668 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) 15669 + eslint-plugin-expo: 1.0.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 15670 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) 15671 + eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1)) 15672 + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.2(jiti@2.6.1)) 15673 + globals: 16.5.0 15674 + transitivePeerDependencies: 15675 + - eslint-import-resolver-webpack 15676 + - eslint-plugin-import-x 15677 + - supports-color 15678 + - typescript 15679 + 14860 15680 eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)): 14861 15681 dependencies: 14862 15682 eslint: 9.39.2(jiti@2.6.1) 14863 15683 15684 + eslint-import-resolver-node@0.3.9: 15685 + dependencies: 15686 + debug: 3.2.7 15687 + is-core-module: 2.16.1 15688 + resolve: 1.22.11 15689 + transitivePeerDependencies: 15690 + - supports-color 15691 + 15692 + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)): 15693 + dependencies: 15694 + '@nolyfill/is-core-module': 1.0.39 15695 + debug: 4.4.3 15696 + eslint: 9.39.2(jiti@2.6.1) 15697 + get-tsconfig: 4.13.0 15698 + is-bun-module: 2.0.0 15699 + stable-hash: 0.0.5 15700 + tinyglobby: 0.2.15 15701 + unrs-resolver: 1.11.1 15702 + optionalDependencies: 15703 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) 15704 + transitivePeerDependencies: 15705 + - supports-color 15706 + 15707 + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): 15708 + dependencies: 15709 + debug: 3.2.7 15710 + optionalDependencies: 15711 + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 15712 + eslint: 9.39.2(jiti@2.6.1) 15713 + eslint-import-resolver-node: 0.3.9 15714 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) 15715 + transitivePeerDependencies: 15716 + - supports-color 15717 + 15718 + eslint-plugin-expo@1.0.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): 15719 + dependencies: 15720 + '@typescript-eslint/types': 8.54.0 15721 + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 15722 + eslint: 9.39.2(jiti@2.6.1) 15723 + transitivePeerDependencies: 15724 + - supports-color 15725 + - typescript 15726 + 15727 + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)): 15728 + dependencies: 15729 + '@rtsao/scc': 1.1.0 15730 + array-includes: 3.1.9 15731 + array.prototype.findlastindex: 1.2.6 15732 + array.prototype.flat: 1.3.3 15733 + array.prototype.flatmap: 1.3.3 15734 + debug: 3.2.7 15735 + doctrine: 2.1.0 15736 + eslint: 9.39.2(jiti@2.6.1) 15737 + eslint-import-resolver-node: 0.3.9 15738 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)) 15739 + hasown: 2.0.2 15740 + is-core-module: 2.16.1 15741 + is-glob: 4.0.3 15742 + minimatch: 3.1.2 15743 + object.fromentries: 2.0.8 15744 + object.groupby: 1.0.3 15745 + object.values: 1.2.1 15746 + semver: 6.3.1 15747 + string.prototype.trimend: 1.0.9 15748 + tsconfig-paths: 3.15.0 15749 + optionalDependencies: 15750 + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) 15751 + transitivePeerDependencies: 15752 + - eslint-import-resolver-typescript 15753 + - eslint-import-resolver-webpack 15754 + - supports-color 15755 + 14864 15756 eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.1): 14865 15757 dependencies: 14866 15758 eslint: 9.39.2(jiti@2.6.1) ··· 14870 15762 optionalDependencies: 14871 15763 '@types/eslint': 9.6.1 14872 15764 eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) 15765 + 15766 + eslint-plugin-react-hooks@5.2.0(eslint@9.39.2(jiti@2.6.1)): 15767 + dependencies: 15768 + eslint: 9.39.2(jiti@2.6.1) 15769 + 15770 + eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)): 15771 + dependencies: 15772 + array-includes: 3.1.9 15773 + array.prototype.findlast: 1.2.5 15774 + array.prototype.flatmap: 1.3.3 15775 + array.prototype.tosorted: 1.1.4 15776 + doctrine: 2.1.0 15777 + es-iterator-helpers: 1.2.2 15778 + eslint: 9.39.2(jiti@2.6.1) 15779 + estraverse: 5.3.0 15780 + hasown: 2.0.2 15781 + jsx-ast-utils: 3.3.5 15782 + minimatch: 3.1.2 15783 + object.entries: 1.1.9 15784 + object.fromentries: 2.0.8 15785 + object.values: 1.2.1 15786 + prop-types: 15.8.1 15787 + resolve: 2.0.0-next.5 15788 + semver: 6.3.1 15789 + string.prototype.matchall: 4.0.12 15790 + string.prototype.repeat: 1.0.0 14873 15791 14874 15792 eslint-scope@5.1.1: 14875 15793 dependencies: ··· 14995 15913 expo-asset@12.0.12(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 14996 15914 dependencies: 14997 15915 '@expo/image-utils': 0.8.8 14998 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15916 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 14999 15917 expo-constants: 18.0.13(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 15000 15918 react: 19.1.0 15001 15919 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) ··· 15006 15924 dependencies: 15007 15925 '@expo/config': 12.0.13 15008 15926 '@expo/env': 2.0.8 15009 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15927 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15010 15928 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15011 15929 transitivePeerDependencies: 15012 15930 - supports-color 15013 15931 15014 - expo-dev-client@6.0.20(expo@54.0.33): 15015 - dependencies: 15016 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15017 - expo-dev-launcher: 6.0.20(expo@54.0.33) 15018 - expo-dev-menu: 7.0.18(expo@54.0.33) 15019 - expo-dev-menu-interface: 2.0.0(expo@54.0.33) 15020 - expo-manifests: 1.0.10(expo@54.0.33) 15021 - expo-updates-interface: 2.0.0(expo@54.0.33) 15022 - transitivePeerDependencies: 15023 - - supports-color 15024 - 15025 - expo-dev-launcher@6.0.20(expo@54.0.33): 15026 - dependencies: 15027 - ajv: 8.17.1 15028 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15029 - expo-dev-menu: 7.0.18(expo@54.0.33) 15030 - expo-manifests: 1.0.10(expo@54.0.33) 15031 - transitivePeerDependencies: 15032 - - supports-color 15033 - 15034 - expo-dev-menu-interface@2.0.0(expo@54.0.33): 15035 - dependencies: 15036 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15037 - 15038 - expo-dev-menu@7.0.18(expo@54.0.33): 15039 - dependencies: 15040 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15041 - expo-dev-menu-interface: 2.0.0(expo@54.0.33) 15042 - 15043 15932 expo-file-system@19.0.21(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)): 15044 15933 dependencies: 15045 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15934 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15046 15935 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15047 15936 15048 15937 expo-font@14.0.11(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 15049 15938 dependencies: 15050 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15939 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15051 15940 fontfaceobserver: 2.3.0 15052 15941 react: 19.1.0 15053 15942 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15054 15943 15055 - expo-json-utils@0.15.0: {} 15944 + expo-haptics@15.0.8(expo@54.0.33): 15945 + dependencies: 15946 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15947 + 15948 + expo-image@3.0.11(expo@54.0.33)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 15949 + dependencies: 15950 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15951 + react: 19.1.0 15952 + react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15953 + optionalDependencies: 15954 + react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 15056 15955 15057 15956 expo-keep-awake@15.0.8(expo@54.0.33)(react@19.1.0): 15058 15957 dependencies: 15059 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15958 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15060 15959 react: 19.1.0 15061 15960 15062 15961 expo-linking@8.0.11(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): ··· 15069 15968 - expo 15070 15969 - supports-color 15071 15970 15072 - expo-manifests@1.0.10(expo@54.0.33): 15073 - dependencies: 15074 - '@expo/config': 12.0.13 15075 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15076 - expo-json-utils: 0.15.0 15077 - transitivePeerDependencies: 15078 - - supports-color 15079 - 15080 15971 expo-modules-autolinking@3.0.24: 15081 15972 dependencies: 15082 15973 '@expo/spawn-async': 1.7.2 ··· 15091 15982 react: 19.1.0 15092 15983 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15093 15984 15094 - expo-router@4.0.22(expo-constants@18.0.13)(expo-linking@8.0.11)(expo@54.0.33)(react-dom@19.2.4(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 15985 + expo-router@6.0.23(7b0271988d3f94ed3d3507a5fd980a46): 15095 15986 dependencies: 15096 15987 '@expo/metro-runtime': 4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 15097 - '@expo/server': 0.5.3 15098 - '@radix-ui/react-slot': 1.0.1(react@19.1.0) 15988 + '@expo/schema-utils': 0.1.8 15989 + '@radix-ui/react-slot': 1.2.0(@types/react@19.1.17)(react@19.1.0) 15990 + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 15099 15991 '@react-navigation/bottom-tabs': 7.12.0(@react-navigation/native@7.1.28(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15100 15992 '@react-navigation/native': 7.1.28(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15101 15993 '@react-navigation/native-stack': 7.11.0(@react-navigation/native@7.1.28(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15102 15994 client-only: 0.0.1 15103 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15995 + debug: 4.4.3 15996 + escape-string-regexp: 4.0.0 15997 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15104 15998 expo-constants: 18.0.13(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 15105 15999 expo-linking: 8.0.11(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15106 - react-helmet-async: 1.3.0(react-dom@19.2.4(react@19.1.0))(react@19.1.0) 15107 - react-native-helmet-async: 2.0.4(react@19.1.0) 16000 + expo-server: 1.0.5 16001 + fast-deep-equal: 3.1.3 16002 + invariant: 2.2.4 16003 + nanoid: 3.3.11 16004 + query-string: 7.1.3 16005 + react: 19.1.0 16006 + react-fast-compare: 3.2.2 16007 + react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15108 16008 react-native-is-edge-to-edge: 1.2.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15109 16009 react-native-safe-area-context: 5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15110 16010 react-native-screens: 4.16.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15111 - schema-utils: 4.3.3 15112 16011 semver: 7.6.3 15113 16012 server-only: 0.0.1 16013 + sf-symbols-typescript: 2.2.0 16014 + shallowequal: 1.1.0 16015 + use-latest-callback: 0.2.6(react@19.1.0) 16016 + vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 16017 + optionalDependencies: 16018 + react-dom: 19.1.0(react@19.1.0) 16019 + react-native-gesture-handler: 2.28.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 16020 + react-native-reanimated: 4.1.6(@babel/core@7.28.6)(react-native-worklets@0.5.1(@babel/core@7.28.6)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 16021 + react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 15114 16022 transitivePeerDependencies: 15115 16023 - '@react-native-masked-view/masked-view' 15116 - - react 15117 - - react-dom 15118 - - react-native 16024 + - '@types/react' 16025 + - '@types/react-dom' 15119 16026 - supports-color 15120 16027 15121 - expo-secure-store@15.0.8(expo@54.0.33): 15122 - dependencies: 15123 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15124 - 15125 16028 expo-server@1.0.5: {} 15126 16029 16030 + expo-splash-screen@31.0.13(expo@54.0.33): 16031 + dependencies: 16032 + '@expo/prebuild-config': 54.0.8(expo@54.0.33) 16033 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 16034 + transitivePeerDependencies: 16035 + - supports-color 16036 + 15127 16037 expo-status-bar@3.0.9(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 15128 16038 dependencies: 15129 16039 react: 19.1.0 15130 16040 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15131 16041 react-native-is-edge-to-edge: 1.2.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15132 16042 15133 - expo-updates-interface@2.0.0(expo@54.0.33): 16043 + expo-symbols@1.0.8(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)): 15134 16044 dependencies: 15135 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 16045 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 16046 + react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 16047 + sf-symbols-typescript: 2.2.0 16048 + 16049 + expo-system-ui@6.0.9(expo@54.0.33)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)): 16050 + dependencies: 16051 + '@react-native/normalize-colors': 0.81.5 16052 + debug: 4.4.3 16053 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 16054 + react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 16055 + optionalDependencies: 16056 + react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 16057 + transitivePeerDependencies: 16058 + - supports-color 15136 16059 15137 16060 expo-web-browser@15.0.10(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)): 15138 16061 dependencies: 15139 - expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 16062 + expo: 54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 15140 16063 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 15141 16064 15142 - expo@54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@4.0.22)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 16065 + expo@54.0.33(@babel/core@7.28.6)(@expo/metro-runtime@4.0.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)))(expo-router@6.0.23)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 15143 16066 dependencies: 15144 16067 '@babel/runtime': 7.28.6 15145 - '@expo/cli': 54.0.23(expo-router@4.0.22)(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 16068 + '@expo/cli': 54.0.23(expo-router@6.0.23)(expo@54.0.33)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0)) 15146 16069 '@expo/config': 12.0.13 15147 16070 '@expo/config-plugins': 54.0.4 15148 16071 '@expo/devtools': 0.1.8(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) ··· 15269 16192 dependencies: 15270 16193 bser: 2.1.1 15271 16194 16195 + fbjs-css-vars@1.0.2: {} 16196 + 16197 + fbjs@3.0.5: 16198 + dependencies: 16199 + cross-fetch: 3.2.0 16200 + fbjs-css-vars: 1.0.2 16201 + loose-envify: 1.4.0 16202 + object-assign: 4.1.1 16203 + promise: 7.3.1 16204 + setimmediate: 1.0.5 16205 + ua-parser-js: 1.0.41 16206 + transitivePeerDependencies: 16207 + - encoding 16208 + 15272 16209 fdir@6.5.0(picomatch@4.0.3): 15273 16210 optionalDependencies: 15274 16211 picomatch: 4.0.3 ··· 15354 16291 15355 16292 fontfaceobserver@2.3.0: {} 15356 16293 16294 + for-each@0.3.5: 16295 + dependencies: 16296 + is-callable: 1.2.7 16297 + 15357 16298 foreground-child@3.3.1: 15358 16299 dependencies: 15359 16300 cross-spawn: 7.0.6 ··· 15416 16357 15417 16358 function-bind@1.1.2: {} 15418 16359 16360 + function.prototype.name@1.1.8: 16361 + dependencies: 16362 + call-bind: 1.0.8 16363 + call-bound: 1.0.4 16364 + define-properties: 1.2.1 16365 + functions-have-names: 1.2.3 16366 + hasown: 2.0.2 16367 + is-callable: 1.2.7 16368 + 16369 + functions-have-names@1.2.3: {} 16370 + 15419 16371 generate-function@2.3.1: 15420 16372 dependencies: 15421 16373 is-property: 1.0.2 16374 + 16375 + generator-function@2.0.1: {} 15422 16376 15423 16377 gensync@1.0.0-beta.2: {} 15424 16378 ··· 15449 16403 es-object-atoms: 1.1.1 15450 16404 15451 16405 get-stream@6.0.1: {} 16406 + 16407 + get-symbol-description@1.1.0: 16408 + dependencies: 16409 + call-bound: 1.0.4 16410 + es-errors: 1.3.0 16411 + get-intrinsic: 1.3.0 15452 16412 15453 16413 get-tsconfig@4.13.0: 15454 16414 dependencies: ··· 15515 16475 15516 16476 globals@16.5.0: {} 15517 16477 16478 + globalthis@1.0.4: 16479 + dependencies: 16480 + define-properties: 1.2.1 16481 + gopd: 1.2.0 16482 + 15518 16483 globrex@0.1.2: {} 15519 16484 15520 16485 goober@2.1.18(csstype@3.2.3): ··· 15545 16510 optionalDependencies: 15546 16511 uglify-js: 3.19.3 15547 16512 16513 + has-bigints@1.1.0: {} 16514 + 15548 16515 has-flag@3.0.0: {} 15549 16516 15550 16517 has-flag@4.0.0: {} 15551 16518 16519 + has-property-descriptors@1.0.2: 16520 + dependencies: 16521 + es-define-property: 1.0.1 16522 + 16523 + has-proto@1.2.0: 16524 + dependencies: 16525 + dunder-proto: 1.0.1 16526 + 15552 16527 has-symbols@1.1.0: {} 15553 16528 15554 16529 has-tostringtag@1.0.2: ··· 15570 16545 hermes-parser@0.32.0: 15571 16546 dependencies: 15572 16547 hermes-estree: 0.32.0 16548 + 16549 + hoist-non-react-statics@3.3.2: 16550 + dependencies: 16551 + react-is: 16.13.1 15573 16552 15574 16553 hono@4.11.4: {} 15575 16554 ··· 15618 16597 15619 16598 human-signals@2.1.0: {} 15620 16599 16600 + hyphenate-style-name@1.1.0: {} 16601 + 15621 16602 iconv-lite@0.4.24: 15622 16603 dependencies: 15623 16604 safer-buffer: 2.1.2 ··· 15665 16646 15666 16647 ini@1.3.8: {} 15667 16648 16649 + inline-style-prefixer@7.0.1: 16650 + dependencies: 16651 + css-in-js-utils: 3.1.0 16652 + 16653 + internal-slot@1.1.0: 16654 + dependencies: 16655 + es-errors: 1.3.0 16656 + hasown: 2.0.2 16657 + side-channel: 1.1.0 16658 + 15668 16659 invariant@2.2.4: 15669 16660 dependencies: 15670 16661 loose-envify: 1.4.0 ··· 15672 16663 ipaddr.js@1.9.1: {} 15673 16664 15674 16665 ipaddr.js@2.3.0: {} 16666 + 16667 + is-array-buffer@3.0.5: 16668 + dependencies: 16669 + call-bind: 1.0.8 16670 + call-bound: 1.0.4 16671 + get-intrinsic: 1.3.0 15675 16672 15676 16673 is-arrayish@0.2.1: {} 15677 16674 15678 16675 is-arrayish@0.3.4: {} 15679 16676 16677 + is-async-function@2.1.1: 16678 + dependencies: 16679 + async-function: 1.0.0 16680 + call-bound: 1.0.4 16681 + get-proto: 1.0.1 16682 + has-tostringtag: 1.0.2 16683 + safe-regex-test: 1.1.0 16684 + 16685 + is-bigint@1.1.0: 16686 + dependencies: 16687 + has-bigints: 1.1.0 16688 + 15680 16689 is-binary-path@2.1.0: 15681 16690 dependencies: 15682 16691 binary-extensions: 2.3.0 15683 16692 16693 + is-boolean-object@1.2.2: 16694 + dependencies: 16695 + call-bound: 1.0.4 16696 + has-tostringtag: 1.0.2 16697 + 16698 + is-bun-module@2.0.0: 16699 + dependencies: 16700 + semver: 7.7.3 16701 + 16702 + is-callable@1.2.7: {} 16703 + 15684 16704 is-core-module@2.16.1: 15685 16705 dependencies: 15686 16706 hasown: 2.0.2 15687 16707 16708 + is-data-view@1.0.2: 16709 + dependencies: 16710 + call-bound: 1.0.4 16711 + get-intrinsic: 1.3.0 16712 + is-typed-array: 1.1.15 16713 + 16714 + is-date-object@1.1.0: 16715 + dependencies: 16716 + call-bound: 1.0.4 16717 + has-tostringtag: 1.0.2 16718 + 15688 16719 is-docker@2.2.1: {} 15689 16720 15690 16721 is-docker@3.0.0: {} 15691 16722 15692 16723 is-extglob@2.1.1: {} 15693 16724 16725 + is-finalizationregistry@1.1.1: 16726 + dependencies: 16727 + call-bound: 1.0.4 16728 + 15694 16729 is-fullwidth-code-point@3.0.0: {} 15695 16730 15696 16731 is-generator-fn@2.1.0: {} 15697 16732 16733 + is-generator-function@1.1.2: 16734 + dependencies: 16735 + call-bound: 1.0.4 16736 + generator-function: 2.0.1 16737 + get-proto: 1.0.1 16738 + has-tostringtag: 1.0.2 16739 + safe-regex-test: 1.1.0 16740 + 15698 16741 is-glob@4.0.3: 15699 16742 dependencies: 15700 16743 is-extglob: 2.1.1 ··· 15707 16750 15708 16751 is-interactive@1.0.0: {} 15709 16752 16753 + is-map@2.0.3: {} 16754 + 16755 + is-negative-zero@2.0.3: {} 16756 + 16757 + is-number-object@1.1.1: 16758 + dependencies: 16759 + call-bound: 1.0.4 16760 + has-tostringtag: 1.0.2 16761 + 15710 16762 is-number@7.0.0: {} 15711 16763 15712 16764 is-potential-custom-element-name@1.0.1: {} ··· 15715 16767 15716 16768 is-property@1.0.2: {} 15717 16769 16770 + is-regex@1.2.1: 16771 + dependencies: 16772 + call-bound: 1.0.4 16773 + gopd: 1.2.0 16774 + has-tostringtag: 1.0.2 16775 + hasown: 2.0.2 16776 + 16777 + is-set@2.0.3: {} 16778 + 16779 + is-shared-array-buffer@1.0.4: 16780 + dependencies: 16781 + call-bound: 1.0.4 16782 + 15718 16783 is-stream@2.0.1: {} 15719 16784 16785 + is-string@1.1.1: 16786 + dependencies: 16787 + call-bound: 1.0.4 16788 + has-tostringtag: 1.0.2 16789 + 16790 + is-symbol@1.1.1: 16791 + dependencies: 16792 + call-bound: 1.0.4 16793 + has-symbols: 1.1.0 16794 + safe-regex-test: 1.1.0 16795 + 16796 + is-typed-array@1.1.15: 16797 + dependencies: 16798 + which-typed-array: 1.1.20 16799 + 15720 16800 is-unicode-supported@0.1.0: {} 15721 16801 16802 + is-weakmap@2.0.2: {} 16803 + 16804 + is-weakref@1.1.1: 16805 + dependencies: 16806 + call-bound: 1.0.4 16807 + 16808 + is-weakset@2.0.4: 16809 + dependencies: 16810 + call-bound: 1.0.4 16811 + get-intrinsic: 1.3.0 16812 + 15722 16813 is-wsl@2.2.0: 15723 16814 dependencies: 15724 16815 is-docker: 2.2.1 ··· 15726 16817 is-wsl@3.1.0: 15727 16818 dependencies: 15728 16819 is-inside-container: 1.0.0 16820 + 16821 + isarray@2.0.5: {} 15729 16822 15730 16823 isbot@5.1.34: {} 15731 16824 ··· 15775 16868 istanbul-lib-report: 3.0.1 15776 16869 15777 16870 iterare@1.2.1: {} 16871 + 16872 + iterator.prototype@1.1.5: 16873 + dependencies: 16874 + define-data-property: 1.1.4 16875 + es-object-atoms: 1.1.1 16876 + get-intrinsic: 1.3.0 16877 + get-proto: 1.0.1 16878 + has-symbols: 1.1.0 16879 + set-function-name: 2.0.2 15778 16880 15779 16881 jackspeak@3.4.3: 15780 16882 dependencies: ··· 16267 17369 16268 17370 json-stable-stringify-without-jsonify@1.0.1: {} 16269 17371 17372 + json5@1.0.2: 17373 + dependencies: 17374 + minimist: 1.2.8 17375 + 16270 17376 json5@2.2.3: {} 16271 17377 16272 17378 jsonc-parser@3.3.1: {} ··· 16276 17382 universalify: 2.0.1 16277 17383 optionalDependencies: 16278 17384 graceful-fs: 4.2.11 17385 + 17386 + jsx-ast-utils@3.3.5: 17387 + dependencies: 17388 + array-includes: 3.1.9 17389 + array.prototype.flat: 1.3.3 17390 + object.assign: 4.1.7 17391 + object.values: 1.2.1 16279 17392 16280 17393 keyv@4.5.4: 16281 17394 dependencies: ··· 16496 17609 fs-monkey: 1.1.0 16497 17610 16498 17611 memoize-one@5.2.1: {} 17612 + 17613 + memoize-one@6.0.0: {} 16499 17614 16500 17615 merge-descriptors@1.0.3: {} 16501 17616 ··· 16864 17979 16865 17980 node-fetch-native@1.6.7: {} 16866 17981 17982 + node-fetch@2.7.0: 17983 + dependencies: 17984 + whatwg-url: 5.0.0 17985 + 16867 17986 node-forge@1.3.3: {} 16868 17987 16869 17988 node-int64@0.4.0: {} ··· 16903 18022 16904 18023 object-inspect@1.13.4: {} 16905 18024 18025 + object-keys@1.1.1: {} 18026 + 18027 + object.assign@4.1.7: 18028 + dependencies: 18029 + call-bind: 1.0.8 18030 + call-bound: 1.0.4 18031 + define-properties: 1.2.1 18032 + es-object-atoms: 1.1.1 18033 + has-symbols: 1.1.0 18034 + object-keys: 1.1.1 18035 + 18036 + object.entries@1.1.9: 18037 + dependencies: 18038 + call-bind: 1.0.8 18039 + call-bound: 1.0.4 18040 + define-properties: 1.2.1 18041 + es-object-atoms: 1.1.1 18042 + 18043 + object.fromentries@2.0.8: 18044 + dependencies: 18045 + call-bind: 1.0.8 18046 + define-properties: 1.2.1 18047 + es-abstract: 1.24.1 18048 + es-object-atoms: 1.1.1 18049 + 18050 + object.groupby@1.0.3: 18051 + dependencies: 18052 + call-bind: 1.0.8 18053 + define-properties: 1.2.1 18054 + es-abstract: 1.24.1 18055 + 18056 + object.values@1.2.1: 18057 + dependencies: 18058 + call-bind: 1.0.8 18059 + call-bound: 1.0.4 18060 + define-properties: 1.2.1 18061 + es-object-atoms: 1.1.1 18062 + 16906 18063 ofetch@2.0.0-alpha.3: {} 16907 18064 16908 18065 ohash@2.0.11: {} ··· 16982 18139 log-symbols: 4.1.0 16983 18140 strip-ansi: 6.0.1 16984 18141 wcwidth: 1.0.1 18142 + 18143 + own-keys@1.0.1: 18144 + dependencies: 18145 + get-intrinsic: 1.3.0 18146 + object-keys: 1.1.1 18147 + safe-push-apply: 1.0.0 16985 18148 16986 18149 oxc-minify@0.111.0: 16987 18150 optionalDependencies: ··· 17237 18400 17238 18401 pngjs@7.0.0: {} 17239 18402 18403 + possible-typed-array-names@1.1.0: {} 18404 + 18405 + postcss-value-parser@4.2.0: {} 18406 + 17240 18407 postcss@8.4.49: 17241 18408 dependencies: 17242 18409 nanoid: 3.3.11 ··· 17332 18499 process@0.11.10: {} 17333 18500 17334 18501 progress@2.0.3: {} 18502 + 18503 + promise@7.3.1: 18504 + dependencies: 18505 + asap: 2.0.6 17335 18506 17336 18507 promise@8.3.0: 17337 18508 dependencies: ··· 17502 18673 - bufferutil 17503 18674 - utf-8-validate 17504 18675 17505 - react-dom@19.2.4(react@19.1.0): 18676 + react-dom@19.1.0(react@19.1.0): 17506 18677 dependencies: 17507 18678 react: 19.1.0 17508 - scheduler: 0.27.0 18679 + scheduler: 0.26.0 17509 18680 17510 18681 react-dom@19.2.4(react@19.2.4): 17511 18682 dependencies: ··· 17518 18689 dependencies: 17519 18690 react: 19.1.0 17520 18691 17521 - react-helmet-async@1.3.0(react-dom@19.2.4(react@19.1.0))(react@19.1.0): 17522 - dependencies: 17523 - '@babel/runtime': 7.28.6 17524 - invariant: 2.2.4 17525 - prop-types: 15.8.1 17526 - react: 19.1.0 17527 - react-dom: 19.2.4(react@19.1.0) 17528 - react-fast-compare: 3.2.2 17529 - shallowequal: 1.1.0 17530 - 17531 18692 react-is@16.13.1: {} 17532 18693 17533 18694 react-is@17.0.2: {} ··· 17536 18697 17537 18698 react-is@19.2.4: {} 17538 18699 17539 - react-native-helmet-async@2.0.4(react@19.1.0): 18700 + react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 17540 18701 dependencies: 18702 + '@egjs/hammerjs': 2.0.17 18703 + hoist-non-react-statics: 3.3.2 17541 18704 invariant: 2.2.4 17542 18705 react: 19.1.0 17543 - react-fast-compare: 3.2.2 17544 - shallowequal: 1.1.0 18706 + react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 17545 18707 17546 18708 react-native-is-edge-to-edge@1.2.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 17547 18709 dependencies: 17548 18710 react: 19.1.0 17549 18711 react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 17550 18712 18713 + react-native-reanimated@4.1.6(@babel/core@7.28.6)(react-native-worklets@0.5.1(@babel/core@7.28.6)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 18714 + dependencies: 18715 + '@babel/core': 7.28.6 18716 + react: 19.1.0 18717 + react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 18718 + react-native-is-edge-to-edge: 1.2.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 18719 + react-native-worklets: 0.5.1(@babel/core@7.28.6)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 18720 + semver: 7.7.2 18721 + 17551 18722 react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 17552 18723 dependencies: 17553 18724 react: 19.1.0 ··· 17561 18732 react-native-is-edge-to-edge: 1.2.1(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 17562 18733 warn-once: 0.1.1 17563 18734 18735 + react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0): 18736 + dependencies: 18737 + '@babel/runtime': 7.28.6 18738 + '@react-native/normalize-colors': 0.74.89 18739 + fbjs: 3.0.5 18740 + inline-style-prefixer: 7.0.1 18741 + memoize-one: 6.0.0 18742 + nullthrows: 1.1.1 18743 + postcss-value-parser: 4.2.0 18744 + react: 19.1.0 18745 + react-dom: 19.1.0(react@19.1.0) 18746 + styleq: 0.1.3 18747 + transitivePeerDependencies: 18748 + - encoding 18749 + 18750 + react-native-worklets@0.5.1(@babel/core@7.28.6)(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): 18751 + dependencies: 18752 + '@babel/core': 7.28.6 18753 + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.6) 18754 + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.28.6) 18755 + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.28.6) 18756 + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.28.6) 18757 + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.28.6) 18758 + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.6) 18759 + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.6) 18760 + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.6) 18761 + '@babel/preset-typescript': 7.28.5(@babel/core@7.28.6) 18762 + convert-source-map: 2.0.0 18763 + react: 19.1.0 18764 + react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 18765 + semver: 7.7.2 18766 + transitivePeerDependencies: 18767 + - supports-color 18768 + 17564 18769 react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0): 17565 18770 dependencies: 17566 18771 '@jest/create-cache-key-function': 29.7.0 ··· 17612 18817 17613 18818 react-refresh@0.18.0: {} 17614 18819 18820 + react-remove-scroll-bar@2.3.8(@types/react@19.1.17)(react@19.1.0): 18821 + dependencies: 18822 + react: 19.1.0 18823 + react-style-singleton: 2.2.3(@types/react@19.1.17)(react@19.1.0) 18824 + tslib: 2.8.1 18825 + optionalDependencies: 18826 + '@types/react': 19.1.17 18827 + 17615 18828 react-remove-scroll-bar@2.3.8(@types/react@19.2.10)(react@19.2.4): 17616 18829 dependencies: 17617 18830 react: 19.2.4 ··· 17620 18833 optionalDependencies: 17621 18834 '@types/react': 19.2.10 17622 18835 18836 + react-remove-scroll@2.7.2(@types/react@19.1.17)(react@19.1.0): 18837 + dependencies: 18838 + react: 19.1.0 18839 + react-remove-scroll-bar: 2.3.8(@types/react@19.1.17)(react@19.1.0) 18840 + react-style-singleton: 2.2.3(@types/react@19.1.17)(react@19.1.0) 18841 + tslib: 2.8.1 18842 + use-callback-ref: 1.3.3(@types/react@19.1.17)(react@19.1.0) 18843 + use-sidecar: 1.1.3(@types/react@19.1.17)(react@19.1.0) 18844 + optionalDependencies: 18845 + '@types/react': 19.1.17 18846 + 17623 18847 react-remove-scroll@2.7.2(@types/react@19.2.10)(react@19.2.4): 17624 18848 dependencies: 17625 18849 react: 19.2.4 ··· 17631 18855 optionalDependencies: 17632 18856 '@types/react': 19.2.10 17633 18857 18858 + react-style-singleton@2.2.3(@types/react@19.1.17)(react@19.1.0): 18859 + dependencies: 18860 + get-nonce: 1.0.1 18861 + react: 19.1.0 18862 + tslib: 2.8.1 18863 + optionalDependencies: 18864 + '@types/react': 19.1.17 18865 + 17634 18866 react-style-singleton@2.2.3(@types/react@19.2.10)(react@19.2.4): 17635 18867 dependencies: 17636 18868 get-nonce: 1.0.1 ··· 17681 18913 17682 18914 reflect-metadata@0.2.2: {} 17683 18915 18916 + reflect.getprototypeof@1.0.10: 18917 + dependencies: 18918 + call-bind: 1.0.8 18919 + define-properties: 1.2.1 18920 + es-abstract: 1.24.1 18921 + es-errors: 1.3.0 18922 + es-object-atoms: 1.1.1 18923 + get-intrinsic: 1.3.0 18924 + get-proto: 1.0.1 18925 + which-builtin-type: 1.2.1 18926 + 17684 18927 regenerate-unicode-properties@10.2.2: 17685 18928 dependencies: 17686 18929 regenerate: 1.4.2 ··· 17691 18934 17692 18935 regexp-to-ast@0.5.0: {} 17693 18936 18937 + regexp.prototype.flags@1.5.4: 18938 + dependencies: 18939 + call-bind: 1.0.8 18940 + define-properties: 1.2.1 18941 + es-errors: 1.3.0 18942 + get-proto: 1.0.1 18943 + gopd: 1.2.0 18944 + set-function-name: 2.0.2 18945 + 17694 18946 regexpu-core@6.4.0: 17695 18947 dependencies: 17696 18948 regenerate: 1.4.2 ··· 17746 18998 dependencies: 17747 18999 path-parse: 1.0.7 17748 19000 19001 + resolve@2.0.0-next.5: 19002 + dependencies: 19003 + is-core-module: 2.16.1 19004 + path-parse: 1.0.7 19005 + supports-preserve-symlinks-flag: 1.0.0 19006 + 17749 19007 restore-cursor@2.0.0: 17750 19008 dependencies: 17751 19009 onetime: 2.0.1 ··· 17814 19072 rxjs@7.8.2: 17815 19073 dependencies: 17816 19074 tslib: 2.8.1 19075 + 19076 + safe-array-concat@1.1.3: 19077 + dependencies: 19078 + call-bind: 1.0.8 19079 + call-bound: 1.0.4 19080 + get-intrinsic: 1.3.0 19081 + has-symbols: 1.1.0 19082 + isarray: 2.0.5 17817 19083 17818 19084 safe-buffer@5.2.1: {} 17819 19085 19086 + safe-push-apply@1.0.0: 19087 + dependencies: 19088 + es-errors: 1.3.0 19089 + isarray: 2.0.5 19090 + 19091 + safe-regex-test@1.1.0: 19092 + dependencies: 19093 + call-bound: 1.0.4 19094 + es-errors: 1.3.0 19095 + is-regex: 1.2.1 19096 + 17820 19097 safe-stable-stringify@2.5.0: {} 17821 19098 17822 19099 safer-buffer@2.1.2: {} ··· 17847 19124 semver@6.3.1: {} 17848 19125 17849 19126 semver@7.6.3: {} 19127 + 19128 + semver@7.7.2: {} 17850 19129 17851 19130 semver@7.7.3: {} 17852 19131 ··· 17918 19197 17919 19198 server-only@0.0.1: {} 17920 19199 19200 + set-function-length@1.2.2: 19201 + dependencies: 19202 + define-data-property: 1.1.4 19203 + es-errors: 1.3.0 19204 + function-bind: 1.1.2 19205 + get-intrinsic: 1.3.0 19206 + gopd: 1.2.0 19207 + has-property-descriptors: 1.0.2 19208 + 19209 + set-function-name@2.0.2: 19210 + dependencies: 19211 + define-data-property: 1.1.4 19212 + es-errors: 1.3.0 19213 + functions-have-names: 1.2.3 19214 + has-property-descriptors: 1.0.2 19215 + 19216 + set-proto@1.0.0: 19217 + dependencies: 19218 + dunder-proto: 1.0.1 19219 + es-errors: 1.3.0 19220 + es-object-atoms: 1.1.1 19221 + 19222 + setimmediate@1.0.5: {} 19223 + 17921 19224 setprototypeof@1.2.0: {} 17922 19225 17923 19226 sf-symbols-typescript@2.2.0: {} ··· 18037 19340 18038 19341 srvx@0.10.1: {} 18039 19342 19343 + stable-hash@0.0.5: {} 19344 + 18040 19345 stack-utils@2.0.6: 18041 19346 dependencies: 18042 19347 escape-string-regexp: 2.0.0 ··· 18054 19359 statuses@2.0.2: {} 18055 19360 18056 19361 std-env@3.10.0: {} 19362 + 19363 + stop-iteration-iterator@1.1.0: 19364 + dependencies: 19365 + es-errors: 1.3.0 19366 + internal-slot: 1.1.0 18057 19367 18058 19368 stream-buffers@2.2.0: {} 18059 19369 ··· 18078 19388 emoji-regex: 9.2.2 18079 19389 strip-ansi: 7.1.2 18080 19390 19391 + string.prototype.matchall@4.0.12: 19392 + dependencies: 19393 + call-bind: 1.0.8 19394 + call-bound: 1.0.4 19395 + define-properties: 1.2.1 19396 + es-abstract: 1.24.1 19397 + es-errors: 1.3.0 19398 + es-object-atoms: 1.1.1 19399 + get-intrinsic: 1.3.0 19400 + gopd: 1.2.0 19401 + has-symbols: 1.1.0 19402 + internal-slot: 1.1.0 19403 + regexp.prototype.flags: 1.5.4 19404 + set-function-name: 2.0.2 19405 + side-channel: 1.1.0 19406 + 19407 + string.prototype.repeat@1.0.0: 19408 + dependencies: 19409 + define-properties: 1.2.1 19410 + es-abstract: 1.24.1 19411 + 19412 + string.prototype.trim@1.2.10: 19413 + dependencies: 19414 + call-bind: 1.0.8 19415 + call-bound: 1.0.4 19416 + define-data-property: 1.1.4 19417 + define-properties: 1.2.1 19418 + es-abstract: 1.24.1 19419 + es-object-atoms: 1.1.1 19420 + has-property-descriptors: 1.0.2 19421 + 19422 + string.prototype.trimend@1.0.9: 19423 + dependencies: 19424 + call-bind: 1.0.8 19425 + call-bound: 1.0.4 19426 + define-properties: 1.2.1 19427 + es-object-atoms: 1.1.1 19428 + 19429 + string.prototype.trimstart@1.0.8: 19430 + dependencies: 19431 + call-bind: 1.0.8 19432 + define-properties: 1.2.1 19433 + es-object-atoms: 1.1.1 19434 + 18081 19435 string_decoder@1.3.0: 18082 19436 dependencies: 18083 19437 safe-buffer: 5.2.1 ··· 18118 19472 peek-readable: 4.1.0 18119 19473 18120 19474 structured-headers@0.4.1: {} 19475 + 19476 + styleq@0.1.3: {} 18121 19477 18122 19478 sucrase@3.35.1: 18123 19479 dependencies: ··· 18188 19544 '@pkgr/core': 0.2.9 18189 19545 18190 19546 tailwind-merge@3.4.0: {} 18191 - 18192 - tailwindcss@4.1.17: {} 18193 19547 18194 19548 tailwindcss@4.1.18: {} 18195 19549 ··· 18317 19671 dependencies: 18318 19672 tldts: 7.0.19 18319 19673 19674 + tr46@0.0.3: {} 19675 + 18320 19676 tr46@6.0.0: 18321 19677 dependencies: 18322 19678 punycode: 2.3.1 ··· 18391 19747 tapable: 2.3.0 18392 19748 tsconfig-paths: 4.2.0 18393 19749 19750 + tsconfig-paths@3.15.0: 19751 + dependencies: 19752 + '@types/json5': 0.0.29 19753 + json5: 1.0.2 19754 + minimist: 1.2.8 19755 + strip-bom: 3.0.0 19756 + 18394 19757 tsconfig-paths@4.2.0: 18395 19758 dependencies: 18396 19759 json5: 2.2.3 ··· 18463 19826 media-typer: 1.1.0 18464 19827 mime-types: 3.0.2 18465 19828 19829 + typed-array-buffer@1.0.3: 19830 + dependencies: 19831 + call-bound: 1.0.4 19832 + es-errors: 1.3.0 19833 + is-typed-array: 1.1.15 19834 + 19835 + typed-array-byte-length@1.0.3: 19836 + dependencies: 19837 + call-bind: 1.0.8 19838 + for-each: 0.3.5 19839 + gopd: 1.2.0 19840 + has-proto: 1.2.0 19841 + is-typed-array: 1.1.15 19842 + 19843 + typed-array-byte-offset@1.0.4: 19844 + dependencies: 19845 + available-typed-arrays: 1.0.7 19846 + call-bind: 1.0.8 19847 + for-each: 0.3.5 19848 + gopd: 1.2.0 19849 + has-proto: 1.2.0 19850 + is-typed-array: 1.1.15 19851 + reflect.getprototypeof: 1.0.10 19852 + 19853 + typed-array-length@1.0.7: 19854 + dependencies: 19855 + call-bind: 1.0.8 19856 + for-each: 0.3.5 19857 + gopd: 1.2.0 19858 + is-typed-array: 1.1.15 19859 + possible-typed-array-names: 1.1.0 19860 + reflect.getprototypeof: 1.0.10 19861 + 18466 19862 typedarray@0.0.6: {} 18467 19863 18468 19864 typescript-eslint@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): ··· 18477 19873 - supports-color 18478 19874 18479 19875 typescript@5.9.3: {} 19876 + 19877 + ua-parser-js@1.0.41: {} 18480 19878 18481 19879 ufo@1.6.3: {} 18482 19880 ··· 18493 19891 dependencies: 18494 19892 multiformats: 9.9.0 18495 19893 19894 + unbox-primitive@1.1.0: 19895 + dependencies: 19896 + call-bound: 1.0.4 19897 + has-bigints: 1.1.0 19898 + has-symbols: 1.1.0 19899 + which-boxed-primitive: 1.1.1 19900 + 18496 19901 undici-types@6.21.0: {} 18497 - 18498 - undici-types@7.16.0: {} 18499 19902 18500 19903 undici@6.23.0: {} 18501 19904 ··· 18523 19926 crypto-random-string: 2.0.0 18524 19927 18525 19928 universalify@2.0.1: {} 18526 - 18527 - uniwind@1.2.7(react-native@0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@4.1.18): 18528 - dependencies: 18529 - '@tailwindcss/node': 4.1.17 18530 - '@tailwindcss/oxide': 4.1.17 18531 - culori: 4.0.2 18532 - lightningcss: 1.30.2 18533 - react: 19.1.0 18534 - react-native: 0.81.5(@babel/core@7.28.6)(@types/react@19.1.17)(react@19.1.0) 18535 - tailwindcss: 4.1.18 18536 19929 18537 19930 unpipe@1.0.0: {} 18538 19931 ··· 18584 19977 dependencies: 18585 19978 punycode: 2.3.1 18586 19979 19980 + use-callback-ref@1.3.3(@types/react@19.1.17)(react@19.1.0): 19981 + dependencies: 19982 + react: 19.1.0 19983 + tslib: 2.8.1 19984 + optionalDependencies: 19985 + '@types/react': 19.1.17 19986 + 18587 19987 use-callback-ref@1.3.3(@types/react@19.2.10)(react@19.2.4): 18588 19988 dependencies: 18589 19989 react: 19.2.4 ··· 18594 19994 use-latest-callback@0.2.6(react@19.1.0): 18595 19995 dependencies: 18596 19996 react: 19.1.0 19997 + 19998 + use-sidecar@1.1.3(@types/react@19.1.17)(react@19.1.0): 19999 + dependencies: 20000 + detect-node-es: 1.1.0 20001 + react: 19.1.0 20002 + tslib: 2.8.1 20003 + optionalDependencies: 20004 + '@types/react': 19.1.17 18597 20005 18598 20006 use-sidecar@1.1.3(@types/react@19.2.10)(react@19.2.4): 18599 20007 dependencies: ··· 18641 20049 18642 20050 vary@1.1.2: {} 18643 20051 20052 + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): 20053 + dependencies: 20054 + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 20055 + react: 19.1.0 20056 + react-dom: 19.1.0(react@19.1.0) 20057 + transitivePeerDependencies: 20058 + - '@types/react' 20059 + - '@types/react-dom' 20060 + 18644 20061 vite-node@3.2.4(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): 18645 20062 dependencies: 18646 20063 cac: 6.7.14 ··· 18758 20175 18759 20176 web-vitals@5.1.0: {} 18760 20177 20178 + webidl-conversions@3.0.1: {} 20179 + 18761 20180 webidl-conversions@5.0.0: {} 18762 20181 18763 20182 webidl-conversions@8.0.1: {} ··· 18820 20239 dependencies: 18821 20240 tr46: 6.0.0 18822 20241 webidl-conversions: 8.0.1 20242 + 20243 + whatwg-url@5.0.0: 20244 + dependencies: 20245 + tr46: 0.0.3 20246 + webidl-conversions: 3.0.1 20247 + 20248 + which-boxed-primitive@1.1.1: 20249 + dependencies: 20250 + is-bigint: 1.1.0 20251 + is-boolean-object: 1.2.2 20252 + is-number-object: 1.1.1 20253 + is-string: 1.1.1 20254 + is-symbol: 1.1.1 20255 + 20256 + which-builtin-type@1.2.1: 20257 + dependencies: 20258 + call-bound: 1.0.4 20259 + function.prototype.name: 1.1.8 20260 + has-tostringtag: 1.0.2 20261 + is-async-function: 2.1.1 20262 + is-date-object: 1.1.0 20263 + is-finalizationregistry: 1.1.1 20264 + is-generator-function: 1.1.2 20265 + is-regex: 1.2.1 20266 + is-weakref: 1.1.1 20267 + isarray: 2.0.5 20268 + which-boxed-primitive: 1.1.1 20269 + which-collection: 1.0.2 20270 + which-typed-array: 1.1.20 20271 + 20272 + which-collection@1.0.2: 20273 + dependencies: 20274 + is-map: 2.0.3 20275 + is-set: 2.0.3 20276 + is-weakmap: 2.0.2 20277 + is-weakset: 2.0.4 20278 + 20279 + which-typed-array@1.1.20: 20280 + dependencies: 20281 + available-typed-arrays: 1.0.7 20282 + call-bind: 1.0.8 20283 + call-bound: 1.0.4 20284 + for-each: 0.3.5 20285 + get-proto: 1.0.1 20286 + gopd: 1.2.0 20287 + has-tostringtag: 1.0.2 18823 20288 18824 20289 which@2.0.2: 18825 20290 dependencies: