this repo has no description
0
fork

Configure Feed

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

get timeline working!!!

+403 -40
+1 -1
apps/expo/index.tsx
··· 1 - import "./src/utils/polyfills/platform-polyfills"; 1 + import "./src/lib/utils/polyfills/platform-polyfills"; 2 2 import { registerRootComponent } from "expo"; 3 3 import { ExpoRoot } from "expo-router"; 4 4
+3
apps/expo/package.json
··· 14 14 "dependencies": { 15 15 "@atproto/api": "^0.2.7", 16 16 "@expo/metro-config": "^0.7.1", 17 + "@react-native-async-storage/async-storage": "1.17.11", 17 18 "@shopify/flash-list": "1.4.2", 18 19 "@tanstack/react-query": "^4.28.0", 19 20 "@trpc/client": "^10.20.0", ··· 29 30 "expo-status-bar": "~1.4.4", 30 31 "fast-text-encoding": "^1.0.6", 31 32 "graphemer": "^1.4.0", 33 + "lucide-react-native": "^0.145.0", 32 34 "nativewind": "^2.0.11", 33 35 "react": "18.2.0", 34 36 "react-dom": "18.2.0", 35 37 "react-native": "0.71.6", 36 38 "react-native-safe-area-context": "4.5.0", 37 39 "react-native-screens": "~3.20.0", 40 + "react-native-svg": "^13.9.0", 38 41 "react-native-url-polyfill": "^1.3.0", 39 42 "superjson": "1.9.1", 40 43 "tailwind-merge": "^1.12.0"
+15
apps/expo/src/app/(app)/_layout.tsx
··· 1 + import { Stack, Tabs } from "expo-router"; 2 + 3 + import { useAuthedAgent } from "../../lib/agent"; 4 + 5 + export default function AppLayout() { 6 + const agent = useAuthedAgent(); 7 + return ( 8 + <> 9 + <Stack.Screen 10 + options={{ headerTitle: agent.session.handle, animation: "none" }} 11 + /> 12 + <Tabs screenOptions={{ headerShown: false }} /> 13 + </> 14 + ); 15 + }
+119
apps/expo/src/app/(app)/app.tsx
··· 1 + import { ActivityIndicator, Text, View } from "react-native"; 2 + // import { Tabs } from "expo-router"; 3 + import { type AppBskyFeedPost } from "@atproto/api"; 4 + import { type FeedViewPost } from "@atproto/api/dist/client/types/app/bsky/feed/defs"; 5 + import { FlashList } from "@shopify/flash-list"; 6 + import { useInfiniteQuery } from "@tanstack/react-query"; 7 + import { Heart, MessageSquare, Repeat } from "lucide-react-native"; 8 + 9 + import { Button } from "../../components/button"; 10 + import { useAuthedAgent } from "../../lib/agent"; 11 + 12 + function Timeline() { 13 + const agent = useAuthedAgent(); 14 + const timeline = useInfiniteQuery({ 15 + queryKey: ["timeline"], 16 + queryFn: async ({ pageParam }) => { 17 + const timeline = await agent.getTimeline({ 18 + limit: 5, 19 + cursor: pageParam as string | undefined, 20 + }); 21 + return timeline.data; 22 + }, 23 + getNextPageParam: (lastPage) => lastPage.cursor, 24 + }); 25 + 26 + switch (timeline.status) { 27 + case "loading": 28 + return ( 29 + <View className="flex-1 items-center justify-center"> 30 + <ActivityIndicator size="large" /> 31 + </View> 32 + ); 33 + 34 + case "error": 35 + return ( 36 + <View className="flex-1 items-center justify-center p-4"> 37 + <Text className="text-center text-xl"> 38 + {(timeline.error as Error).message || "An error occurred"} 39 + </Text> 40 + <Button variant="outline" onPress={() => void timeline.refetch()}> 41 + Retry 42 + </Button> 43 + </View> 44 + ); 45 + 46 + case "success": 47 + return ( 48 + <FlashList 49 + onEndReached={() => void timeline.fetchNextPage()} 50 + className="flex-1" 51 + data={timeline.data.pages.flatMap((page) => page.feed)} 52 + estimatedItemSize={107} 53 + renderItem={({ item }) => <Post item={item} />} 54 + /> 55 + ); 56 + } 57 + } 58 + 59 + export default function TimelinePage() { 60 + return ( 61 + <> 62 + {/* <Tabs.Screen /> */} 63 + <Timeline /> 64 + </> 65 + ); 66 + } 67 + 68 + const Post = ({ item }: { item: FeedViewPost }) => { 69 + return ( 70 + <View 71 + className="gap- border border-b border-neutral-200 bg-white p-4" 72 + // onLayout={(x) => console.log(x.nativeEvent.layout)} 73 + > 74 + {void console.log(item.post.embed)} 75 + <Text className="text-base"> 76 + {item.post.author.displayName}{" "} 77 + <Text className="text-neutral-400">@{item.post.author.handle}</Text> 78 + </Text> 79 + {/* text content */} 80 + <Text className="text-base"> 81 + {(item.post.record as AppBskyFeedPost.Record).text} 82 + </Text> 83 + <View className="flex-row justify-between pt-2"> 84 + <View className="flex-row items-center gap-2"> 85 + <MessageSquare size={16} color="#1C1C1E" /> 86 + <Text>{item.post.replyCount}</Text> 87 + </View> 88 + <View className="flex-row items-center gap-2"> 89 + <Repeat 90 + size={16} 91 + color={item.post.viewer?.repost ? "#2563eb" : "#1C1C1E"} 92 + /> 93 + <Text 94 + style={{ 95 + color: item.post.viewer?.repost ? "#2563eb" : "#1C1C1E", 96 + }} 97 + > 98 + {item.post.repostCount} 99 + </Text> 100 + </View> 101 + <View className="flex-row items-center gap-2"> 102 + <Heart 103 + size={16} 104 + fill={item.post.viewer?.like ? "#dc2626" : "transparent"} 105 + color={item.post.viewer?.like ? "#dc2626" : "#1C1C1E"} 106 + /> 107 + <Text 108 + style={{ 109 + color: item.post.viewer?.like ? "#dc2626" : "#1C1C1E", 110 + }} 111 + > 112 + {item.post.likeCount} 113 + </Text> 114 + </View> 115 + <View className="w-8" /> 116 + </View> 117 + </View> 118 + ); 119 + };
+109 -13
apps/expo/src/app/_layout.tsx
··· 1 + import { useEffect, useMemo, useState } from "react"; 2 + import { Alert } from "react-native"; 1 3 import { SafeAreaProvider } from "react-native-safe-area-context"; 2 - import { Stack } from "expo-router"; 4 + import { SplashScreen, Stack, useRouter, useSegments } from "expo-router"; 3 5 import { StatusBar } from "expo-status-bar"; 6 + import { 7 + BskyAgent, 8 + type AtpSessionData, 9 + type AtpSessionEvent, 10 + } from "@atproto/api"; 11 + import AsyncStorage from "@react-native-async-storage/async-storage"; 4 12 import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 5 13 14 + import { AgentProvider } from "../lib/agent"; 15 + import { fetchHandler } from "../lib/utils/polyfills/fetch-polyfill"; 16 + 6 17 const queryClient = new QueryClient(); 7 18 8 19 export default function RootLayout() { 20 + const segments = useSegments(); 21 + const router = useRouter(); 22 + const [loading, setLoading] = useState(true); 23 + const [session, setSession] = useState<AtpSessionData | null>(null); 24 + 25 + const agent = useMemo(() => { 26 + BskyAgent.configure({ fetch: fetchHandler }); 27 + return new BskyAgent({ 28 + service: "https://bsky.social/", 29 + persistSession(evt: AtpSessionEvent, sess?: AtpSessionData) { 30 + // store the session-data for reuse 31 + switch (evt) { 32 + case "create": 33 + console.log("session created"); 34 + if (!sess) throw new Error("should be unreachable"); 35 + void AsyncStorage.setItem("session", JSON.stringify(sess)); 36 + setSession(sess); 37 + break; 38 + case "create-failed": 39 + void AsyncStorage.removeItem("session"); 40 + setSession(null); 41 + Alert.alert( 42 + "An error occurred", 43 + "Please check your details and try again", 44 + ); 45 + break; 46 + case "update": 47 + console.log("session updated"); 48 + if (!sess) throw new Error("should be unreachable"); 49 + void AsyncStorage.setItem("session", JSON.stringify(sess)); 50 + setSession(sess); 51 + break; 52 + case "expired": 53 + console.log("session expired"); 54 + void AsyncStorage.removeItem("session"); 55 + setSession(null); 56 + break; 57 + } 58 + }, 59 + }); 60 + }, []); 61 + 62 + useEffect(() => { 63 + AsyncStorage.getItem("session") 64 + .then(async (sess) => { 65 + if (sess) { 66 + const session = JSON.parse(sess) as AtpSessionData; 67 + await agent.resumeSession(session); 68 + setSession(session); 69 + } 70 + setLoading(false); 71 + }) 72 + .catch((err) => { 73 + console.error(err); 74 + setLoading(false); 75 + }); 76 + }, [agent]); 77 + 78 + const did = session?.did; 79 + 80 + // invalidate all queries when the session changes 81 + useEffect(() => { 82 + void queryClient.invalidateQueries(); 83 + }, [did]); 84 + 85 + // redirect depending on login state 86 + useEffect(() => { 87 + // early return if we're still loading 88 + if (loading) return; 89 + const atRoot = segments.length === 0; 90 + const inAuthGroup = segments[0] === "(auth)"; 91 + 92 + if ( 93 + // If the user is not signed in and the initial segment is not anything in the auth group. 94 + !did && 95 + !inAuthGroup && 96 + !atRoot 97 + ) { 98 + // Redirect to the sign-in page. 99 + router.replace("/login"); 100 + } else if (did && (inAuthGroup || atRoot)) { 101 + // Redirect away from the sign-in page. 102 + router.replace("/app"); 103 + } 104 + }, [did, segments, router, loading]); 105 + 9 106 return ( 10 107 <QueryClientProvider client={queryClient}> 11 108 <SafeAreaProvider> 12 - {/* 13 - The Stack component displays the current page. 14 - It also allows you to configure your screens 15 - */} 16 - <Stack 17 - screenOptions={{ 18 - headerStyle: { 19 - backgroundColor: "#fff", 20 - }, 21 - }} 22 - /> 23 - <StatusBar /> 109 + <AgentProvider value={agent}> 110 + {loading && <SplashScreen />} 111 + <Stack 112 + screenOptions={{ 113 + headerStyle: { 114 + backgroundColor: "#fff", 115 + }, 116 + }} 117 + /> 118 + <StatusBar /> 119 + </AgentProvider> 24 120 </SafeAreaProvider> 25 121 </QueryClientProvider> 26 122 );
+2 -2
apps/expo/src/app/index.tsx
··· 17 17 return ( 18 18 <View className="flex-1"> 19 19 <StatusBar style="light" /> 20 - <Stack.Screen options={{ header: () => null }} /> 20 + <Stack.Screen options={{ headerShown: false }} /> 21 21 <ImageBackground className="flex-1" source={background}> 22 - <SafeAreaView className="flex flex-1 items-stretch justify-between p-4"> 22 + <SafeAreaView className="flex-1 items-stretch justify-between p-4"> 23 23 <Text className="mx-auto mt-16 text-6xl font-bold text-white"> 24 24 GRAYSKY 25 25 </Text>
+4 -22
apps/expo/src/app/login.tsx apps/expo/src/app/(auth)/login.tsx
··· 1 - import { useMemo, useState } from "react"; 1 + import { useState } from "react"; 2 2 import { Button, TextInput, View } from "react-native"; 3 3 import { SafeAreaView } from "react-native-safe-area-context"; 4 4 import { Stack } from "expo-router"; 5 - import { 6 - BskyAgent, 7 - type AtpSessionData, 8 - type AtpSessionEvent, 9 - } from "@atproto/api"; 10 5 import { useMutation } from "@tanstack/react-query"; 11 6 12 - import { fetchHandler } from "../utils/polyfills/fetch-polyfill"; 7 + import { useAgent } from "../../lib/agent"; 13 8 14 9 export default function Login() { 15 10 const [identifier, setIdentifier] = useState(""); 16 11 const [password, setPassword] = useState(""); 17 12 18 - const agent = useMemo(() => { 19 - BskyAgent.configure({ fetch: fetchHandler }); 20 - return new BskyAgent({ 21 - service: "https://bsky.social/", 22 - persistSession(evt: AtpSessionEvent, sess?: AtpSessionData) { 23 - // store the session-data for reuse 24 - console.log({ 25 - evt, 26 - sess, 27 - }); 28 - }, 29 - }); 30 - }, []); 13 + const agent = useAgent(); 31 14 32 15 const login = useMutation({ 33 16 mutationKey: ["login"], 34 17 mutationFn: async () => { 35 18 try { 36 - console.log({ identifier, password }); 37 19 await agent.login({ identifier, password }); 38 20 } catch (err) { 39 21 console.info("caught error"); ··· 45 27 return ( 46 28 <SafeAreaView className="flex-1 px-4"> 47 29 <Stack.Screen options={{ title: "Log in" }} /> 48 - <View className="flex gap-4"> 30 + <View className="gap-4"> 49 31 <TextInput 50 32 className="rounded bg-white p-2 text-base" 51 33 placeholder="Username or email address"
+2 -2
apps/expo/src/components/button.tsx
··· 2 2 import { Text, TouchableOpacity } from "react-native"; 3 3 import { useRouter } from "expo-router"; 4 4 5 - import { cx } from "../utils/cx"; 5 + import { cx } from "../lib/utils/cx"; 6 6 7 7 interface ButtonProps extends React.PropsWithChildren { 8 8 onPress: () => void; ··· 21 21 <TouchableOpacity 22 22 onPress={onPress} 23 23 className={cx( 24 - "flex items-center justify-center rounded-sm px-4 py-2", 24 + "items-center justify-center rounded-sm px-4 py-2", 25 25 { 26 26 black: "bg-black", 27 27 white: "bg-white",
+23
apps/expo/src/lib/agent.ts
··· 1 + import { createContext, useContext } from "react"; 2 + import { useRouter } from "expo-router"; 3 + import { type AtpSessionData, type BskyAgent } from "@atproto/api"; 4 + 5 + const agentContext = createContext<BskyAgent | null>(null); 6 + 7 + export default agentContext; 8 + 9 + export const useAgent = () => { 10 + const agent = useContext(agentContext); 11 + if (!agent) throw new Error("No agent found in context"); 12 + return agent; 13 + }; 14 + 15 + export const useAuthedAgent = () => { 16 + const router = useRouter(); 17 + const agent = useContext(agentContext); 18 + if (!agent) throw new Error("No agent found in context"); 19 + if (!agent.hasSession) router.replace("/login"); 20 + return agent as BskyAgent & { session: AtpSessionData }; 21 + }; 22 + 23 + export const AgentProvider = agentContext.Provider;
apps/expo/src/utils/api.tsx apps/expo/src/lib/utils/api.tsx
apps/expo/src/utils/cx.ts apps/expo/src/lib/utils/cx.ts
apps/expo/src/utils/polyfills/fetch-polyfill.ts apps/expo/src/lib/utils/polyfills/fetch-polyfill.ts
apps/expo/src/utils/polyfills/platform-polyfills.ts apps/expo/src/lib/utils/polyfills/platform-polyfills.ts
+125
pnpm-lock.yaml
··· 40 40 '@expo/metro-config': 41 41 specifier: ^0.7.1 42 42 version: 0.7.1 43 + '@react-native-async-storage/async-storage': 44 + specifier: 1.17.11 45 + version: 1.17.11(react-native@0.71.6) 43 46 '@shopify/flash-list': 44 47 specifier: 1.4.2 45 48 version: 1.4.2(@babel/runtime@7.21.0)(react-native@0.71.6)(react@18.2.0) ··· 85 88 graphemer: 86 89 specifier: ^1.4.0 87 90 version: 1.4.0 91 + lucide-react-native: 92 + specifier: ^0.145.0 93 + version: 0.145.0(prop-types@15.8.1)(react-native-svg@13.9.0)(react-native@0.71.6)(react@18.2.0) 88 94 nativewind: 89 95 specifier: ^2.0.11 90 96 version: 2.0.11(react@18.2.0)(tailwindcss@3.3.1) ··· 103 109 react-native-screens: 104 110 specifier: ~3.20.0 105 111 version: 3.20.0(react-native@0.71.6)(react@18.2.0) 112 + react-native-svg: 113 + specifier: ^13.9.0 114 + version: 13.9.0(react-native@0.71.6)(react@18.2.0) 106 115 react-native-url-polyfill: 107 116 specifier: ^1.3.0 108 117 version: 1.3.0(react-native@0.71.6) ··· 2440 2449 react: 18.2.0 2441 2450 dev: false 2442 2451 2452 + /@react-native-async-storage/async-storage@1.17.11(react-native@0.71.6): 2453 + resolution: {integrity: sha512-bzs45n5HNcDq6mxXnSsOHysZWn1SbbebNxldBXCQs8dSvF8Aor9KCdpm+TpnnGweK3R6diqsT8lFhX77VX0NFw==} 2454 + peerDependencies: 2455 + react-native: ^0.0.0-0 || 0.60 - 0.71 || 1000.0.0 2456 + dependencies: 2457 + merge-options: 3.0.4 2458 + react-native: 0.71.6(@babel/core@7.21.4)(@babel/preset-env@7.21.4)(react@18.2.0) 2459 + dev: false 2460 + 2443 2461 /@react-native-community/cli-clean@10.1.1: 2444 2462 resolution: {integrity: sha512-iNsrjzjIRv9yb5y309SWJ8NDHdwYtnCpmxZouQDyOljUdC9MwdZ4ChbtA4rwQyAwgOVfS9F/j56ML3Cslmvrxg==} 2445 2463 dependencies: ··· 3614 3632 - supports-color 3615 3633 dev: false 3616 3634 3635 + /boolbase@1.0.0: 3636 + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} 3637 + dev: false 3638 + 3617 3639 /bplist-creator@0.1.0: 3618 3640 resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} 3619 3641 dependencies: ··· 4163 4185 resolution: {integrity: sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==} 4164 4186 dev: false 4165 4187 4188 + /css-select@5.1.0: 4189 + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} 4190 + dependencies: 4191 + boolbase: 1.0.0 4192 + css-what: 6.1.0 4193 + domhandler: 5.0.3 4194 + domutils: 3.0.1 4195 + nth-check: 2.1.1 4196 + dev: false 4197 + 4166 4198 /css-to-react-native@3.0.0: 4167 4199 resolution: {integrity: sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==} 4168 4200 dependencies: 4169 4201 camelize: 1.0.1 4170 4202 css-color-keywords: 1.0.0 4171 4203 postcss-value-parser: 4.2.0 4204 + dev: false 4205 + 4206 + /css-tree@1.1.3: 4207 + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} 4208 + engines: {node: '>=8.0.0'} 4209 + dependencies: 4210 + mdn-data: 2.0.14 4211 + source-map: 0.6.1 4212 + dev: false 4213 + 4214 + /css-what@6.1.0: 4215 + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} 4216 + engines: {node: '>= 6'} 4172 4217 dev: false 4173 4218 4174 4219 /cssesc@3.0.0: ··· 4389 4434 dependencies: 4390 4435 esutils: 2.0.3 4391 4436 4437 + /dom-serializer@2.0.0: 4438 + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} 4439 + dependencies: 4440 + domelementtype: 2.3.0 4441 + domhandler: 5.0.3 4442 + entities: 4.5.0 4443 + dev: false 4444 + 4445 + /domelementtype@2.3.0: 4446 + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} 4447 + dev: false 4448 + 4449 + /domhandler@5.0.3: 4450 + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} 4451 + engines: {node: '>= 4'} 4452 + dependencies: 4453 + domelementtype: 2.3.0 4454 + dev: false 4455 + 4456 + /domutils@3.0.1: 4457 + resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} 4458 + dependencies: 4459 + dom-serializer: 2.0.0 4460 + domelementtype: 2.3.0 4461 + domhandler: 5.0.3 4462 + dev: false 4463 + 4392 4464 /dotenv-cli@7.1.0: 4393 4465 resolution: {integrity: sha512-motytjZFQB3ZtGTIN4c0vnFgv4kuNZ2WxVnGY6PVFiygCzkm3IFBBguDUzezd9HgNA0OYYd6vNCWlozs0Q1Zxg==} 4394 4466 hasBin: true ··· 4441 4513 dependencies: 4442 4514 graceful-fs: 4.2.11 4443 4515 tapable: 2.2.1 4516 + dev: false 4517 + 4518 + /entities@4.5.0: 4519 + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} 4520 + engines: {node: '>=0.12'} 4444 4521 dev: false 4445 4522 4446 4523 /env-editor@0.4.2: ··· 6022 6099 resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 6023 6100 engines: {node: '>=8'} 6024 6101 6102 + /is-plain-obj@2.1.0: 6103 + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} 6104 + engines: {node: '>=8'} 6105 + dev: false 6106 + 6025 6107 /is-plain-object@2.0.4: 6026 6108 resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} 6027 6109 engines: {node: '>=0.10.0'} ··· 6554 6636 dependencies: 6555 6637 yallist: 4.0.0 6556 6638 6639 + /lucide-react-native@0.145.0(prop-types@15.8.1)(react-native-svg@13.9.0)(react-native@0.71.6)(react@18.2.0): 6640 + resolution: {integrity: sha512-Fa5RiNYu10m7Pq4X6vn+ujHGuenI9/xmBp5KMPo2i3F9utIkjvayMgFiD1xVKfW6yAWvnYPe89ub63zvGGVaQA==} 6641 + peerDependencies: 6642 + prop-types: ^15.7.2 6643 + react: ^16.5.1 || ^17.0.0 || ^18.0.0 6644 + react-native: '*' 6645 + react-native-svg: ^12.0.0 || ^13.0.0 6646 + dependencies: 6647 + prop-types: 15.8.1 6648 + react: 18.2.0 6649 + react-native: 0.71.6(@babel/core@7.21.4)(@babel/preset-env@7.21.4)(react@18.2.0) 6650 + react-native-svg: 13.9.0(react-native@0.71.6)(react@18.2.0) 6651 + dev: false 6652 + 6557 6653 /make-dir@2.1.0: 6558 6654 resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} 6559 6655 engines: {node: '>=6'} ··· 6604 6700 resolution: {integrity: sha512-c2YOUbp33+6thdCUi34xIyOU/a7bvGKj/3DB1iaPMTuPHf/Q2d5s4sn1FaCOO43XkXggnb08y5W2PU8UNYNLKQ==} 6605 6701 dev: false 6606 6702 6703 + /mdn-data@2.0.14: 6704 + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} 6705 + dev: false 6706 + 6607 6707 /media-typer@0.3.0: 6608 6708 resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} 6609 6709 engines: {node: '>= 0.6'} ··· 6614 6714 6615 6715 /memory-cache@0.2.0: 6616 6716 resolution: {integrity: sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==} 6717 + dev: false 6718 + 6719 + /merge-options@3.0.4: 6720 + resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} 6721 + engines: {node: '>=10'} 6722 + dependencies: 6723 + is-plain-obj: 2.1.0 6617 6724 dev: false 6618 6725 6619 6726 /merge-stream@2.0.0: ··· 7543 7650 dependencies: 7544 7651 path-key: 2.0.1 7545 7652 7653 + /nth-check@2.1.1: 7654 + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} 7655 + dependencies: 7656 + boolbase: 1.0.0 7657 + dev: false 7658 + 7546 7659 /nullthrows@1.1.1: 7547 7660 resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} 7548 7661 ··· 8379 8492 react-freeze: 1.0.3(react@18.2.0) 8380 8493 react-native: 0.71.6(@babel/core@7.21.4)(@babel/preset-env@7.21.4)(react@18.2.0) 8381 8494 warn-once: 0.1.1 8495 + dev: false 8496 + 8497 + /react-native-svg@13.9.0(react-native@0.71.6)(react@18.2.0): 8498 + resolution: {integrity: sha512-Ey18POH0dA0ob/QiwCBVrxIiwflhYuw0P0hBlOHeY4J5cdbs8ngdKHeWC/Kt9+ryP6fNoEQ1PUgPYw2Bs/rp5Q==} 8499 + peerDependencies: 8500 + react: '*' 8501 + react-native: '*' 8502 + dependencies: 8503 + css-select: 5.1.0 8504 + css-tree: 1.1.3 8505 + react: 18.2.0 8506 + react-native: 0.71.6(@babel/core@7.21.4)(@babel/preset-env@7.21.4)(react@18.2.0) 8382 8507 dev: false 8383 8508 8384 8509 /react-native-url-polyfill@1.3.0(react-native@0.71.6):