diff --git a/app.json b/app.json index 9ad190e..7413002 100644 --- a/app.json +++ b/app.json @@ -16,7 +16,7 @@ "supportsTablet": true, "bundleIdentifier": "com.cally.app", "googleServicesFile": "./ios/GoogleService-Info.plist", - "buildNumber": "40", + "buildNumber": "60", "usesAppleSignIn": true }, "android": { diff --git a/app/(auth)/_layout.tsx b/app/(auth)/_layout.tsx index 5edd485..13d04c3 100644 --- a/app/(auth)/_layout.tsx +++ b/app/(auth)/_layout.tsx @@ -6,8 +6,8 @@ import { DrawerItem, DrawerItemList, } from "@react-navigation/drawer"; -import { Button, View, Text, ButtonSize, Constants } from "react-native-ui-lib"; -import { StyleSheet } from "react-native"; +import { Button, View, Text, ButtonSize } from "react-native-ui-lib"; +import { Dimensions, ImageBackground, StyleSheet } from "react-native"; import Feather from "@expo/vector-icons/Feather"; import DrawerButton from "@/components/shared/DrawerButton"; import { @@ -24,9 +24,21 @@ import NavBrainDumpIcon from "@/assets/svgs/NavBrainDumpIcon"; import NavCalendarIcon from "@/assets/svgs/NavCalendarIcon"; import NavSettingsIcon from "@/assets/svgs/NavSettingsIcon"; import ViewSwitch from "@/components/pages/(tablet_pages)/ViewSwitch"; +import { useAtom, useSetAtom } from "jotai"; +import { + isFamilyViewAtom, + settingsPageIndex, + toDosPageIndex, + userSettingsView, +} from "@/components/pages/calendar/atoms"; +import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon"; export default function TabLayout() { const { mutateAsync: signOut } = useSignOut(); + const setIsFamilyView = useSetAtom(isFamilyViewAtom); + const setPageIndex = useSetAtom(settingsPageIndex); + const setUserView = useSetAtom(userSettingsView); + const setToDosIndex = useSetAtom(toDosPageIndex); return ( , }} drawerContent={(props) => { return ( - - + + + Welcome to Cally props.navigation.navigate("calendar")} + pressFunc={() => { + props.navigation.navigate("calendar"); + setPageIndex(0); + setToDosIndex(0); + setUserView(true); + setIsFamilyView(false); + }} icon={} /> props.navigation.navigate("grocery")} + pressFunc={() => { + props.navigation.navigate("grocery"); + setPageIndex(0); + setToDosIndex(0); + setUserView(true); + setIsFamilyView(false); + }} icon={} /> + { + props.navigation.navigate("feedback"); + setPageIndex(0); + setToDosIndex(0); + setUserView(true); + setIsFamilyView(false); + }} + icon={} + /> {/* props.navigation.navigate("todos")} + pressFunc={() => { + props.navigation.navigate("todos"); + setPageIndex(0); + setToDosIndex(0); + setUserView(true); + setIsFamilyView(false); + }} icon={} /> props.navigation.navigate("brain_dump")} + pressFunc={() => { + props.navigation.navigate("brain_dump"); + setPageIndex(0); + setToDosIndex(0); + setUserView(true); + setIsFamilyView(false); + }} icon={} /> {/* signOut()} />*/} + } + /> + )} - {pageIndex == 1 && } - {pageIndex == 2 && } + + - { - profileData?.userType == ProfileType.PARENT && - } - - ) - ; + )} + {pageIndex == 1 && ( + + )} + {pageIndex == 2 && } + + + + + ); }; const styles = StyleSheet.create({ - linkBtn: { - backgroundColor: "transparent", - padding: 0, - }, + linkBtn: { + backgroundColor: "transparent", + padding: 0, + }, }); export default ToDosPage; diff --git a/components/pages/todos/family-chores/FamilyChoresProgress.tsx b/components/pages/todos/family-chores/FamilyChoresProgress.tsx index 8e2bcb1..66570fe 100644 --- a/components/pages/todos/family-chores/FamilyChoresProgress.tsx +++ b/components/pages/todos/family-chores/FamilyChoresProgress.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ImageBackground, StyleSheet } from "react-native"; import FamilyChart from "./FamilyChart"; import { TouchableOpacity } from "react-native-ui-lib/src/incubator"; +import { Ionicons } from "@expo/vector-icons"; const FamilyChoresProgress = ({ setPageIndex, @@ -12,7 +13,20 @@ const FamilyChoresProgress = ({ return ( setPageIndex(0)}> - Back to ToDos + + + + Return to To Do's + + diff --git a/components/pages/todos/user-chores/UserChoresProgress.tsx b/components/pages/todos/user-chores/UserChoresProgress.tsx index b4a4fbd..f4cec19 100644 --- a/components/pages/todos/user-chores/UserChoresProgress.tsx +++ b/components/pages/todos/user-chores/UserChoresProgress.tsx @@ -30,8 +30,21 @@ const UserChoresProgress = ({ showsHorizontalScrollIndicator={false} > setPageIndex(0)}> - Back to ToDos - + + + + Return to To Do's + + + Your To Do's Progress Report diff --git a/components/shared/HeaderTemplate.tsx b/components/shared/HeaderTemplate.tsx index b55d97d..3d47487 100644 --- a/components/shared/HeaderTemplate.tsx +++ b/components/shared/HeaderTemplate.tsx @@ -1,18 +1,37 @@ import { Image, Text, View } from "react-native-ui-lib"; -import React from "react"; -import { useAuthContext } from "@/contexts/AuthContext"; +import React, { useEffect, useState } from "react"; +import { ProfileType, useAuthContext } from "@/contexts/AuthContext"; import { StyleSheet } from "react-native"; import { colorMap } from "@/constants/colorMap"; +import { useAtom } from "jotai"; +import { isFamilyViewAtom } from "../pages/calendar/atoms"; +import { useGetChildrenByParentId } from "@/hooks/firebase/useGetChildrenByParentId"; +import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers"; +import { UserProfile } from "@/hooks/firebase/types/profileTypes"; +import { child } from "@react-native-firebase/storage"; +import CachedImage from 'expo-cached-image' const HeaderTemplate = (props: { message: string; isWelcome: boolean; children?: React.ReactNode; link?: React.ReactNode; + isCalendar?: boolean; + isToDos?: boolean; + isBrainDump?: boolean; + isGroceries?: boolean; }) => { const { user, profileData } = useAuthContext(); - const headerHeight: number = 72; + const { data: members } = useGetFamilyMembers(); + const [children, setChildren] = useState([]); + const [isFamilyView] = useAtom(isFamilyViewAtom); + + const headerHeight: number = + (props.isCalendar && 65.54) || + (props.isToDos && 84) || + (props.isGroceries && 72.09) || + 65.54; const styles = StyleSheet.create({ pfp: { @@ -26,14 +45,71 @@ const HeaderTemplate = (props: { pfpTxt: { fontFamily: "Manrope_500Medium", fontSize: 30, - color: 'white', + color: "white", + }, + childrenPfpArr: { + width: 65.54, + position: "absolute", + bottom: -12.44, + left: (children.length > 3 && -9) || 0, + height: 27.32, + }, + childrenPfp: { + aspectRatio: 1, + width: 27.32, + backgroundColor: "#fd1575", + borderRadius: 50, + position: "absolute", + borderWidth: 2, + borderColor: "#f2f2f2", + }, + bottomMarg: { + marginBottom: isFamilyView ? 30 : 15, }, }); + useEffect(() => { + if (members) { + const childrenMembers = members.filter( + (member) => member.userType === ProfileType.CHILD + ); + setChildren(childrenMembers); + } + }, []); + return ( - + {profileData?.pfp ? ( - + + + {isFamilyView && props.isCalendar && ( + + {children?.slice(0, 3).map((child, index) => { + return child.pfp ? ( + + ) : ( + + + {child?.firstName?.at(0)} + {child?.firstName?.at(1)} + + + ); + })} + {children?.length > 3 && ( + + +{children.length - 3} + + )} + + )} + ) : ( diff --git a/components/shared/RemoveAssigneeBtn.tsx b/components/shared/RemoveAssigneeBtn.tsx index 9416009..3384949 100644 --- a/components/shared/RemoveAssigneeBtn.tsx +++ b/components/shared/RemoveAssigneeBtn.tsx @@ -6,7 +6,7 @@ import { View } from "react-native-ui-lib"; const RemoveAssigneeBtn = () => { return ( - + ); }; diff --git a/contexts/AuthContext.tsx b/contexts/AuthContext.tsx index e6f28cc..8483f67 100644 --- a/contexts/AuthContext.tsx +++ b/contexts/AuthContext.tsx @@ -8,7 +8,7 @@ import {UserProfile} from "@/hooks/firebase/types/profileTypes"; import * as Notifications from 'expo-notifications'; import * as Device from 'expo-device'; import Constants from 'expo-constants'; -import { Platform } from 'react-native'; +import {Platform} from 'react-native'; import {useQueryClient} from "react-query"; @@ -24,6 +24,7 @@ interface IAuthContext { profileType?: ProfileType, profileData?: UserProfile, setProfileData: (profileData: UserProfile) => void, + setRedirectOverride: (val: boolean) => void, refreshProfileData: () => Promise } @@ -50,16 +51,16 @@ async function registerForPushNotificationsAsync() { } if (Device.isDevice) { - const { status: existingStatus } = await Notifications.getPermissionsAsync(); + const {status: existingStatus} = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== 'granted') { - const { status } = await Notifications.requestPermissionsAsync(); + const {status} = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== 'granted') { - alert('Failed to get push token for push notification!'); + // alert('Failed to get push token for push notification!'); return; } @@ -72,15 +73,15 @@ async function registerForPushNotificationsAsync() { } try { - const token = (await Notifications.getExpoPushTokenAsync({ projectId })).data; + const token = (await Notifications.getExpoPushTokenAsync({projectId})).data; console.log('Push Token:', token); return token; } catch (error) { - alert(`Error getting push token: ${error}`); + // alert(`Error getting push token: ${error}`); throw error; } } else { - alert('Must use a physical device for push notifications'); + // alert('Must use a physical device for push notifications'); } } @@ -91,24 +92,28 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) => const [initializing, setInitializing] = useState(true); const [profileType, setProfileType] = useState(undefined); const [profileData, setProfileData] = useState(undefined); + const [redirectOverride, setRedirectOverride] = useState(false); + const {replace} = useRouter(); const ready = !initializing; const queryClient = useQueryClient(); const onAuthStateChangedHandler = async (authUser: FirebaseAuthTypes.User | null) => { - setUser(authUser); + if (!redirectOverride) { + setUser(authUser); - if (authUser) { - await refreshProfileData(authUser); - const pushToken = await registerForPushNotificationsAsync(); - if (pushToken) { - await savePushTokenToFirestore(authUser.uid, pushToken); + if (authUser) { + await refreshProfileData(authUser); + const pushToken = await registerForPushNotificationsAsync(); + if (pushToken) { + await savePushTokenToFirestore(authUser.uid, pushToken); + } } - } - if (initializing) setInitializing(false); + if (initializing) setInitializing(false); + } }; const refreshProfileData = async (user?: FirebaseAuthTypes.User) => { @@ -152,12 +157,12 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) => }, [initializing]); useEffect(() => { - if (ready && user) { + if (ready && user && !redirectOverride) { replace({pathname: "/(auth)/calendar"}); - } else if (ready && !user) { + } else if (ready && !user && !redirectOverride) { replace({pathname: "/(unauth)"}); } - }, [user, ready]); + }, [user, ready, redirectOverride]); useEffect(() => { const sub = Notifications.addNotificationReceivedListener(notification => { @@ -175,7 +180,8 @@ export const AuthContextProvider: FC<{ children: ReactNode }> = ({children}) => } return ( - + {children} ); diff --git a/contexts/DumpContext.tsx b/contexts/DumpContext.tsx index f732eb9..8bcefc7 100644 --- a/contexts/DumpContext.tsx +++ b/contexts/DumpContext.tsx @@ -1,5 +1,10 @@ +import { useCreateNote } from "@/hooks/firebase/useCreateNote"; +import { useDeleteNote } from "@/hooks/firebase/useDeleteNote"; +import { useGetNotes } from "@/hooks/firebase/useGetNotes"; +import { useUpdateNote } from "@/hooks/firebase/useUpdateNote"; import { MaterialCommunityIcons } from "@expo/vector-icons"; import { createContext, useContext, useState } from "react"; +import { create } from "react-test-renderer"; export interface IBrainDump { id: number; @@ -8,7 +13,7 @@ export interface IBrainDump { } interface IBrainDumpContext { - brainDumps: IBrainDump[]; + brainDumps: IBrainDump[] | undefined; updateBrainDumpItem: (id: number, changes: Partial) => void; isAddingBrainDump: boolean; setIsAddingBrainDump: (value: boolean) => void; @@ -23,70 +28,43 @@ const BrainDumpContext = createContext( export const BrainDumpProvider: React.FC<{ children: React.ReactNode }> = ({ children, }) => { + const { data: brainDumps } = useGetNotes(); + const { mutate: deleteNote } = useDeleteNote(); + const { mutateAsync: createBrainDump } = useCreateNote(); + const { mutateAsync: updateNoteMutate } = useUpdateNote(); + const [isAddingBrainDump, setIsAddingBrainDump] = useState(false); - const [brainDumps, setBrainDumps] = useState([ - { - id: 0, - title: "Favorite Weekend Activities", - description: - "What's something fun we can do together this weekend? Maybe a new game, a picnic?", - }, - { - id: 1, - title: "What’s For Dinner", - description: - "What’s one meal you’d love to have for dinner this week?", - }, - { - id: 2, - title: "The Best Thing About Today", - description: - "What was the highlight of your day? Let’s each take a moment to share something!", - }, - { - id: 3, - title: "A Dream Vacation Spot", - description: - "If we could go anywhere in the world right now, where would it be? Everyone pick one dream destination and tell us why.", - }, - { - id: 4, - title: "Favorite Childhood Memory", - description: - "What’s a favorite memory from your childhood? Let’s take a trip down memory lane and share some of the moments that made us smile.", - }, - { - id: 5, - title: "A New Family Tradition", - description: - "What’s one new tradition we could start as a family? Maybe a weekly movie night, a monthly game day, or a yearly family trip. Share your ideas!", - }, - ]); const addBrainDump = (BrainDump: IBrainDump) => { - setBrainDumps((prevBrainDumps) => [ - ...prevBrainDumps, - { - ...BrainDump, - id: prevBrainDumps.length - ? prevBrainDumps[prevBrainDumps.length - 1].id + 1 - : 0, - }, - ]); + createBrainDump(BrainDump); }; const updateBrainDumpItem = (id: number, changes: Partial) => { - setBrainDumps((prevBrainDumps) => - prevBrainDumps.map((BrainDump) => - BrainDump.id === id ? { ...BrainDump, ...changes } : BrainDump - ) + updateNoteMutate( + { + id: id, + changes: changes, + }, + { + onSuccess: (data) => { + console.log("Note updated successfully", data); + }, + onError: (error) => { + console.error("Failed to update note:", error); + }, + } ); }; const deleteBrainDump = (id: number) => { - setBrainDumps((prevBrainDumps) => - prevBrainDumps.filter((BrainDump) => BrainDump.id !== id) - ); + deleteNote(id.toString(), { + onSuccess: () => { + console.log("Feedback deleted successfully"); + }, + onError: (error) => { + console.error("Failed to delete feedback:", error); + }, + }); }; return ( @@ -97,7 +75,7 @@ export const BrainDumpProvider: React.FC<{ children: React.ReactNode }> = ({ isAddingBrainDump, setIsAddingBrainDump, addBrainDump, - deleteBrainDump + deleteBrainDump, }} > {children} diff --git a/contexts/FeedbackContext.tsx b/contexts/FeedbackContext.tsx new file mode 100644 index 0000000..4159ea3 --- /dev/null +++ b/contexts/FeedbackContext.tsx @@ -0,0 +1,87 @@ +import { useCreateFeedback } from "@/hooks/firebase/useCreateFeedback"; +import { useDeleteFeedback } from "@/hooks/firebase/useDeleteFeedback"; +import { useGetFeedbacks } from "@/hooks/firebase/useGetFeedbacks"; +import { useUpdateFeedback } from "@/hooks/firebase/useUpdateFeedback"; +import { MaterialCommunityIcons } from "@expo/vector-icons"; +import { createContext, useContext, useState } from "react"; + +export interface IFeedback { + id: number; + title: string; + text: string; +} + +interface IFeedbackContext { + feedbacks: IFeedback[] | undefined; + isAddingFeedback: boolean; + setIsAddingFeedback: (value: boolean) => void; + addFeedback: (BrainDump: IFeedback) => void; + updateFeedback: (id: number, changes: Partial) => void; + deleteFeedback: (id: number) => void; +} + +const FeedbackContext = createContext(undefined); + +export const FeedbackProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const { + mutateAsync: createFeedback, + isLoading: isAdding, + isError, + } = useCreateFeedback(); + const { data: feedbacks } = useGetFeedbacks(); + const { mutate: deleteFeedbackMutate } = useDeleteFeedback(); + const { mutate: updateFeedbackMutate } = useUpdateFeedback(); + + const [isAddingFeedback, setIsAddingFeedback] = useState(false); + + const addFeedback = (Feedback: IFeedback) => { + createFeedback({ title: Feedback.title, text: Feedback.text }); + }; + + const updateFeedback = (id: number, changes: Partial) => { + updateFeedbackMutate( + { + id: id, + changes: changes, + }, + { + onSuccess: (data) => { + console.log("Feedback updated successfully", data); + }, + onError: (error) => { + console.error("Failed to update feedback:", error); + }, + } + ); + }; + + const deleteFeedback = (id: number) => { + deleteFeedbackMutate(id.toString(), { + onSuccess: () => { + console.log("Feedback deleted successfully"); + }, + onError: (error) => { + console.error("Failed to delete feedback:", error); + }, + }); + }; + + return ( + + {children} + + ); +}; + +export const useFeedbackContext = () => useContext(FeedbackContext)!; diff --git a/contexts/ToDosContext.tsx b/contexts/ToDosContext.tsx index 6fadc5e..25ff49f 100644 --- a/contexts/ToDosContext.tsx +++ b/contexts/ToDosContext.tsx @@ -1,8 +1,6 @@ import { createContext, FC, ReactNode, useContext, useState } from "react"; import {IToDo} from "@/hooks/firebase/types/todoData"; -import {useGetGroceries} from "@/hooks/firebase/useGetGroceries"; import {useGetTodos} from "@/hooks/firebase/useGetTodos"; -import {useCreateGrocery} from "@/hooks/firebase/useCreateGrocery"; import {useCreateTodo} from "@/hooks/firebase/useCreateTodo"; import {useUpdateTodo} from "@/hooks/firebase/useUpdateTodo"; diff --git a/firebase/functions/index.js b/firebase/functions/index.js index 475f6d8..704507b 100644 --- a/firebase/functions/index.js +++ b/firebase/functions/index.js @@ -18,49 +18,50 @@ exports.sendNotificationOnEventCreation = functions.firestore .document('Events/{eventId}') .onCreate(async (snapshot, context) => { const eventData = snapshot.data(); - const {familyId, creatorId} = eventData; + const { familyId, creatorId, email } = eventData; + + if (email) { + console.log('Event has an email field. Skipping notification.'); + return; + } if (!familyId || !creatorId) { console.error('Missing familyId or creatorId in event data'); return; } + let pushTokens = await getPushTokensForFamilyExcludingCreator(familyId, creatorId); + if (!pushTokens.length) { - pushTokens = await getPushTokensForFamilyExcludingCreator(familyId, creatorId); - if (!pushTokens.length) { - console.log('No push tokens available for the event.'); - return; - } + console.log('No push tokens available for the event.'); + return; } - // Increment event count for debouncing eventCount++; if (notificationTimeout) { - clearTimeout(notificationTimeout); // Reset the timer if events keep coming + clearTimeout(notificationTimeout); } - // Set a debounce time (e.g., 5 seconds) notificationTimeout = setTimeout(async () => { const eventMessage = eventCount === 1 ? `An event "${eventData.title}" has been added. Check it out!` : `${eventCount} new events have been added.`; - let messages = []; - for (let pushToken of pushTokens) { + let messages = pushTokens.map(pushToken => { if (!Expo.isExpoPushToken(pushToken)) { console.error(`Push token ${pushToken} is not a valid Expo push token`); - continue; + return null; } - messages.push({ + return { to: pushToken, sound: 'default', title: 'New Events Added!', body: eventMessage, - data: {eventId: context.params.eventId}, - }); - } + data: { eventId: context.params.eventId }, + }; + }).filter(Boolean); let chunks = expo.chunkPushNotifications(messages); let tickets = []; @@ -75,7 +76,7 @@ exports.sendNotificationOnEventCreation = functions.firestore console.log('Notification successfully sent:', ticket.id); } else if (ticket.status === 'error') { console.error(`Notification error: ${ticket.message}`); - if (ticket.details && ticket.details.error === 'DeviceNotRegistered') { + if (ticket.details?.error === 'DeviceNotRegistered') { await removeInvalidPushToken(ticket.to); } } @@ -85,10 +86,10 @@ exports.sendNotificationOnEventCreation = functions.firestore } } - eventCount = 0; // Reset the event count after sending notification - pushTokens = []; // Reset push tokens for the next round + eventCount = 0; + pushTokens = []; - }, 5000); // Debounce time (5 seconds) + }, 5000); }); @@ -180,7 +181,7 @@ exports.generateCustomToken = onRequest(async (request, response) => { } }); -exports.refreshTokens = functions.pubsub.schedule('every 12 hours').onRun(async (context) => { +exports.refreshTokens = functions.pubsub.schedule('every 1 hours').onRun(async (context) => { console.log('Running token refresh job...'); const profilesSnapshot = await db.collection('Profiles').get(); @@ -191,7 +192,7 @@ exports.refreshTokens = functions.pubsub.schedule('every 12 hours').onRun(async if (profileData.googleAccounts) { try { for (const googleEmail of Object.keys(profileData?.googleAccounts)) { - const googleToken = profileData?.googleAccounts?.[googleEmail]; + const googleToken = profileData?.googleAccounts?.[googleEmail]?.refreshToken; if (googleToken) { const refreshedGoogleToken = await refreshGoogleToken(googleToken); const updatedGoogleAccounts = {...profileData.googleAccounts, [googleEmail]: refreshedGoogleToken}; @@ -238,29 +239,35 @@ exports.refreshTokens = functions.pubsub.schedule('every 12 hours').onRun(async return null; }); -// Function to refresh Google token -async function refreshGoogleToken(token) { - // Assuming you use OAuth2 token refresh flow - const response = await axios.post('https://oauth2.googleapis.com/token', { - grant_type: 'refresh_token', - refresh_token: token, // Add refresh token stored previously - client_id: 'YOUR_GOOGLE_CLIENT_ID', - client_secret: 'YOUR_GOOGLE_CLIENT_SECRET', - }); +async function refreshGoogleToken(refreshToken) { + try { + const response = await axios.post('https://oauth2.googleapis.com/token', { + grant_type: 'refresh_token', + refresh_token: refreshToken, + client_id: "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com", // Web client ID from googleConfig + }); - return response.data.access_token; // Return new access token + return response.data.access_token; // Return the new access token + } catch (error) { + console.error("Error refreshing Google token:", error); + throw error; + } } -async function refreshMicrosoftToken(token) { - const response = await axios.post('https://login.microsoftonline.com/common/oauth2/v2.0/token', { - grant_type: 'refresh_token', - refresh_token: token, // Add refresh token stored previously - client_id: 'YOUR_MICROSOFT_CLIENT_ID', - client_secret: 'YOUR_MICROSOFT_CLIENT_SECRET', - scope: 'https://graph.microsoft.com/Calendars.ReadWrite offline_access', - }); +async function refreshMicrosoftToken(refreshToken) { + try { + const response = await axios.post('https://login.microsoftonline.com/common/oauth2/v2.0/token', { + grant_type: 'refresh_token', + refresh_token: refreshToken, + client_id: "13c79071-1066-40a9-9f71-b8c4b138b4af", // Client ID from microsoftConfig + scope: "openid profile email offline_access Calendars.ReadWrite User.Read", // Scope from microsoftConfig + }); - return response.data.access_token; // Return new access token + return response.data.access_token; // Return the new access token + } catch (error) { + console.error("Error refreshing Microsoft token:", error); + throw error; + } } async function getPushTokensForEvent() { diff --git a/firebase/functions/yarn.lock b/firebase/functions/yarn.lock new file mode 100644 index 0000000..c102e08 --- /dev/null +++ b/firebase/functions/yarn.lock @@ -0,0 +1,2353 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@fastify/busboy@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-3.0.0.tgz#328a4639cdd9282c1d1f56aa84943f153df8839d" + integrity sha512-83rnH2nCvclWaPQQKvkJ2pdOjG4TZyEVuFDnlOF6KP08lDaaceVyw/W63mDuafQT+MKHCvXIPpE5uYWeM0rT4w== + +"@firebase/app-check-interop-types@0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.2.tgz#455b6562c7a3de3ef75ea51f72dfec5829ad6997" + integrity sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ== + +"@firebase/app-types@0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.2.tgz#8cbcceba784753a7c0066a4809bc22f93adee080" + integrity sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ== + +"@firebase/auth-interop-types@0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz#927f1f2139a680b55fef0bddbff2c982b08587e8" + integrity sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ== + +"@firebase/component@0.6.9": + version "0.6.9" + resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.6.9.tgz#4248cfeab222245ada0d7f78ece95a87574532b4" + integrity sha512-gm8EUEJE/fEac86AvHn8Z/QW8BvR56TBw3hMW0O838J/1mThYQXAIQBgUv75EqlCZfdawpWLrKt1uXvp9ciK3Q== + dependencies: + "@firebase/util" "1.10.0" + tslib "^2.1.0" + +"@firebase/database-compat@^1.0.2": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-1.0.8.tgz#69ab03d00e27a89f65486896ea219094aa38c27f" + integrity sha512-OpeWZoPE3sGIRPBKYnW9wLad25RaWbGyk7fFQe4xnJQKRzlynWeFBSRRAoLE2Old01WXwskUiucNqUUVlFsceg== + dependencies: + "@firebase/component" "0.6.9" + "@firebase/database" "1.0.8" + "@firebase/database-types" "1.0.5" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.10.0" + tslib "^2.1.0" + +"@firebase/database-types@1.0.5", "@firebase/database-types@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.5.tgz#2d923f42e3d9911b9eec537ed8b5ecaa0ce95c37" + integrity sha512-fTlqCNwFYyq/C6W7AJ5OCuq5CeZuBEsEwptnVxlNPkWCo5cTTyukzAHRSO/jaQcItz33FfYrrFk1SJofcu2AaQ== + dependencies: + "@firebase/app-types" "0.9.2" + "@firebase/util" "1.10.0" + +"@firebase/database@1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.0.8.tgz#01bb0d0cb5653ae6a6641523f6f085b4c1be9c2f" + integrity sha512-dzXALZeBI1U5TXt6619cv0+tgEhJiwlUtQ55WNZY7vGAjv7Q1QioV969iYwt1AQQ0ovHnEW0YW9TiBfefLvErg== + dependencies: + "@firebase/app-check-interop-types" "0.3.2" + "@firebase/auth-interop-types" "0.2.3" + "@firebase/component" "0.6.9" + "@firebase/logger" "0.4.2" + "@firebase/util" "1.10.0" + faye-websocket "0.11.4" + tslib "^2.1.0" + +"@firebase/logger@0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.4.2.tgz#74dfcfeedee810deb8a7080d5b7eba56aa16ffa2" + integrity sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A== + dependencies: + tslib "^2.1.0" + +"@firebase/util@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.10.0.tgz#9ec8ab54da82bfc31baff0c43cb281998cbeddab" + integrity sha512-xKtx4A668icQqoANRxyDLBLz51TAbDP9KRfpbKGxiCAW346d0BeJe5vN6/hKxxmWwnZ0mautyv39JxviwwQMOQ== + dependencies: + tslib "^2.1.0" + +"@google-cloud/firestore@^7.7.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@google-cloud/firestore/-/firestore-7.10.0.tgz#fc434f6da583aba48d5532ce322e8c03af1978f8" + integrity sha512-VFNhdHvfnmqcHHs6YhmSNHHxQqaaD64GwiL0c+e1qz85S8SWZPC2XFRf8p9yHRTF40Kow424s1KBU9f0fdQa+Q== + dependencies: + "@opentelemetry/api" "^1.3.0" + fast-deep-equal "^3.1.1" + functional-red-black-tree "^1.0.1" + google-gax "^4.3.3" + protobufjs "^7.2.6" + +"@google-cloud/paginator@^5.0.0": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-5.0.2.tgz#86ad773266ce9f3b82955a8f75e22cd012ccc889" + integrity sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg== + dependencies: + arrify "^2.0.0" + extend "^3.0.2" + +"@google-cloud/projectify@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-4.0.0.tgz#d600e0433daf51b88c1fa95ac7f02e38e80a07be" + integrity sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA== + +"@google-cloud/promisify@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-4.0.0.tgz#a906e533ebdd0f754dca2509933334ce58b8c8b1" + integrity sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g== + +"@google-cloud/storage@^7.7.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-7.13.0.tgz#b59a495861fe7c48f78c1b482b9404f07aa60e66" + integrity sha512-Y0rYdwM5ZPW3jw/T26sMxxfPrVQTKm9vGrZG8PRyGuUmUJ8a2xNuQ9W/NNA1prxqv2i54DSydV8SJqxF2oCVgA== + dependencies: + "@google-cloud/paginator" "^5.0.0" + "@google-cloud/projectify" "^4.0.0" + "@google-cloud/promisify" "^4.0.0" + abort-controller "^3.0.0" + async-retry "^1.3.3" + duplexify "^4.1.3" + fast-xml-parser "^4.4.1" + gaxios "^6.0.2" + google-auth-library "^9.6.3" + html-entities "^2.5.2" + mime "^3.0.0" + p-limit "^3.0.1" + retry-request "^7.0.0" + teeny-request "^9.0.0" + uuid "^8.0.0" + +"@grpc/grpc-js@^1.10.9": + version "1.12.2" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.12.2.tgz#97eda82dd49bb9c24eaf6434ea8d7de446e95aac" + integrity sha512-bgxdZmgTrJZX50OjyVwz3+mNEnCTNkh3cIqGPWVNeW9jX6bn1ZkU80uPd+67/ZpIJIjRQ9qaHCjhavyoWYxumg== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@opentelemetry/api@^1.3.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" + integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/caseless@*": + version "0.12.5" + resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.5.tgz#db9468cb1b1b5a925b8f34822f1669df0c5472f5" + integrity sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg== + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/cors@^2.8.5": + version "2.8.17" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz#91f06cda1049e8f17eeab364798ed79c97488a1c" + integrity sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express-serve-static-core@^4.17.33": + version "4.19.6" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267" + integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@4.17.3": + version "4.17.3" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.3.tgz#38e4458ce2067873b09a73908df488870c303bd9" + integrity sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/serve-static" "*" + +"@types/express@^4.17.17": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/jsonwebtoken@^9.0.2": + version "9.0.7" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz#e49b96c2b29356ed462e9708fc73b833014727d2" + integrity sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg== + dependencies: + "@types/node" "*" + +"@types/lodash@^4.14.104": + version "4.17.10" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.10.tgz#64f3edf656af2fe59e7278b73d3e62404144a6e6" + integrity sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ== + +"@types/long@^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/node@*", "@types/node@>=13.7.0", "@types/node@^22.0.1": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + +"@types/qs@*": + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/request@^2.48.8": + version "2.48.12" + resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.12.tgz#0f590f615a10f87da18e9790ac94c29ec4c5ef30" + integrity sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw== + dependencies: + "@types/caseless" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + form-data "^2.5.0" + +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + +"@typescript-eslint/eslint-plugin@^8.7.0": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" + integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/type-utils" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/scope-manager@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" + integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + +"@typescript-eslint/type-utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" + integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== + dependencies: + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" + integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== + +"@typescript-eslint/typescript-estree@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" + integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" + integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + +"@typescript-eslint/visitor-keys@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" + integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== + dependencies: + "@typescript-eslint/types" "8.8.1" + eslint-visitor-keys "^3.4.3" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +agent-base@^7.0.2: + version "7.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +arrify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bignumber.js@^9.0.0: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +duplexify@^4.0.0, duplexify@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.3.tgz#a07e1c0d0a2c001158563d32592ba58bddb0236f" + integrity sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.2" + +ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-google@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.14.0.tgz#4f5f8759ba6e11b424294a219dbfa18c508bcc1a" + integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw== + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.57.1: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +expo-server-sdk@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/expo-server-sdk/-/expo-server-sdk-3.11.0.tgz#80bc16e2ec103a1235e856adf0d2ae358f7f5ddc" + integrity sha512-EGH82ZcdAFjKq+6daDE8Xj7BjaSeP1VDvZ3Hmtn/KzEQ3ffqHkauMsgXL2wLEPlvatLq3EsYNcejXRBV54WnFQ== + dependencies: + node-fetch "^2.6.0" + promise-limit "^2.7.0" + promise-retry "^2.0.1" + +express@^4.17.1: + version "4.21.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281" + integrity sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.7.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.10" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +farmhash-modern@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/farmhash-modern/-/farmhash-modern-1.1.0.tgz#c36b34ad196290d57b0b482dc89e637d0b59835f" + integrity sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-xml-parser@^4.4.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz#2882b7d01a6825dfdf909638f2de0256351def37" + integrity sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg== + dependencies: + strnum "^1.0.5" + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +faye-websocket@0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== + dependencies: + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +firebase-admin@^12.1.0: + version "12.6.0" + resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-12.6.0.tgz#495bfa30a4484d1af6390bb3481fdf911bca530e" + integrity sha512-gc0pDiUmxscxBhcjMcttmjvExJmnQdVRb+IIth95CvMm7F9rLdabrQZThW2mK02HR696P+rzd6NqkdUA3URu4w== + dependencies: + "@fastify/busboy" "^3.0.0" + "@firebase/database-compat" "^1.0.2" + "@firebase/database-types" "^1.0.0" + "@types/node" "^22.0.1" + farmhash-modern "^1.1.0" + jsonwebtoken "^9.0.0" + jwks-rsa "^3.1.0" + node-forge "^1.3.1" + uuid "^10.0.0" + optionalDependencies: + "@google-cloud/firestore" "^7.7.0" + "@google-cloud/storage" "^7.7.0" + +firebase-functions-test@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/firebase-functions-test/-/firebase-functions-test-3.3.0.tgz#63566f0ea71d9fd0651c756b29a8b50ec5f408d8" + integrity sha512-X+OOA34MGrsTimFXTDnWT0psAqnmBkJ85bGCoLMwjgei5Prfkqh3bv5QASnXC/cmIVBSF2Qw9uW1+mF/t3kFlw== + dependencies: + "@types/lodash" "^4.14.104" + lodash "^4.17.5" + ts-deepmerge "^2.0.1" + +firebase-functions@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/firebase-functions/-/firebase-functions-5.1.1.tgz#15c668d072d4000d6a348aabb7ab4acdbd2442f8" + integrity sha512-KkyKZE98Leg/C73oRyuUYox04PQeeBThdygMfeX+7t1cmKWYKa/ZieYa89U8GHgED+0mF7m7wfNZOfbURYxIKg== + dependencies: + "@types/cors" "^2.8.5" + "@types/express" "4.17.3" + cors "^2.8.5" + express "^4.17.1" + protobufjs "^7.2.2" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +form-data@^2.5.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.2.tgz#dc653743d1de2fcc340ceea38079daf6e9069fd2" + integrity sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + safe-buffer "^5.2.1" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +gaxios@^6.0.0, gaxios@^6.0.2, gaxios@^6.1.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-6.7.1.tgz#ebd9f7093ede3ba502685e73390248bb5b7f71fb" + integrity sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ== + dependencies: + extend "^3.0.2" + https-proxy-agent "^7.0.1" + is-stream "^2.0.0" + node-fetch "^2.6.9" + uuid "^9.0.1" + +gcp-metadata@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-6.1.0.tgz#9b0dd2b2445258e7597f2024332d20611cbd6b8c" + integrity sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg== + dependencies: + gaxios "^6.0.0" + json-bigint "^1.0.0" + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +google-auth-library@^9.3.0, google-auth-library@^9.6.3: + version "9.14.2" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.14.2.tgz#92a53ba32b3a9ff9ced8ed34129edb5a7fa7fb52" + integrity sha512-R+FRIfk1GBo3RdlRYWPdwk8nmtVUOn6+BkDomAC46KoU8kzXzE1HLmOasSCbWUByMMAGkknVF0G5kQ69Vj7dlA== + dependencies: + base64-js "^1.3.0" + ecdsa-sig-formatter "^1.0.11" + gaxios "^6.1.1" + gcp-metadata "^6.1.0" + gtoken "^7.0.0" + jws "^4.0.0" + +google-gax@^4.3.3: + version "4.4.1" + resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-4.4.1.tgz#95a9cf7ee7777ac22d1926a45b5f886dd8beecae" + integrity sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg== + dependencies: + "@grpc/grpc-js" "^1.10.9" + "@grpc/proto-loader" "^0.7.13" + "@types/long" "^4.0.0" + abort-controller "^3.0.0" + duplexify "^4.0.0" + google-auth-library "^9.3.0" + node-fetch "^2.7.0" + object-hash "^3.0.0" + proto3-json-serializer "^2.0.2" + protobufjs "^7.3.2" + retry-request "^7.0.0" + uuid "^9.0.1" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +gtoken@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-7.1.0.tgz#d61b4ebd10132222817f7222b1e6064bd463fc26" + integrity sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw== + dependencies: + gaxios "^6.0.0" + jws "^4.0.0" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +html-entities@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" + integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +https-proxy-agent@^7.0.1: + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== + dependencies: + agent-base "^7.0.2" + debug "4" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jose@^4.14.6: + version "4.15.9" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.9.tgz#9b68eda29e9a0614c042fa29387196c7dd800100" + integrity sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +jsonwebtoken@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jwa@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc" + integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jwks-rsa@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jwks-rsa/-/jwks-rsa-3.1.0.tgz#50406f23e38c9b2682cd437f824d7d61aa983171" + integrity sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg== + dependencies: + "@types/express" "^4.17.17" + "@types/jsonwebtoken" "^9.0.2" + debug "^4.3.4" + jose "^4.14.6" + limiter "^1.1.5" + lru-memoizer "^2.2.0" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +jws@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" + integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg== + dependencies: + jwa "^2.0.0" + safe-buffer "^5.0.1" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +limiter@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2" + integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash@^4.17.5: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +long@^5.0.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + +lru-cache@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru-memoizer@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.3.0.tgz#ef0fbc021bceb666794b145eefac6be49dc47f31" + integrity sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug== + dependencies: + lodash.clonedeep "^4.5.0" + lru-cache "6.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +node-fetch@^2.6.0, node-fetch@^2.6.9, node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-forge@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.1, p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +promise-limit@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/promise-limit/-/promise-limit-2.7.0.tgz#eb5737c33342a030eaeaecea9b3d3a93cb592b26" + integrity sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw== + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +proto3-json-serializer@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz#5b705203b4d58f3880596c95fad64902617529dd" + integrity sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ== + dependencies: + protobufjs "^7.2.5" + +protobufjs@^7.2.2, protobufjs@^7.2.5, protobufjs@^7.2.6, protobufjs@^7.3.2: + version "7.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^3.1.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +retry-request@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-7.0.2.tgz#60bf48cfb424ec01b03fca6665dee91d06dd95f3" + integrity sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w== + dependencies: + "@types/request" "^2.48.8" + extend "^3.0.2" + teeny-request "^9.0.0" + +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^7.5.4, semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +stream-events@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" + integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== + dependencies: + stubs "^3.0.0" + +stream-shift@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" + integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + +stubs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" + integrity sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +teeny-request@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-9.0.0.tgz#18140de2eb6595771b1b02203312dfad79a4716d" + integrity sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g== + dependencies: + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.0" + node-fetch "^2.6.9" + stream-events "^1.0.5" + uuid "^9.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +ts-deepmerge@^2.0.1: + version "2.0.7" + resolved "https://registry.yarnpkg.com/ts-deepmerge/-/ts-deepmerge-2.0.7.tgz#36786a9a10b5f3a6f5154007cf17bfba7251e0a7" + integrity sha512-3phiGcxPSSR47RBubQxPoZ+pqXsEsozLo4G4AlSrsMKTFg9TA3l+3he5BqpUi9wiuDbaHWXH/amlzQ49uEdXtg== + +tslib@^2.1.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + +uuid@^8.0.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^9.0.0, uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +websocket-driver@>=0.5.1: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/hooks/firebase/types/todoData.ts b/hooks/firebase/types/todoData.ts index e71d79f..32542c0 100644 --- a/hooks/firebase/types/todoData.ts +++ b/hooks/firebase/types/todoData.ts @@ -11,4 +11,22 @@ export interface IToDo { creatorId?: string; familyId?: string; assignees?: string[]; // Optional list of assignees + connectedTodoId?: string; } + +export const DAYS_OF_WEEK_ENUM = { + MONDAY: "Monday", + TUESDAY: "Tuesday", + WEDNESDAY: "Wednesday", + THURSDAY: "Thursday", + FRIDAY: "Friday", + SATURDAY: "Saturday", + SUNDAY: "Sunday" +} + +export const REPEAT_TYPE = { + NONE: "None", + EVERY_WEEK: "Every week", + ONCE_A_MONTH: "Once a month", + ONCE_A_YEAR: "Once a year" +} \ No newline at end of file diff --git a/hooks/firebase/useChangeProfilePicture.ts b/hooks/firebase/useChangeProfilePicture.ts index 4f0b97e..6dff508 100644 --- a/hooks/firebase/useChangeProfilePicture.ts +++ b/hooks/firebase/useChangeProfilePicture.ts @@ -1,13 +1,13 @@ -import { useMutation, useQueryClient } from "react-query"; +import {useMutation, useQueryClient} from "react-query"; import firestore from "@react-native-firebase/firestore"; import storage from "@react-native-firebase/storage"; -import { useAuthContext } from "@/contexts/AuthContext"; +import {useAuthContext} from "@/contexts/AuthContext"; import * as ImagePicker from "expo-image-picker"; -import { Platform } from "react-native"; +import {Platform} from "react-native"; -export const useChangeProfilePicture = () => { +export const useChangeProfilePicture = (customUserId?: string) => { const queryClient = useQueryClient(); - const { user, refreshProfileData } = useAuthContext(); + const {user, refreshProfileData} = useAuthContext(); return useMutation({ mutationKey: ["changeProfilePicture"], @@ -38,20 +38,24 @@ export const useChangeProfilePicture = () => { const downloadURL = await reference.getDownloadURL(); console.log("Download URL:", downloadURL); + if(!customUserId) { await firestore() .collection("Profiles") .doc(user?.uid) - .update({ pfp: downloadURL }); + .update({pfp: downloadURL}); + } } catch (e) { - console.error("Error uploading profile picture:", e.message); + console.error("Error uploading profile picture:", e); throw e; } }, onSuccess: () => { // Invalidate queries to refresh profile data - queryClient.invalidateQueries("Profiles"); - refreshProfileData(); + if (!customUserId) { + queryClient.invalidateQueries("Profiles"); + refreshProfileData(); + } }, }); }; \ No newline at end of file diff --git a/hooks/firebase/useClearTokens.ts b/hooks/firebase/useClearTokens.ts new file mode 100644 index 0000000..35fd305 --- /dev/null +++ b/hooks/firebase/useClearTokens.ts @@ -0,0 +1,39 @@ +import {useMutation} from "react-query"; +import {UserProfile} from "@firebase/auth"; +import {useAuthContext} from "@/contexts/AuthContext"; +import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData"; + +export const useClearTokens = () => { + const {profileData} = useAuthContext(); + const {mutateAsync: updateUserData} = useUpdateUserData(); + + return useMutation({ + mutationKey: ["clearTokens"], + mutationFn: async ({provider, email}: { + provider: "google" | "outlook" | "apple", + email: string + }) => { + const newUserData: Partial = {}; + if (provider === "google") { + let googleAccounts = profileData?.googleAccounts; + if (googleAccounts) { + googleAccounts[email] = null; + newUserData.googleAccounts = googleAccounts; + } + } else if (provider === "outlook") { + let microsoftAccounts = profileData?.microsoftAccounts; + if (microsoftAccounts) { + microsoftAccounts[email] = null; + newUserData.microsoftAccounts = microsoftAccounts; + } + } else if (provider === "apple") { + let appleAccounts = profileData?.appleAccounts; + if (appleAccounts) { + appleAccounts[email] = null; + newUserData.appleAccounts = appleAccounts; + } + } + await updateUserData({newUserData}); + }, + }) +} \ No newline at end of file diff --git a/hooks/firebase/useCreateEvent.ts b/hooks/firebase/useCreateEvent.ts index 4aecf1e..2b56346 100644 --- a/hooks/firebase/useCreateEvent.ts +++ b/hooks/firebase/useCreateEvent.ts @@ -30,9 +30,10 @@ export const useCreateEvent = () => { return; } } + const newDoc = firestore().collection('Events').doc(); await firestore() .collection("Events") - .add({...eventData, creatorId: currentUser?.uid, familyId: profileData?.familyId}); + .add({...eventData, id: newDoc.id, creatorId: currentUser?.uid, familyId: profileData?.familyId}); } catch (e) { console.error(e); } @@ -44,34 +45,41 @@ export const useCreateEvent = () => { } export const useCreateEventsFromProvider = () => { - const {user: currentUser} = useAuthContext(); + const { user: currentUser } = useAuthContext(); const queryClient = useQueryClient(); return useMutation({ mutationKey: ["createEventsFromProvider"], mutationFn: async (eventDataArray: Partial[]) => { try { - for (const eventData of eventDataArray) { + // Create an array of promises for each event's Firestore read/write operation + const promises = eventDataArray.map(async (eventData) => { console.log("Processing EventData: ", eventData); + // Check if the event already exists const snapshot = await firestore() .collection("Events") .where("id", "==", eventData.id) .get(); if (snapshot.empty) { - await firestore() + // Event doesn't exist, so add it + return firestore() .collection("Events") - .add({...eventData, creatorId: currentUser?.uid}); + .add({ ...eventData, creatorId: currentUser?.uid }); } else { - console.log("Event already exists, updating..."); + // Event exists, update it const docId = snapshot.docs[0].id; - await firestore() + return firestore() .collection("Events") .doc(docId) - .set({...eventData, creatorId: currentUser?.uid}, {merge: true}); + .set({ ...eventData, creatorId: currentUser?.uid }, { merge: true }); } - } + }); + + // Execute all promises in parallel + await Promise.all(promises); + } catch (e) { console.error("Error creating/updating events: ", e); } diff --git a/hooks/firebase/useCreateFeedback.ts b/hooks/firebase/useCreateFeedback.ts new file mode 100644 index 0000000..849afe1 --- /dev/null +++ b/hooks/firebase/useCreateFeedback.ts @@ -0,0 +1,85 @@ +import {useAuthContext} from "@/contexts/AuthContext"; +import {useMutation, useQueryClient} from "react-query"; +import firestore from "@react-native-firebase/firestore"; +import { IFeedback } from "@/contexts/FeedbackContext"; + +export const useCreateFeedback = () => { + const {user: currentUser, profileData} = useAuthContext() + const queryClients = useQueryClient() + + return useMutation({ + mutationKey: ["createFeedback"], + mutationFn: async (feedback: Partial) => { + try { + if (feedback.id) { + const snapshot = await firestore() + .collection("Feedbacks") + .where("id", "==", feedback.id) + .get(); + + if (!snapshot.empty) { + const docId = snapshot.docs[0].id; + await firestore() + .collection("Feedbacks") + .doc(docId) + .set({ + ...feedback, + creatorId: currentUser?.uid, + }, {merge: true}); + return; + } + } + const newDoc = firestore().collection('Feedbacks').doc(); + await firestore() + .collection("Feedbacks") + .add({...feedback, id: newDoc.id, creatorId: currentUser?.uid}); + } catch (e) { + console.error(e); + } + }, + onSuccess: () => { + queryClients.invalidateQueries("feedbacks") + } + }) +} + +export const useCreateFeedbacksFromProvider = () => { + const { user: currentUser } = useAuthContext(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ["createFeedbacksFromProvider"], + mutationFn: async (feedbackDataArray: Partial[]) => { + try { + const promises = feedbackDataArray.map(async (feedbackData) => { + console.log("Processing FeedbackData: ", feedbackData); + + const snapshot = await firestore() + .collection("Feedbacks") + .where("id", "==", feedbackData.id) + .get(); + + if (snapshot.empty) { + return firestore() + .collection("Feedbacks") + .add({ ...feedbackData, creatorId: currentUser?.uid }); + } else { + const docId = snapshot.docs[0].id; + return firestore() + .collection("Feedbacks") + .doc(docId) + .set({ ...feedbackData, creatorId: currentUser?.uid }, { merge: true }); + } + }); + + await Promise.all(promises); + + } catch (e) { + console.error("Error creating/updating feedbacks: ", e); + } + }, + onSuccess: () => { + queryClient.invalidateQueries("feedbacks"); + } + }); +}; \ No newline at end of file diff --git a/hooks/firebase/useCreateNote.ts b/hooks/firebase/useCreateNote.ts new file mode 100644 index 0000000..417e959 --- /dev/null +++ b/hooks/firebase/useCreateNote.ts @@ -0,0 +1,91 @@ +import { useAuthContext } from "@/contexts/AuthContext"; +import { useMutation, useQueryClient } from "react-query"; +import firestore from "@react-native-firebase/firestore"; +import { IFeedback } from "@/contexts/FeedbackContext"; +import { IBrainDump } from "@/contexts/DumpContext"; + +export const useCreateNote = () => { + const { user: currentUser, profileData } = useAuthContext(); + const queryClients = useQueryClient(); + + return useMutation({ + mutationKey: ["createNote"], + mutationFn: async (note: Partial) => { + try { + if (note.id) { + const snapshot = await firestore() + .collection("BrainDumps") + .where("id", "==", note.id) + .get(); + + if (!snapshot.empty) { + const docId = snapshot.docs[0].id; + await firestore() + .collection("BrainDumps") + .doc(docId) + .set( + { + ...note, + creatorId: currentUser?.uid, + }, + { merge: true } + ); + return; + } + } + const newDoc = firestore().collection("BrainDumps").doc(); + await firestore() + .collection("BrainDumps") + .add({ ...note, id: newDoc.id, creatorId: currentUser?.uid }); + } catch (e) { + console.error(e); + } + }, + onSuccess: () => { + queryClients.invalidateQueries("braindumps"); + }, + }); +}; + +export const useCreateNotesFromProvider = () => { + const { user: currentUser } = useAuthContext(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ["createNotesFromProvider"], + mutationFn: async (noteDataArray: Partial[]) => { + try { + const promises = noteDataArray.map(async (noteData) => { + console.log("Processing NoteData: ", noteData); + + const snapshot = await firestore() + .collection("BrainDumps") + .where("id", "==", noteData.id) + .get(); + + if (snapshot.empty) { + return firestore() + .collection("BrainDumps") + .add({ ...noteData, creatorId: currentUser?.uid }); + } else { + const docId = snapshot.docs[0].id; + return firestore() + .collection("BrainDumps") + .doc(docId) + .set( + { ...noteData, creatorId: currentUser?.uid }, + { merge: true } + ); + } + }); + + await Promise.all(promises); + } catch (e) { + console.error("Error creating/updating braindumps: ", e); + } + }, + onSuccess: () => { + queryClient.invalidateQueries("braindumps"); + }, + }); +}; diff --git a/hooks/firebase/useCreateSubUser.ts b/hooks/firebase/useCreateSubUser.ts index 84c5408..3418bb8 100644 --- a/hooks/firebase/useCreateSubUser.ts +++ b/hooks/firebase/useCreateSubUser.ts @@ -15,7 +15,7 @@ export const useCreateSubUser = () => { return await functions().httpsCallable("createSubUser")({ ...userProfile, email, - familyId: profileData?.familyId + familyId: profileData?.familyId! }) as HttpsCallableResult<{ userId: string }> } else { throw Error("Can't create sub-users as a non-parent.") diff --git a/hooks/firebase/useCreateTodo.ts b/hooks/firebase/useCreateTodo.ts index d065fc5..06e4979 100644 --- a/hooks/firebase/useCreateTodo.ts +++ b/hooks/firebase/useCreateTodo.ts @@ -1,7 +1,17 @@ -import { useMutation, useQueryClient } from "react-query"; +import {useMutation, useQueryClient} from "react-query"; import firestore from "@react-native-firebase/firestore"; -import { useAuthContext } from "@/contexts/AuthContext"; -import { IToDo } from "@/hooks/firebase/types/todoData"; +import {useAuthContext} from "@/contexts/AuthContext"; +import {DAYS_OF_WEEK_ENUM, IToDo, REPEAT_TYPE} from "@/hooks/firebase/types/todoData"; +import {addDays, addMonths, addWeeks, addYears, compareAsc, format, subDays} from "date-fns"; + +export const daysOfWeek = [ + DAYS_OF_WEEK_ENUM.MONDAY, + DAYS_OF_WEEK_ENUM.TUESDAY, + DAYS_OF_WEEK_ENUM.WEDNESDAY, + DAYS_OF_WEEK_ENUM.THURSDAY, + DAYS_OF_WEEK_ENUM.FRIDAY, + DAYS_OF_WEEK_ENUM.SATURDAY, + DAYS_OF_WEEK_ENUM.SUNDAY]; export const useCreateTodo = () => { const { user: currentUser, profileData } = useAuthContext(); @@ -11,10 +21,92 @@ export const useCreateTodo = () => { mutationKey: ["createTodo"], mutationFn: async (todoData: Partial) => { try { - const newDoc = firestore().collection('Todos').doc(); - await firestore() - .collection("Todos") - .add({...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid}) + if (todoData.repeatType === REPEAT_TYPE.NONE) { + const newDoc = firestore().collection('Todos').doc(); + let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid} + await firestore() + .collection("Todos") + .add(originalTodo); + } else { + // Create the one original to do + const newDoc = firestore().collection('Todos').doc(); + let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid, connectedTodoId: newDoc.id}; + + originalTodo = resolveTodoAlternatingAssignees(todoData, originalTodo, 0); + + await firestore() + .collection("Todos") + .add(originalTodo); + + const batch = firestore().batch(); + + if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) { + + let date = originalTodo.date; + let repeatDays = originalTodo.repeatDays; + const dates = []; + + const originalDateDay = format(date, 'EEEE'); + const originalNumber = daysOfWeek.indexOf(originalDateDay); + repeatDays?.forEach((day) => { + let number = daysOfWeek.indexOf(day); + let newDate; + if (originalNumber > number) { + let diff = originalNumber - number; + newDate = subDays(date, diff); + } else { + let diff = number - originalNumber; + newDate = addDays(date, diff); + } + dates.push(newDate); + }); + + // TODO: for the next 52 weeks + let index = 1; + for (let i = 0; i < 4; i++) { + dates?.forEach((dateToAdd) => { + index ++; + let newTodoDate = addWeeks(dateToAdd, i); + if (compareAsc(newTodoDate, originalTodo.date) !== 0) { + + let docRef = firestore().collection("Todos").doc(); + let newTodo = { ...originalTodo, id: docRef.id, date: newTodoDate, connectedTodoId: newDoc.id }; + newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, index); + + batch.set(docRef, newTodo); + } + }) + } + } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) { + + // for the next 12 months + for (let i = 1; i < 12; i++) { + let date = originalTodo.date; + const nextMonth = addMonths(date, i); + + let docRef = firestore().collection("Todos").doc(); + let newTodo = { ...originalTodo, id: docRef.id, date: nextMonth, connectedTodoId: newDoc.id }; + newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i); + + batch.set(docRef, newTodo); + } + } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) { + + // for the next 5 years + for (let i = 1; i < 5; i++) { + let date = originalTodo.date; + const nextMonth = addYears(date, i); + + let docRef = firestore().collection("Todos").doc(); + let newTodo = { ...originalTodo, id: docRef.id, date: nextMonth, connectedTodoId: newDoc.id }; + newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i); + + batch.set(docRef, newTodo); + } + } + + await batch.commit(); + } } catch (e) { console.error(e) } @@ -23,4 +115,15 @@ export const useCreateTodo = () => { queryClients.invalidateQueries("todos") } }) +} + +export const resolveTodoAlternatingAssignees = (todoData, newTodo, i) => { + if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) { + const assignees = todoData.assignees; + const assignee = assignees[i % assignees.length]; + + newTodo = {...newTodo, assignees: [assignee]}; + } + + return newTodo; } \ No newline at end of file diff --git a/hooks/firebase/useDeleteEvent.ts b/hooks/firebase/useDeleteEvent.ts new file mode 100644 index 0000000..ac24168 --- /dev/null +++ b/hooks/firebase/useDeleteEvent.ts @@ -0,0 +1,39 @@ +import {useMutation, useQueryClient} from "react-query"; +import firestore from "@react-native-firebase/firestore"; + +export const useDeleteEvent = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ["deleteEvent"], + mutationFn: async ({eventId, docId}: { eventId?: string; docId?: string }) => { + try { + if (docId) { + await firestore() + .collection("Events") + .doc(docId) + .delete(); + } else if (eventId) { + const snapshot = await firestore() + .collection("Events") + .where("id", "==", eventId) + .get(); + + const doc = snapshot.docs[0]; + if (doc) { + await doc.ref.delete(); + } else { + console.warn("Event not found"); + } + } else { + console.warn("No identifier provided"); + } + } catch (e) { + console.error(e); + } + }, + onSuccess: () => { + queryClient.invalidateQueries("events"); + } + }); +}; \ No newline at end of file diff --git a/hooks/firebase/useDeleteFeedback.ts b/hooks/firebase/useDeleteFeedback.ts new file mode 100644 index 0000000..2490332 --- /dev/null +++ b/hooks/firebase/useDeleteFeedback.ts @@ -0,0 +1,45 @@ +import {useAuthContext} from "@/contexts/AuthContext"; +import {useMutation, useQueryClient} from "react-query"; +import firestore from "@react-native-firebase/firestore"; + +export const useDeleteFeedback = () => { + const { user: currentUser } = useAuthContext(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ["deleteFeedback"], + mutationFn: async (feedbackId: string) => { + try { + // Find the document with matching id field + const snapshot = await firestore() + .collection("Feedbacks") + .where("id", "==", feedbackId) + .get(); + + if (snapshot.empty) { + throw new Error("Feedback not found"); + } + + // Get the first matching document + const docId = snapshot.docs[0].id; + + // Optional: Check if the current user is the creator + const feedbackData = snapshot.docs[0].data(); + if (feedbackData.creatorId !== currentUser?.uid) { + throw new Error( + "Unauthorized: You can only delete your own feedback" + ); + } + + // Delete the document + await firestore().collection("Feedbacks").doc(docId).delete(); + } catch (e) { + console.error("Error deleting feedback: ", e); + throw e; // Re-throw the error to be handled by the mutation + } + }, + onSuccess: () => { + queryClient.invalidateQueries("feedbacks"); + }, + }); +}; diff --git a/hooks/firebase/useDeleteNote.ts b/hooks/firebase/useDeleteNote.ts new file mode 100644 index 0000000..cc78709 --- /dev/null +++ b/hooks/firebase/useDeleteNote.ts @@ -0,0 +1,39 @@ +import { useAuthContext } from "@/contexts/AuthContext"; +import { useMutation, useQueryClient } from "react-query"; +import firestore from "@react-native-firebase/firestore"; + +export const useDeleteNote = () => { + const { user: currentUser } = useAuthContext(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ["deleteNote"], + mutationFn: async (noteId: string) => { + try { + const snapshot = await firestore() + .collection("BrainDumps") + .where("id", "==", noteId) + .get(); + + if (snapshot.empty) { + throw new Error("Note not found"); + } + + const docId = snapshot.docs[0].id; + + const noteData = snapshot.docs[0].data(); + if (noteData.creatorId !== currentUser?.uid) { + throw new Error("Unauthorized: You can only delete your own Note"); + } + + await firestore().collection("BrainDumps").doc(docId).delete(); + } catch (e) { + console.error("Error deleting note: ", e); + throw e; + } + }, + onSuccess: () => { + queryClient.invalidateQueries("braindumps"); + }, + }); +}; diff --git a/hooks/firebase/useGetEvents.ts b/hooks/firebase/useGetEvents.ts index c8c64d2..3b7254a 100644 --- a/hooks/firebase/useGetEvents.ts +++ b/hooks/firebase/useGetEvents.ts @@ -1,23 +1,24 @@ -import {useQuery} from "react-query"; +import { useQuery } from "react-query"; import firestore from "@react-native-firebase/firestore"; -import {useAuthContext} from "@/contexts/AuthContext"; -import {useAtomValue} from "jotai"; -import {isFamilyViewAtom} from "@/components/pages/calendar/atoms"; -import {colorMap} from "@/constants/colorMap"; +import { useAuthContext } from "@/contexts/AuthContext"; +import { useAtomValue } from "jotai"; +import { isFamilyViewAtom } from "@/components/pages/calendar/atoms"; +import { colorMap } from "@/constants/colorMap"; export const useGetEvents = () => { - const {user, profileData} = useAuthContext(); + const { user, profileData } = useAuthContext(); const isFamilyView = useAtomValue(isFamilyViewAtom); return useQuery({ queryKey: ["events", user?.uid, isFamilyView], queryFn: async () => { const db = firestore(); - const userId = user?.uid; const familyId = profileData?.familyId; + let allEvents = []; + // If family view is active, include family, creator, and attendee events if (isFamilyView) { const familyQuery = db.collection("Events").where("familyID", "==", familyId); const creatorQuery = db.collection("Events").where("creatorId", "==", userId); @@ -29,12 +30,14 @@ export const useGetEvents = () => { attendeeQuery.get(), ]); + // Collect all events const familyEvents = familySnapshot.docs.map(doc => doc.data()); const creatorEvents = creatorSnapshot.docs.map(doc => doc.data()); const attendeeEvents = attendeeSnapshot.docs.map(doc => doc.data()); allEvents = [...familyEvents, ...creatorEvents, ...attendeeEvents]; } else { + // Only include creator and attendee events when family view is off const creatorQuery = db.collection("Events").where("creatorId", "==", userId); const attendeeQuery = db.collection("Events").where("attendees", "array-contains", userId); @@ -49,19 +52,28 @@ export const useGetEvents = () => { allEvents = [...creatorEvents, ...attendeeEvents]; } - allEvents = allEvents.filter((event, index, self) => - index === self.findIndex(e => e.id === event.id) - ); + // Use a Map to ensure uniqueness only for events with IDs + const uniqueEventsMap = new Map(); + allEvents.forEach(event => { + if (event.id) { + uniqueEventsMap.set(event.id, event); // Ensure uniqueness for events with IDs + } else { + uniqueEventsMap.set(Math.random().toString(36), event); // Generate a temp key for events without ID + } + }); + const uniqueEvents = Array.from(uniqueEventsMap.values()); - allEvents = allEvents.filter(event => { + // Filter out private events unless the user is the creator + const filteredEvents = uniqueEvents.filter(event => { if (event.private) { return event.creatorId === userId; } return true; }); + // Attach event colors and return the final list of events return await Promise.all( - allEvents.map(async (event) => { + filteredEvents.map(async (event) => { const profileSnapshot = await db .collection("Profiles") .doc(event.creatorId) @@ -71,13 +83,13 @@ export const useGetEvents = () => { const eventColor = profileData?.eventColor || colorMap.pink; return { - id: event.id, + id: event.id || Math.random().toString(36).substr(2, 9), // Generate temp ID if missing title: event.title, start: new Date(event.startDate.seconds * 1000), end: new Date(event.endDate.seconds * 1000), hideHours: event.allDay, - eventColor: eventColor, - notes: event.notes + eventColor, + notes: event.notes, }; }) ); diff --git a/hooks/firebase/useGetFeedbacks.ts b/hooks/firebase/useGetFeedbacks.ts new file mode 100644 index 0000000..da0b699 --- /dev/null +++ b/hooks/firebase/useGetFeedbacks.ts @@ -0,0 +1,28 @@ +import { useAuthContext } from "@/contexts/AuthContext"; +import { useQuery } from "react-query"; +import firestore from "@react-native-firebase/firestore"; +import { IFeedback } from "@/contexts/FeedbackContext"; + +export const useGetFeedbacks = () => { + const { user: currentUser } = useAuthContext(); + + return useQuery({ + queryKey: ["feedbacks", currentUser?.uid], + queryFn: async () => { + try { + const snapshot = await firestore() + .collection("Feedbacks") + .where("creatorId", "==", currentUser?.uid) + .get(); + + return snapshot.docs.map((doc) => ({ + ...doc.data(), + })) as IFeedback[]; + } catch (error) { + console.error("Error fetching feedbacks:", error); + throw error; + } + }, + enabled: !!currentUser?.uid, // Only run query if we have a user ID + }); +}; diff --git a/hooks/firebase/useGetNotes.ts b/hooks/firebase/useGetNotes.ts new file mode 100644 index 0000000..62b590a --- /dev/null +++ b/hooks/firebase/useGetNotes.ts @@ -0,0 +1,28 @@ +import { useAuthContext } from "@/contexts/AuthContext"; +import { useQuery } from "react-query"; +import firestore from "@react-native-firebase/firestore"; +import { IBrainDump } from "@/contexts/DumpContext"; + +export const useGetNotes = () => { + const { user: currentUser } = useAuthContext(); + + return useQuery({ + queryKey: ["braindumps", currentUser?.uid], + queryFn: async () => { + try { + const snapshot = await firestore() + .collection("BrainDumps") + .where("creatorId", "==", currentUser?.uid) + .get(); + + return snapshot.docs.map((doc) => ({ + ...doc.data(), + })) as IBrainDump[]; + } catch (error) { + console.error("Error fetching braindumps:", error); + throw error; + } + }, + enabled: !!currentUser?.uid, + }); +}; diff --git a/hooks/firebase/useGetTodos.ts b/hooks/firebase/useGetTodos.ts index b1d6b77..de4b853 100644 --- a/hooks/firebase/useGetTodos.ts +++ b/hooks/firebase/useGetTodos.ts @@ -1,20 +1,25 @@ import { useQuery } from "react-query"; -import firestore from "@react-native-firebase/firestore"; -import { useAuthContext } from "@/contexts/AuthContext"; -import {UserProfile} from "@/hooks/firebase/types/profileTypes"; -import {IToDo} from "@/hooks/firebase/types/todoData"; +import firestore, {or, query, where} from "@react-native-firebase/firestore"; +import { ProfileType, useAuthContext } from "@/contexts/AuthContext"; +import { IToDo } from "@/hooks/firebase/types/todoData"; export const useGetTodos = () => { const { user, profileData } = useAuthContext(); - //TODO: Add role based filtering for todos return useQuery({ queryKey: ["todos", user?.uid], queryFn: async () => { - const snapshot = await firestore() - .collection("Todos") - .where("familyId", "==", profileData?.familyId) - .get(); + + let snapshot; + if (profileData?.userType === ProfileType.PARENT) { + snapshot = await firestore() + .collection("Todos") + .where("familyId", "==", profileData?.familyId) + .get(); + } else { + let todosQuery = query(firestore().collection("Todos"), or(where("assignees", "array-contains", user?.uid), where("creatorId", "==", user?.uid))); + snapshot = await todosQuery.get(); + } return snapshot.docs.map((doc) => { const data = doc.data(); @@ -23,6 +28,7 @@ export const useGetTodos = () => { ...data, id: doc.id, date: data.date ? new Date(data.date.seconds * 1000) : null, + repeatDays: data.repeatDays ?? [] }; }) as IToDo[]; } diff --git a/hooks/firebase/useLoginWithQrCode.ts b/hooks/firebase/useLoginWithQrCode.ts index 13cc44b..d28c456 100644 --- a/hooks/firebase/useLoginWithQrCode.ts +++ b/hooks/firebase/useLoginWithQrCode.ts @@ -1,12 +1,16 @@ import {useMutation} from "react-query"; import functions, {FirebaseFunctionsTypes} from '@react-native-firebase/functions'; import auth from "@react-native-firebase/auth"; +import {useAuthContext} from "@/contexts/AuthContext"; export const useLoginWithQrCode = () => { + const {setRedirectOverride} = useAuthContext() + return useMutation({ mutationKey: ["loginWithQrCode"], mutationFn: async ({userId}: { userId: string }) => { try { + setRedirectOverride(true) const res = await functions().httpsCallable("generateCustomToken")({userId}) as FirebaseFunctionsTypes.HttpsCallableResult<{ token: string }> diff --git a/hooks/firebase/useSignUp.ts b/hooks/firebase/useSignUp.ts index 2464cd0..4326297 100644 --- a/hooks/firebase/useSignUp.ts +++ b/hooks/firebase/useSignUp.ts @@ -1,44 +1,47 @@ -import { useMutation } from "react-query"; +import {useMutation} from "react-query"; import auth from "@react-native-firebase/auth"; -import { ProfileType } from "@/contexts/AuthContext"; -import { useSetUserData } from "./useSetUserData"; +import {ProfileType, useAuthContext} from "@/contexts/AuthContext"; +import {useSetUserData} from "./useSetUserData"; import {uuidv4} from "@firebase/util"; import * as Localization from "expo-localization"; export const useSignUp = () => { - const { mutateAsync: setUserData } = useSetUserData(); + const {setRedirectOverride} = useAuthContext() + const {mutateAsync: setUserData} = useSetUserData(); - return useMutation({ - mutationKey: ["signUp"], - mutationFn: async ({ - email, - password, - firstName, - lastName, - }: { - email: string; - password: string; - firstName: string; - lastName: string; - }) => { - await auth() - .createUserWithEmailAndPassword(email, password) - .then(async (res) => { - try { - await setUserData({ - newUserData: { - userType: ProfileType.PARENT, - firstName: firstName, - lastName: lastName, - familyId: uuidv4(), - timeZone: Localization.getCalendars()[0].timeZone, - }, - customUser: res.user, - }); - } catch (error) { - console.error(error); - } - }); - }, - }); + return useMutation({ + mutationKey: ["signUp"], + mutationFn: async ({ + email, + password, + firstName, + lastName, + }: { + email: string; + password: string; + firstName: string; + lastName: string; + }) => { + setRedirectOverride(true) + + await auth() + .createUserWithEmailAndPassword(email, password) + .then(async (res) => { + try { + await setUserData({ + newUserData: { + userType: ProfileType.PARENT, + firstName: firstName, + lastName: lastName, + familyId: uuidv4(), + timeZone: Localization.getCalendars()[0].timeZone, + }, + customUser: res.user, + }); + } catch (error) { + console.error(error); + } + }); + }, + }); }; diff --git a/hooks/firebase/useUpdateFeedback.ts b/hooks/firebase/useUpdateFeedback.ts new file mode 100644 index 0000000..aa7260c --- /dev/null +++ b/hooks/firebase/useUpdateFeedback.ts @@ -0,0 +1,65 @@ +import { useAuthContext } from "@/contexts/AuthContext"; +import { useMutation, useQueryClient } from "react-query"; +import firestore from "@react-native-firebase/firestore"; +import { IFeedback } from "@/contexts/FeedbackContext"; + +interface UpdateFeedbackParams { + id: number; + changes: Partial; +} + +export const useUpdateFeedback = () => { + const { user: currentUser } = useAuthContext(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ["updateFeedback"], + mutationFn: async ({ id, changes }: UpdateFeedbackParams) => { + try { + const snapshot = await firestore() + .collection("Feedbacks") + .where("id", "==", id) + .get(); + + if (snapshot.empty) { + throw new Error("Feedback not found"); + } + + const docId = snapshot.docs[0].id; + const feedbackData = snapshot.docs[0].data(); + + if (feedbackData.creatorId !== currentUser?.uid) { + throw new Error( + "Unauthorized: You can only update your own feedback" + ); + } + + await firestore() + .collection("Feedbacks") + .doc(docId) + .update({ + ...changes, + updatedAt: firestore.FieldValue.serverTimestamp(), + lastModifiedBy: currentUser?.uid, + }); + + return { + id, + ...feedbackData, + ...changes, + }; + } catch (e) { + console.error("Error updating feedback: ", e); + throw e; + } + }, + onSuccess: (updatedFeedback) => { + queryClient.invalidateQueries("feedbacks"); + + queryClient.setQueryData( + ["feedback", updatedFeedback.id], + updatedFeedback + ); + }, + }); +}; diff --git a/hooks/firebase/useUpdateNote.ts b/hooks/firebase/useUpdateNote.ts new file mode 100644 index 0000000..fa1035f --- /dev/null +++ b/hooks/firebase/useUpdateNote.ts @@ -0,0 +1,65 @@ +import { useAuthContext } from "@/contexts/AuthContext"; +import { useMutation, useQueryClient } from "react-query"; +import firestore from "@react-native-firebase/firestore"; +import { IBrainDump } from "@/contexts/DumpContext"; + +interface UpdateNoteParams { + id: number; + changes: Partial; +} + +export const useUpdateNote = () => { + const { user: currentUser } = useAuthContext(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ["updateNote"], + mutationFn: async ({ id, changes }: UpdateNoteParams) => { + try { + const snapshot = await firestore() + .collection("BrainDumps") + .where("id", "==", id) + .get(); + + if (snapshot.empty) { + throw new Error("Note not found"); + } + + const docId = snapshot.docs[0].id; + const noteData = snapshot.docs[0].data(); + + if (noteData.creatorId !== currentUser?.uid) { + throw new Error( + "Unauthorized: You can only update your own note" + ); + } + + await firestore() + .collection("BrainDumps") + .doc(docId) + .update({ + ...changes, + updatedAt: firestore.FieldValue.serverTimestamp(), + lastModifiedBy: currentUser?.uid, + }); + + return { + id, + ...noteData, + ...changes, + }; + } catch (e) { + console.error("Error updating note: ", e); + throw e; + } + }, + onSuccess: (updatedNote) => { + queryClient.invalidateQueries("braindumps"); + + queryClient.setQueryData( + ["feedback", updatedNote.id], + updatedNote + ); + }, + }); +}; diff --git a/hooks/firebase/useUpdateTodo.ts b/hooks/firebase/useUpdateTodo.ts index b1b985f..35b254c 100644 --- a/hooks/firebase/useUpdateTodo.ts +++ b/hooks/firebase/useUpdateTodo.ts @@ -1,18 +1,153 @@ import { useMutation, useQueryClient } from "react-query"; import firestore from "@react-native-firebase/firestore"; -import { IToDo } from "@/hooks/firebase/types/todoData"; +import {IToDo, REPEAT_TYPE} from "@/hooks/firebase/types/todoData"; +import {addDays, addMonths, addWeeks, addYears, compareAsc, format, subDays} from "date-fns"; +import {daysOfWeek, resolveTodoAlternatingAssignees} from "@/hooks/firebase/useCreateTodo"; +import {useAuthContext} from "@/contexts/AuthContext"; export const useUpdateTodo = () => { + const { user: currentUser, profileData } = useAuthContext(); const queryClients = useQueryClient() return useMutation({ mutationKey: ["updateTodo"], mutationFn: async (todoData: Partial) => { try { - await firestore() - .collection("Todos") - .doc(todoData.id) - .update(todoData); + if (todoData.connectedTodoId) { + console.log("CONNECTED") + const snapshot = await firestore() + .collection("Todos") + .where("connectedTodoId", "==", todoData.connectedTodoId) + .get(); + const connectedTodos = snapshot.docs.map((doc) => { + const data = doc.data(); + + return { + ...data, + id: doc.id, + date: data.date ? new Date(data.date.seconds * 1000) : null, + ref: doc.ref + }; + }) as IToDo[]; + + console.log("CONNECTED TODO"); + let filteredTodos = connectedTodos?.filter((item) => compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 1 || + compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 0).sort((a,b) =>{ + return b.date?.getSeconds() - a.date?.getSeconds(); + }); + + let firstTodo = filteredTodos?.[0]; + const batch = firestore().batch(); + if (compareAsc(format(firstTodo?.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) !== 0 || firstTodo?.repeatType !== todoData.repeatType) { + + console.log("DELETE"); + filteredTodos?.forEach((item) => { + batch.delete(item.ref); + }); + + if (todoData.repeatType === REPEAT_TYPE.NONE) { + + console.log("NONE"); + const newDoc = firestore().collection('Todos').doc(); + let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid} + batch.set(newDoc, originalTodo); + } else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) { + + console.log("EVERY WEEK"); + let date = todoData?.date; + let repeatDays = todoData?.repeatDays; + const dates = []; + + const originalDateDay = format(date, 'EEEE'); + const originalNumber = daysOfWeek.indexOf(originalDateDay); + repeatDays?.forEach((day) => { + let number = daysOfWeek.indexOf(day); + let newDate; + if (originalNumber > number) { + let diff = originalNumber - number; + newDate = subDays(date, diff); + } else { + let diff = number - originalNumber; + newDate = addDays(date, diff); + } + dates.push(newDate); + }); + + let todosToAddCycles = 4; + if (firstTodo?.repeatType === REPEAT_TYPE.EVERY_WEEK) { + todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length; + } + console.log(todosToAddCycles); + let newDoc = firestore().collection("Todos").doc(); + let originalTodo = { ...todoData, id: newDoc.id, date: todoData.date, connectedTodoId: newDoc?.id }; + originalTodo = resolveTodoAlternatingAssignees(todoData, originalTodo, 0); + batch.set(newDoc, originalTodo); + + console.log(dates); + let index = 1; + for (let i = 0; i <= todosToAddCycles; i++) { + dates?.forEach((dateToAdd) => { + index++; + let newTodoDate = addWeeks(dateToAdd, i); + if (compareAsc(newTodoDate, originalTodo.date) !== 0) { + + let docRef = firestore().collection("Todos").doc(); + let newTodo = { ...todoData, id: docRef.id, date: newTodoDate, connectedTodoId: newDoc?.id }; + newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, index); + + batch.set(docRef, newTodo); + } + }) + } + } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) { + + console.log("ONCE A MONTH"); + // for the next 12 months + for (let i = 0; i < 12; i++) { + let date = todoData?.date; + const nextMonth = addMonths(date, i); + + let docRef = firestore().collection("Todos").doc(); + let newTodo = { ...todoData, id: docRef.id, date: nextMonth, connectedTodoId: firstTodo?.connectedTodoId }; + newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i); + batch.set(docRef, newTodo); + } + } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) { + + console.log("ONCE A YEAR"); + // for the next 5 years + for (let i = 0; i < 5; i++) { + let date = todoData?.date; + const nextMonth = addYears(date, i); + + let docRef = firestore().collection("Todos").doc(); + let newTodo = { ...todoData, id: docRef.id, date: nextMonth, connectedTodoId: firstTodo?.connectedTodoId }; + newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i); + batch.set(docRef, newTodo); + } + } + + await batch.commit(); + } else if (firstTodo?.repeatDays !== todoData.repeatDays) { + + console.log("UPDATE REPEAT DAYS"); + await updateRepeatDaysTodos(batch, todoData, firstTodo, filteredTodos) + } else { + filteredTodos?.forEach((item) => { + + console.log("UPDATE"); + batch.update(item.ref, {...todoData, date: item.date}); + }) + await batch.commit(); + } + } else { + console.log("REGULAR UPDATE"); + console.log(todoData); + await firestore() + .collection("Todos") + .doc(todoData.id) + .update(todoData); + } } catch (e) { console.error(e) } @@ -21,4 +156,62 @@ export const useUpdateTodo = () => { queryClients.invalidateQueries("todos") } }) +} + +const updateRepeatDaysTodos = async (batch: any, todoData: IToDo, firstTodo: IToDo, filteredTodos: IToDo[]) => { + const todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length; + console.log(todosToAddCycles); + + filteredTodos?.forEach((item) => { + + batch.update(item.ref, {...todoData, date: item.date}); + }) + + let newRepeatDays = todoData.repeatDays?.filter((element) => firstTodo?.repeatDays?.indexOf(element) === -1); + let removeRepeatDays = firstTodo?.repeatDays?.filter((element) => todoData?.repeatDays?.indexOf(element) === -1); + const dates = []; + + let date = firstTodo?.date; + const originalDateDay = format(date, 'EEEE'); + const originalNumber = daysOfWeek.indexOf(originalDateDay); + newRepeatDays?.forEach((day) => { + let number = daysOfWeek.indexOf(day); + let newDate; + if (originalNumber > number) { + let diff = originalNumber - number; + newDate = subDays(date, diff); + } else { + let diff = number - originalNumber; + newDate = addDays(date, diff); + } + dates.push(newDate); + }); + + let index = 0; + for (let i = 0; i < todosToAddCycles; i++) { + dates?.forEach((dateToAdd) => { + index ++; + let newTodoDate = addWeeks(dateToAdd, i); + if (compareAsc(newTodoDate, firstTodo?.date) !== 0) { + let newTodo = {...todoData, date: newTodoDate}; + newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, index); + + let docRef = firestore().collection("Todos").doc(); + batch.set(docRef, newTodo); + } + }) + } + + removeRepeatDays?.forEach((removeDay) => { + filteredTodos?.forEach((item) => { + + let todoDate = item.date; + const todoDateDay = format(todoDate, 'EEEE'); + + if (todoDateDay === removeDay) { + batch.delete(item.ref); + } + }) + }) + await batch.commit(); } \ No newline at end of file diff --git a/hooks/useCalSync.ts b/hooks/useCalSync.ts new file mode 100644 index 0000000..76c2dff --- /dev/null +++ b/hooks/useCalSync.ts @@ -0,0 +1,288 @@ +import {useAuthContext} from "@/contexts/AuthContext"; +import {useEffect} from "react"; +import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData"; +import {useFetchAndSaveGoogleEvents} from "@/hooks/useFetchAndSaveGoogleEvents"; +import {useFetchAndSaveOutlookEvents} from "@/hooks/useFetchAndSaveOutlookEvents"; +import {useFetchAndSaveAppleEvents} from "@/hooks/useFetchAndSaveAppleEvents"; +import * as WebBrowser from "expo-web-browser"; +import * as Google from "expo-auth-session/providers/google"; +import * as AuthSession from "expo-auth-session"; +import * as AppleAuthentication from "expo-apple-authentication"; + +const googleConfig = { + androidClientId: + "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com", + iosClientId: + "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com", + webClientId: + "406146460310-2u67ab2nbhu23trp8auho1fq4om29fc0.apps.googleusercontent.com", + scopes: [ + "email", + "profile", + "https://www.googleapis.com/auth/calendar.events.owned", + ], + extraParams: { + access_type: "offline", + }, +}; + +const microsoftConfig = { + clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af", + redirectUri: AuthSession.makeRedirectUri({path: "settings"}), + scopes: [ + "openid", + "profile", + "email", + "offline_access", + "Calendars.ReadWrite", + "User.Read", + ], + authorizationEndpoint: + "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", + tokenEndpoint: "https://login.microsoftonline.com/common/oauth2/v2.0/token", +}; + +export const useCalSync = () => { + const {profileData} = useAuthContext(); + + const {mutateAsync: updateUserData} = useUpdateUserData(); + const {mutateAsync: fetchAndSaveGoogleEvents, isLoading: isSyncingGoogle} = + useFetchAndSaveGoogleEvents(); + const { + mutateAsync: fetchAndSaveOutlookEvents, + isLoading: isSyncingOutlook, + } = useFetchAndSaveOutlookEvents(); + const {mutateAsync: fetchAndSaveAppleEvents, isLoading: isSyncingApple} = + useFetchAndSaveAppleEvents(); + + WebBrowser.maybeCompleteAuthSession(); + const [_, response, promptAsync] = Google.useAuthRequest(googleConfig); + + useEffect(() => { + signInWithGoogle(); + }, [response]); + + const signInWithGoogle = async () => { + try { + if (response?.type === "success") { + const {accessToken, refreshToken} = response?.authentication!; + + const userInfoResponse = await fetch( + "https://www.googleapis.com/oauth2/v3/userinfo", + { + headers: {Authorization: `Bearer ${accessToken}`}, + } + ); + + const userInfo = await userInfoResponse.json(); + const googleMail = userInfo.email; + + let googleAccounts = profileData?.googleAccounts || {}; + const updatedGoogleAccounts = { + ...googleAccounts, + [googleMail]: {accessToken, refreshToken}, + }; + + await updateUserData({ + newUserData: {googleAccounts: updatedGoogleAccounts}, + }); + + await fetchAndSaveGoogleEvents({ + token: accessToken, + email: googleMail, + }); + } + } catch (error) { + console.error("Error during Google sign-in:", error); + } + }; + + const handleMicrosoftSignIn = async () => { + try { + console.log("Starting Microsoft sign-in..."); + + const authRequest = new AuthSession.AuthRequest({ + clientId: microsoftConfig.clientId, + scopes: microsoftConfig.scopes, + redirectUri: microsoftConfig.redirectUri, + responseType: AuthSession.ResponseType.Code, + usePKCE: true, // Enable PKCE + }); + + console.log("Auth request created:", authRequest); + + const authResult = await authRequest.promptAsync({ + authorizationEndpoint: microsoftConfig.authorizationEndpoint, + }); + + console.log("Auth result:", authResult); + + if (authResult.type === "success" && authResult.params?.code) { + const code = authResult.params.code; + console.log("Authorization code received:", code); + + // Exchange authorization code for tokens + const tokenResponse = await fetch(microsoftConfig.tokenEndpoint, { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: `client_id=${ + microsoftConfig.clientId + }&redirect_uri=${encodeURIComponent( + microsoftConfig.redirectUri + )}&grant_type=authorization_code&code=${code}&code_verifier=${ + authRequest.codeVerifier + }&scope=${encodeURIComponent( + "https://graph.microsoft.com/Calendars.ReadWrite offline_access User.Read" + )}`, + }); + + console.log("Token response status:", tokenResponse.status); + + if (!tokenResponse.ok) { + const errorText = await tokenResponse.text(); + console.error("Token exchange failed:", errorText); + return; + } + + const tokenData = await tokenResponse.json(); + console.log("Token data received:", tokenData); + + if (tokenData?.access_token) { + console.log("Access token received, fetching user info..."); + + // Fetch user info from Microsoft Graph API to get the email + const userInfoResponse = await fetch( + "https://graph.microsoft.com/v1.0/me", + { + headers: { + Authorization: `Bearer ${tokenData.access_token}`, + }, + } + ); + + const userInfo = await userInfoResponse.json(); + console.log("User info received:", userInfo); + + if (userInfo.error) { + console.error("Error fetching user info:", userInfo.error); + } else { + const outlookMail = userInfo.mail || userInfo.userPrincipalName; + + let microsoftAccounts = profileData?.microsoftAccounts; + const updatedMicrosoftAccounts = microsoftAccounts + ? {...microsoftAccounts, [outlookMail]: tokenData.access_token} + : {[outlookMail]: tokenData.access_token}; + + await updateUserData({ + newUserData: {microsoftAccounts: updatedMicrosoftAccounts}, + }); + + await fetchAndSaveOutlookEvents( + tokenData.access_token, + outlookMail + ); + console.log("User data updated successfully."); + } + } + } else { + console.warn("Authentication was not successful:", authResult); + } + } catch (error) { + console.error("Error during Microsoft sign-in:", error); + } + }; + + const handleAppleSignIn = async () => { + try { + console.log("Starting Apple Sign-in..."); + + const credential = await AppleAuthentication.signInAsync({ + requestedScopes: [ + AppleAuthentication.AppleAuthenticationScope.EMAIL, + AppleAuthentication.AppleAuthenticationScope.FULL_NAME, + ], + }); + + console.log("Apple sign-in result:", credential); + + alert(JSON.stringify(credential)) + + const appleToken = credential.identityToken; + const appleMail = credential.email!; + + + if (appleToken) { + console.log("Apple ID token received. Fetch user info if needed..."); + + let appleAcounts = profileData?.appleAccounts; + const updatedAppleAccounts = appleAcounts + ? {...appleAcounts, [appleMail]: appleToken} + : {[appleMail]: appleToken}; + + await updateUserData({ + newUserData: {appleAccounts: updatedAppleAccounts}, + }); + + console.log("User data updated with Apple ID token."); + await fetchAndSaveAppleEvents({token: appleToken, email: appleMail!}); + } else { + console.warn( + "Apple authentication was not successful or email was hidden." + ); + } + } catch (error) { + console.error("Error during Apple Sign-in:", error); + } + }; + + + let isConnectedToGoogle = false; + if (profileData?.googleAccounts) { + Object.values(profileData?.googleAccounts).forEach((item) => { + if (item !== null) { + isConnectedToGoogle = true; + return; + } + }); + } + + let isConnectedToMicrosoft = false; + const microsoftAccounts = profileData?.microsoftAccounts; + if (microsoftAccounts) { + Object.values(profileData?.microsoftAccounts).forEach((item) => { + if (item !== null) { + isConnectedToMicrosoft = true; + return; + } + }); + } + + let isConnectedToApple = false; + if (profileData?.appleAccounts) { + Object.values(profileData?.appleAccounts).forEach((item) => { + if (item !== null) { + isConnectedToApple = true; + return; + } + }); + } + + + return { + handleAppleSignIn, + handleMicrosoftSignIn, + handleGoogleSignIn: signInWithGoogle, + handleStartGoogleSignIn: promptAsync, + fetchAndSaveOutlookEvents, + fetchAndSaveAppleEvents, + fetchAndSaveGoogleEvents, + isConnectedToApple, + isConnectedToMicrosoft, + isConnectedToGoogle, + isSyncingOutlook, + isSyncingGoogle, + isSyncingApple + } +} \ No newline at end of file diff --git a/hooks/useFetchAndSaveAppleEvents.ts b/hooks/useFetchAndSaveAppleEvents.ts index b0f1783..85f1cf7 100644 --- a/hooks/useFetchAndSaveAppleEvents.ts +++ b/hooks/useFetchAndSaveAppleEvents.ts @@ -1,9 +1,10 @@ -import {useMutation} from "react-query"; +import {useMutation, useQueryClient} from "react-query"; import {useAuthContext} from "@/contexts/AuthContext"; import {useCreateEventsFromProvider} from "@/hooks/firebase/useCreateEvent"; import {fetchiPhoneCalendarEvents} from "@/calendar-integration/apple-calendar-utils"; export const useFetchAndSaveAppleEvents = () => { + const queryClient = useQueryClient() const {profileData} = useAuthContext(); const {mutateAsync: createEventsFromProvider} = useCreateEventsFromProvider(); @@ -29,5 +30,8 @@ export const useFetchAndSaveAppleEvents = () => { throw error; } }, + onSuccess: () => { + queryClient.invalidateQueries(["events"]) + }, }); }; \ No newline at end of file diff --git a/hooks/useFetchAndSaveGoogleEvents.ts b/hooks/useFetchAndSaveGoogleEvents.ts index 7f823a0..b96c0f9 100644 --- a/hooks/useFetchAndSaveGoogleEvents.ts +++ b/hooks/useFetchAndSaveGoogleEvents.ts @@ -1,11 +1,14 @@ -import {useMutation} from "react-query"; +import {useMutation, useQueryClient} from "react-query"; import {fetchGoogleCalendarEvents} from "@/calendar-integration/google-calendar-utils"; import {useAuthContext} from "@/contexts/AuthContext"; import {useCreateEventsFromProvider} from "@/hooks/firebase/useCreateEvent"; +import {useClearTokens} from "@/hooks/firebase/useClearTokens"; export const useFetchAndSaveGoogleEvents = () => { + const queryClient = useQueryClient() const {profileData} = useAuthContext(); const {mutateAsync: createEventsFromProvider} = useCreateEventsFromProvider(); + const {mutateAsync: clearToken} = useClearTokens(); return useMutation({ mutationKey: ["fetchAndSaveGoogleEvents"], @@ -25,9 +28,14 @@ export const useFetchAndSaveGoogleEvents = () => { timeMax.toISOString().slice(0, -5) + "Z" ); + if(!response.success) { + await clearToken({email: email!, provider: "google"}) + return + } + console.log("Google Calendar events fetched:", response); - const items = response?.map((item) => { + const items = response?.googleEvents?.map((item) => { if (item.allDay) { item.startDate = new Date(new Date(item.startDate).setHours(0, 0, 0, 0)); item.endDate = item.startDate; @@ -41,5 +49,8 @@ export const useFetchAndSaveGoogleEvents = () => { throw error; // Ensure errors are propagated to the mutation } }, + onSuccess: () => { + queryClient.invalidateQueries(["events"]) + }, }); }; \ No newline at end of file diff --git a/hooks/useFetchAndSaveOutlookEvents.ts b/hooks/useFetchAndSaveOutlookEvents.ts index 36540bb..5d5f6a3 100644 --- a/hooks/useFetchAndSaveOutlookEvents.ts +++ b/hooks/useFetchAndSaveOutlookEvents.ts @@ -1,9 +1,10 @@ -import {useMutation} from "react-query"; +import {useMutation, useQueryClient} from "react-query"; import {useAuthContext} from "@/contexts/AuthContext"; import {useCreateEventsFromProvider} from "@/hooks/firebase/useCreateEvent"; import {fetchMicrosoftCalendarEvents} from "@/calendar-integration/microsoft-calendar-utils"; export const useFetchAndSaveOutlookEvents = () => { + const queryClient = useQueryClient() const {profileData} = useAuthContext(); const {mutateAsync: createEventsFromProvider} = useCreateEventsFromProvider(); @@ -32,5 +33,8 @@ export const useFetchAndSaveOutlookEvents = () => { throw error; } }, + onSuccess: () => { + queryClient.invalidateQueries(["events"]) + }, }); }; \ No newline at end of file diff --git a/hooks/useUploadProfilePicture.ts b/hooks/useUploadProfilePicture.ts new file mode 100644 index 0000000..5c452b6 --- /dev/null +++ b/hooks/useUploadProfilePicture.ts @@ -0,0 +1,62 @@ +import {useState} from "react"; +import * as ImagePicker from "expo-image-picker"; +import {useChangeProfilePicture} from "@/hooks/firebase/useChangeProfilePicture"; +import {useUpdateUserData} from "@/hooks/firebase/useUpdateUserData"; + +export const useUploadProfilePicture = (customUserId?: string, existingPfp?: string) => { + const [profileImage, setProfileImage] = useState< + string | ImagePicker.ImagePickerAsset | null + >(existingPfp || null); + + const [profileImageAsset, setProfileImageAsset] = useState< + ImagePicker.ImagePickerAsset | null + >(null); + + const {mutateAsync: updateUserData} = useUpdateUserData(); + const {mutateAsync: changeProfilePicture} = useChangeProfilePicture(customUserId); + + const pickImage = async () => { + const permissionResult = + await ImagePicker.requestMediaLibraryPermissionsAsync(); + if (!permissionResult.granted) { + alert("Permission to access camera roll is required!"); + return; + } + + const result = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.Images, + allowsEditing: true, + aspect: [1, 1], + quality: 1, + }); + + if (!result.canceled) { + setProfileImage(result.assets[0].uri); + setProfileImageAsset(result.assets[0]); + if (!customUserId) { + await changeProfilePicture(result.assets[0]); + } + } + }; + + const handleClearImage = async () => { + if (!customUserId) { + await updateUserData({newUserData: {pfp: null}}); + } + setProfileImage(null); + }; + + const pfpUri = + profileImage && typeof profileImage === "object" && "uri" in profileImage + ? profileImage.uri + : profileImage; + + return { + pfpUri, + profileImage, + profileImageAsset, + handleClearImage, + pickImage, + changeProfilePicture + } +} \ No newline at end of file diff --git a/ios/cally.xcodeproj/project.pbxproj b/ios/cally.xcodeproj/project.pbxproj index ef5c283..ca73519 100644 --- a/ios/cally.xcodeproj/project.pbxproj +++ b/ios/cally.xcodeproj/project.pbxproj @@ -450,7 +450,7 @@ ); OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = com.cally.app; - PRODUCT_NAME = "Cally"; + PRODUCT_NAME = Cally; SWIFT_OBJC_BRIDGING_HEADER = "cally/cally-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -484,7 +484,7 @@ ); OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; PRODUCT_BUNDLE_IDENTIFIER = com.cally.app; - PRODUCT_NAME = "Cally"; + PRODUCT_NAME = Cally; SWIFT_OBJC_BRIDGING_HEADER = "cally/cally-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/ios/cally/Info.plist b/ios/cally/Info.plist index 468c1d5..046ab16 100644 --- a/ios/cally/Info.plist +++ b/ios/cally/Info.plist @@ -47,7 +47,7 @@ CFBundleVersion - 40 + 60 LSRequiresIPhoneOS NSAppTransportSecurity @@ -118,6 +118,24 @@ $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route + $(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route UILaunchStoryboardName SplashScreen diff --git a/package-lock.json b/package-lock.json index 150ac14..2df2850 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "cally", "version": "1.0.0", + "hasInstallScript": true, "dependencies": { "@expo-google-fonts/manrope": "^0.2.3", "@expo-google-fonts/plus-jakarta-sans": "^0.2.3", @@ -50,12 +51,14 @@ "firebase-functions": "^5.1.0", "fuzzysort": "^3.0.2", "jotai": "^2.9.1", + "patch-package": "^8.0.0", "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.74.3", "react-native-app-auth": "^8.0.0", - "react-native-big-calendar": "^4.14.0", + "react-native-big-calendar": "^4.15.1", "react-native-calendars": "^1.1306.0", + "react-native-element-dropdown": "^2.12.2", "react-native-gesture-handler": "~2.16.1", "react-native-gifted-charts": "^1.4.41", "react-native-keyboard-manager": "^6.5.16-0", @@ -82,6 +85,7 @@ "@types/react-test-renderer": "^18.0.7", "jest": "^29.2.1", "jest-expo": "~51.0.3", + "postinstall-postinstall": "^2.1.0", "react-test-renderer": "18.2.0", "typescript": "~5.3.3" } @@ -6013,6 +6017,12 @@ "node": ">=10.0.0" } }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "license": "BSD-2-Clause" + }, "node_modules/@zxing/text-encoding": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", @@ -13185,6 +13195,30 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, + "node_modules/json-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", + "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/json-stable-stringify/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -13209,6 +13243,15 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -13313,6 +13356,15 @@ "node": ">=0.10.0" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -15060,6 +15112,74 @@ "cross-spawn": "^7.0.3" } }, + "node_modules/patch-package": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", + "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -15295,6 +15415,14 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, + "node_modules/postinstall-postinstall": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz", + "integrity": "sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -15908,13 +16036,13 @@ "license": "MIT" }, "node_modules/react-native-big-calendar": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/react-native-big-calendar/-/react-native-big-calendar-4.14.0.tgz", - "integrity": "sha512-EYCxqXnRAg8QWsW3Npq3JI/9+lXlo9o6Gri7WttQQSqE/cGkVrVeKXObpvN6Cc4qrIUvnc4cgLAeM/j4+bOb6g==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/react-native-big-calendar/-/react-native-big-calendar-4.15.1.tgz", + "integrity": "sha512-hNrzkM+9Kb2T0J/1fW9AMaeN+AuhakCfNtQPaQL29l3JXgOO14ikJ3iPqQkmNVbuiWYiMrpI25hrmXffiOVIgQ==", "license": "MIT", "dependencies": { "calendarize": "^1.1.1", - "dayjs": "^1.11.10" + "dayjs": "^1.11.13" }, "peerDependencies": { "react": "*", @@ -15939,6 +16067,22 @@ "moment": "^2.29.4" } }, + "node_modules/react-native-element-dropdown": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/react-native-element-dropdown/-/react-native-element-dropdown-2.12.2.tgz", + "integrity": "sha512-Tf8hfRuniYEXo+LGoVgIMoItKWuPLX6jbqlwAFgMbBhmWGTuV+g1OVOAx/ny16kgnwp+NhgJoWpxhVvr7HSmXA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-gesture-handler": { "version": "2.16.2", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.16.2.tgz", diff --git a/package.json b/package.json index f05e3e3..f05d490 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "prebuild": "npx expo prebuild -p ios", "prebuild-build-submit-ios": "yarn run prebuild && yarn run build-ios && yarn run submit", "prebuild-build-submit-ios-cicd": "yarn build-ios-cicd", - "prebuild-build-submit-cicd": "yarn build-cicd" + "prebuild-build-submit-cicd": "yarn build-cicd", + "postinstall": "patch-package" }, "jest": { "preset": "jest-expo" @@ -49,6 +50,7 @@ "expo-auth-session": "^5.5.2", "expo-barcode-scanner": "~13.0.1", "expo-build-properties": "~0.12.4", + "expo-cached-image": "^51.0.19", "expo-calendar": "~13.0.5", "expo-camera": "~15.0.16", "expo-constants": "~16.0.2", @@ -70,11 +72,12 @@ "firebase-functions": "^5.1.0", "fuzzysort": "^3.0.2", "jotai": "^2.9.1", + "patch-package": "^8.0.0", "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.74.3", "react-native-app-auth": "^8.0.0", - "react-native-big-calendar": "^4.14.0", + "react-native-big-calendar": "^4.15.1", "react-native-calendars": "^1.1306.0", "react-native-element-dropdown": "^2.12.2", "react-native-gesture-handler": "~2.16.1", @@ -103,6 +106,7 @@ "@types/react-test-renderer": "^18.0.7", "jest": "^29.2.1", "jest-expo": "~51.0.3", + "postinstall-postinstall": "^2.1.0", "react-test-renderer": "18.2.0", "typescript": "~5.3.3" }, diff --git a/patches/react-native-big-calendar+4.15.1.patch b/patches/react-native-big-calendar+4.15.1.patch new file mode 100644 index 0000000..9173bde --- /dev/null +++ b/patches/react-native-big-calendar+4.15.1.patch @@ -0,0 +1,186 @@ +diff --git a/node_modules/react-native-big-calendar/build/index.js b/node_modules/react-native-big-calendar/build/index.js +index 848ceba..57fbaed 100644 +--- a/node_modules/react-native-big-calendar/build/index.js ++++ b/node_modules/react-native-big-calendar/build/index.js +@@ -9,6 +9,17 @@ var isoWeek = require('dayjs/plugin/isoWeek'); + var React = require('react'); + var reactNative = require('react-native'); + var calendarize = require('calendarize'); ++var { ++ startOfDay, ++ endOfDay, ++ startOfWeek, ++ isAfter, ++ isBefore, ++ isSameDay, ++ differenceInDays, ++ add, ++ getTime ++} = require('date-fns'); + + function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } + +@@ -1000,87 +1011,91 @@ function _CalendarBodyForMonthView(_a) { + var start = _a.start, end = _a.end; + return day.isBetween(dayjs__default["default"](start).startOf('day'), dayjs__default["default"](end).endOf('day'), null, '[)'); + }); +- } +- else { +- /** +- * Better way to sort overlapping events that spans accross multiple days +- * For example, if you want following events +- * Event 1, start = 01/01 12:00, end = 02/01 12:00 +- * Event 2, start = 02/01 12:00, end = 03/01 12:00 +- * Event 3, start = 03/01 12:00, end = 04/01 12:00 +- * +- * When drawing calendar in month view, event 3 should be placed at 3rd index for 03/01, because Event 2 are placed at 2nd index for 02/01 and 03/01 +- * +- */ +- var min_1 = day.startOf('day'), max_1 = day.endOf('day'); +- //filter all events that starts from the current week until the current day, and sort them by reverse starting time +- var filteredEvents_1 = events +- .filter(function (_a) { +- var start = _a.start, end = _a.end; +- return dayjs__default["default"](end).isAfter(day.startOf('week')) && dayjs__default["default"](start).isBefore(max_1); +- }) +- .sort(function (a, b) { +- if (dayjs__default["default"](a.start).isSame(b.start, 'day')) { +- var aDuration = dayjs__default["default"].duration(dayjs__default["default"](a.end).diff(dayjs__default["default"](a.start))).days(); +- var bDuration = dayjs__default["default"].duration(dayjs__default["default"](b.end).diff(dayjs__default["default"](b.start))).days(); +- return aDuration - bDuration; +- } +- return b.start.getTime() - a.start.getTime(); ++ } else { ++ // Convert day once and cache all the commonly used dates/times ++ const jsDay = day?.toDate?.() || day; ++ const weekStart = startOfWeek(jsDay); ++ var min_1 = startOfDay(jsDay); ++ var max_1 = endOfDay(jsDay); ++ const max1Time = getTime(max_1); ++ const min1Time = getTime(min_1); ++ ++ // Pre-process events with dates and cache timestamps ++ const processedEvents = events.map(event => { ++ const startDay = event.start?.toDate?.() || new Date(event.start); ++ const endDay = event.end?.toDate?.() || new Date(event.end); ++ return { ++ ...event, ++ startDay, ++ endDay, ++ startTime: getTime(startDay), ++ endTime: getTime(endDay), ++ startDayStart: startOfDay(startDay) ++ }; + }); +- /** +- * find the most relevant min date to filter the events +- * in the example: +- * 1. when rendering for 01/01, min date will be 01/01 (start of day for event 1) +- * 2. when rendering for 02/01, min date will be 01/01 (start of day for event 1) +- * 3. when rendering for 03/01, min date will be 01/01 (start of day for event 1) +- * 4. when rendering for 04/01, min date will be 01/01 (start of day for event 1) +- * 5. when rendering for 05/01, min date will be 05/01 (no event overlaps with 05/01) +- */ +- filteredEvents_1.forEach(function (_a) { +- var start = _a.start, end = _a.end; +- if (dayjs__default["default"](end).isAfter(min_1) && dayjs__default["default"](start).isBefore(min_1)) { +- min_1 = dayjs__default["default"](start).startOf('day'); ++ ++ // Filter events within the weekly range and sort by reverse start time ++ let filteredEvents_1 = processedEvents ++ .filter(({ startTime, endTime }) => ++ endTime > getTime(weekStart) && startTime < max1Time ++ ) ++ .sort((a, b) => { ++ if (isSameDay(a.startDay, b.startDay)) { ++ // Pre-calculate durations since they're used in sorting ++ const aDuration = differenceInDays(a.endDay, a.startDay); ++ const bDuration = differenceInDays(b.endDay, b.startDay); ++ return bDuration - aDuration; ++ } ++ return b.startTime - a.startTime; ++ }); ++ ++ // Update min_1 to the earliest startDay for overlapping events ++ for (const event of filteredEvents_1) { ++ if (event.endTime > min1Time && event.startTime < min1Time) { ++ min_1 = event.startDayStart; ++ break; // We only need the first one due to the sort order + } +- }); ++ } ++ ++ // Filter to keep only events that overlap the min to max range, then reverse ++ const min1TimeUpdated = getTime(min_1); + filteredEvents_1 = filteredEvents_1 +- .filter(function (_a) { +- var start = _a.start, end = _a.end; +- return dayjs__default["default"](end).endOf('day').isAfter(min_1) && dayjs__default["default"](start).isBefore(max_1); +- }) ++ .filter(({ startTime, endDay }) => ++ getTime(endOfDay(endDay)) > min1TimeUpdated && startTime < max1Time ++ ) + .reverse(); +- /** +- * We move eligible event to the top +- * For example, when rendering for 03/01, Event 3 should be moved to the top, since there is a gap left by Event 1 +- */ +- var finalEvents_1 = []; +- var tmpDay_1 = day.startOf('week'); +- //re-sort events from the start of week until the calendar cell date +- //optimize sorting of event nodes and make sure that no empty gaps are left on top of calendar cell +- while (!tmpDay_1.isAfter(day)) { +- filteredEvents_1.forEach(function (event) { +- if (dayjs__default["default"](event.end).isBefore(tmpDay_1.startOf('day'))) { +- var eventToMoveUp = filteredEvents_1.find(function (e) { +- return dayjs__default["default"](e.start).startOf('day').isSame(tmpDay_1.startOf('day')); +- }); +- if (eventToMoveUp != undefined) { +- //remove eventToMoveUp from finalEvents first +- if (finalEvents_1.indexOf(eventToMoveUp) > -1) { +- finalEvents_1.splice(finalEvents_1.indexOf(eventToMoveUp), 1); +- } +- if (finalEvents_1.indexOf(event) > -1) { +- finalEvents_1.splice(finalEvents_1.indexOf(event), 1, eventToMoveUp); +- } +- else { ++ ++ // Move eligible events to the top, preventing duplicate entries ++ const finalEvents_1 = []; ++ const seenEvents = new Set(); // Use Set for faster lookups ++ let tmpDay_1 = weekStart; ++ ++ while (!isAfter(tmpDay_1, jsDay)) { ++ const tmpDayTime = getTime(tmpDay_1); ++ ++ for (const event of filteredEvents_1) { ++ const eventEndDayTime = getTime(startOfDay(event.endDay)); ++ ++ if (!seenEvents.has(event)) { ++ if (eventEndDayTime < tmpDayTime) { ++ // Find event starting on tmpDay ++ const eventToMoveUp = filteredEvents_1.find(e => ++ isSameDay(e.startDayStart, tmpDay_1) ++ ); ++ if (eventToMoveUp && !seenEvents.has(eventToMoveUp)) { + finalEvents_1.push(eventToMoveUp); ++ seenEvents.add(eventToMoveUp); + } ++ } else { ++ finalEvents_1.push(event); ++ seenEvents.add(event); + } + } +- else if (finalEvents_1.indexOf(event) == -1) { +- finalEvents_1.push(event); +- } +- }); +- tmpDay_1 = tmpDay_1.add(1, 'day'); ++ } ++ tmpDay_1 = add(tmpDay_1, { days: 1 }); + } ++ ++ console.log(finalEvents_1); + return finalEvents_1; + } + }, [events, sortedMonthView]); diff --git a/yarn.lock b/yarn.lock index 4c0db75..031ff68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -953,6 +953,89 @@ wrap-ansi "^7.0.0" ws "^8.12.1" +"@expo/cli@0.18.30": + version "0.18.30" + resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-0.18.30.tgz#0cb4829aa11e98ae350a5c15958b9816e9a1d2f0" + integrity sha512-V90TUJh9Ly8stYo8nwqIqNWCsYjE28GlVFWEhAFCUOp99foiQr8HSTpiiX5GIrprcPoWmlGoY+J5fQA29R4lFg== + dependencies: + "@babel/runtime" "^7.20.0" + "@expo/code-signing-certificates" "0.0.5" + "@expo/config" "~9.0.0-beta.0" + "@expo/config-plugins" "~8.0.8" + "@expo/devcert" "^1.0.0" + "@expo/env" "~0.3.0" + "@expo/image-utils" "^0.5.0" + "@expo/json-file" "^8.3.0" + "@expo/metro-config" "0.18.11" + "@expo/osascript" "^2.0.31" + "@expo/package-manager" "^1.5.0" + "@expo/plist" "^0.1.0" + "@expo/prebuild-config" "7.0.9" + "@expo/rudder-sdk-node" "1.1.1" + "@expo/spawn-async" "^1.7.2" + "@expo/xcpretty" "^4.3.0" + "@react-native/dev-middleware" "0.74.85" + "@urql/core" "2.3.6" + "@urql/exchange-retry" "0.3.0" + accepts "^1.3.8" + arg "5.0.2" + better-opn "~3.0.2" + bplist-creator "0.0.7" + bplist-parser "^0.3.1" + cacache "^18.0.2" + chalk "^4.0.0" + ci-info "^3.3.0" + connect "^3.7.0" + debug "^4.3.4" + env-editor "^0.4.1" + fast-glob "^3.3.2" + find-yarn-workspace-root "~2.0.0" + form-data "^3.0.1" + freeport-async "2.0.0" + fs-extra "~8.1.0" + getenv "^1.0.0" + glob "^7.1.7" + graphql "15.8.0" + graphql-tag "^2.10.1" + https-proxy-agent "^5.0.1" + internal-ip "4.3.0" + is-docker "^2.0.0" + is-wsl "^2.1.1" + js-yaml "^3.13.1" + json-schema-deref-sync "^0.13.0" + lodash.debounce "^4.0.8" + md5hex "^1.0.0" + minimatch "^3.0.4" + node-fetch "^2.6.7" + node-forge "^1.3.1" + npm-package-arg "^7.0.0" + open "^8.3.0" + ora "3.4.0" + picomatch "^3.0.1" + pretty-bytes "5.6.0" + progress "2.0.3" + prompts "^2.3.2" + qrcode-terminal "0.11.0" + require-from-string "^2.0.2" + requireg "^0.2.2" + resolve "^1.22.2" + resolve-from "^5.0.0" + resolve.exports "^2.0.2" + semver "^7.6.0" + send "^0.18.0" + slugify "^1.3.4" + source-map-support "~0.5.21" + stacktrace-parser "^0.1.10" + structured-headers "^0.4.1" + tar "^6.0.5" + temp-dir "^2.0.0" + tempy "^0.7.1" + terminal-link "^2.1.1" + text-table "^0.2.0" + url-join "4.0.0" + wrap-ansi "^7.0.0" + ws "^8.12.1" + "@expo/code-signing-certificates@0.0.5": version "0.0.5" resolved "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.5.tgz" @@ -961,6 +1044,27 @@ node-forge "^1.2.1" nullthrows "^1.1.1" +"@expo/config-plugins@8.0.10": + version "8.0.10" + resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-8.0.10.tgz#5cda076f38bc04675cb42d8acdd23d6e460a62de" + integrity sha512-KG1fnSKRmsudPU9BWkl59PyE0byrE2HTnqbOrgwr2FAhqh7tfr9nRs6A9oLS/ntpGzmFxccTEcsV0L4apsuxxg== + dependencies: + "@expo/config-types" "^51.0.3" + "@expo/json-file" "~8.3.0" + "@expo/plist" "^0.1.0" + "@expo/sdk-runtime-versions" "^1.0.0" + chalk "^4.1.2" + debug "^4.3.1" + find-up "~5.0.0" + getenv "^1.0.0" + glob "7.1.6" + resolve-from "^5.0.0" + semver "^7.5.4" + slash "^3.0.0" + slugify "^1.6.6" + xcode "^3.0.1" + xml2js "0.6.0" + "@expo/config-plugins@8.0.9", "@expo/config-plugins@~8.0.0-beta.0", "@expo/config-plugins@~8.0.8": version "8.0.9" resolved "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-8.0.9.tgz" @@ -984,7 +1088,7 @@ "@expo/config-plugins@~5.0.3": version "5.0.4" - resolved "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-5.0.4.tgz" + resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-5.0.4.tgz#216fea6558fe66615af1370de55193f4181cb23e" integrity sha512-vzUcVpqOMs3h+hyRdhGwk+eGIOhXa5xYdd92yO17RMNHav3v/+ekMbs7XA2c3lepMO8Yd4/5hqmRw9ZTL6jGzg== dependencies: "@expo/config-types" "^47.0.0" @@ -1013,6 +1117,11 @@ resolved "https://registry.npmjs.org/@expo/config-types/-/config-types-51.0.2.tgz" integrity sha512-IglkIoiDwJMY01lYkF/ZSBoe/5cR+O3+Gx6fpLFjLfgZGBTdyPkKa1g8NWoWQCk+D3cKL2MDbszT2DyRRB0YqQ== +"@expo/config-types@^51.0.3": + version "51.0.3" + resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-51.0.3.tgz#520bdce5fd75f9d234fd81bd0347443086419450" + integrity sha512-hMfuq++b8VySb+m9uNNrlpbvGxYc8OcFCUX9yTmi9tlx6A4k8SDabWFBgmnr4ao3wEArvWrtUQIfQCVtPRdpKA== + "@expo/config@9.0.3", "@expo/config@~9.0.0", "@expo/config@~9.0.0-beta.0": version "9.0.3" resolved "https://registry.npmjs.org/@expo/config/-/config-9.0.3.tgz" @@ -1030,6 +1139,23 @@ slugify "^1.3.4" sucrase "3.34.0" +"@expo/config@9.0.4": + version "9.0.4" + resolved "https://registry.yarnpkg.com/@expo/config/-/config-9.0.4.tgz#52f0a94edd0e2c36dfb5e284cc1a6d99d9d2af97" + integrity sha512-g5ns5u1JSKudHYhjo1zaSfkJ/iZIcWmUmIQptMJZ6ag1C0ShL2sj8qdfU8MmAMuKLOgcIfSaiWlQnm4X3VJVkg== + dependencies: + "@babel/code-frame" "~7.10.4" + "@expo/config-plugins" "~8.0.8" + "@expo/config-types" "^51.0.3" + "@expo/json-file" "^8.3.0" + getenv "^1.0.0" + glob "7.1.6" + require-from-string "^2.0.2" + resolve-from "^5.0.0" + semver "^7.6.0" + slugify "^1.3.4" + sucrase "3.34.0" + "@expo/config@~7.0.2": version "7.0.3" resolved "https://registry.npmjs.org/@expo/config/-/config-7.0.3.tgz" @@ -1278,6 +1404,23 @@ semver "^7.6.0" xml2js "0.6.0" +"@expo/prebuild-config@7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-7.0.9.tgz#7abd489e18ed6514a0c9cd214eb34c0d5efda799" + integrity sha512-9i6Cg7jInpnGEHN0jxnW0P+0BexnePiBzmbUvzSbRXpdXihYUX2AKMu73jgzxn5P1hXOSkzNS7umaY+BZ+aBag== + dependencies: + "@expo/config" "~9.0.0-beta.0" + "@expo/config-plugins" "~8.0.8" + "@expo/config-types" "^51.0.3" + "@expo/image-utils" "^0.5.0" + "@expo/json-file" "^8.3.0" + "@react-native/normalize-colors" "0.74.85" + debug "^4.3.1" + fs-extra "^9.0.0" + resolve-from "^5.0.0" + semver "^7.6.0" + xml2js "0.6.0" + "@expo/rudder-sdk-node@1.1.1": version "1.1.1" resolved "https://registry.npmjs.org/@expo/rudder-sdk-node/-/rudder-sdk-node-1.1.1.tgz" @@ -3183,6 +3326,11 @@ resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz" integrity sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g== +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + "@zxing/text-encoding@0.9.0": version "0.9.0" resolved "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz" @@ -3563,6 +3711,19 @@ babel-plugin-polyfill-regenerator@^0.6.1: dependencies: "@babel/helper-define-polyfill-provider" "^0.6.2" +babel-plugin-react-compiler@0.0.0-experimental-592953e-20240517: + version "0.0.0-experimental-592953e-20240517" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-592953e-20240517.tgz#e800fa1550d03573cd5637218dc711f12f642249" + integrity sha512-OjG1SVaeQZaJrqkMFJatg8W/MTow8Ak5rx2SI0ETQBO1XvOk/XZGMbltNCPdFJLKghBYoBjC+Y3Ap/Xr7B01mA== + dependencies: + "@babel/generator" "7.2.0" + "@babel/types" "^7.19.0" + chalk "4" + invariant "^2.2.4" + pretty-format "^24" + zod "^3.22.4" + zod-validation-error "^2.1.0" + babel-plugin-react-compiler@^0.0.0-experimental-592953e-20240517: version "0.0.0-experimental-7d62301-20240821" resolved "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-7d62301-20240821.tgz" @@ -3630,6 +3791,22 @@ babel-preset-expo@~11.0.14: babel-plugin-react-native-web "~0.19.10" react-refresh "^0.14.2" +babel-preset-expo@~11.0.15: + version "11.0.15" + resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-11.0.15.tgz#f29b1ac1f59f8739f63c80515906186586c24d3c" + integrity sha512-rgiMTYwqIPULaO7iZdqyL7aAff9QLOX6OWUtLZBlOrOTreGY1yHah/5+l8MvI6NVc/8Zj5LY4Y5uMSnJIuzTLw== + dependencies: + "@babel/plugin-proposal-decorators" "^7.12.9" + "@babel/plugin-transform-export-namespace-from" "^7.22.11" + "@babel/plugin-transform-object-rest-spread" "^7.12.13" + "@babel/plugin-transform-parameters" "^7.22.15" + "@babel/preset-react" "^7.22.15" + "@babel/preset-typescript" "^7.23.0" + "@react-native/babel-preset" "0.74.87" + babel-plugin-react-compiler "0.0.0-experimental-592953e-20240517" + babel-plugin-react-native-web "~0.19.10" + react-refresh "^0.14.2" + babel-preset-jest@^29.6.3: version "29.6.3" resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" @@ -3982,7 +4159,7 @@ ci-info@^2.0.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -ci-info@^3.2.0, ci-info@^3.3.0: +ci-info@^3.2.0, ci-info@^3.3.0, ci-info@^3.7.0: version "3.9.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== @@ -4456,7 +4633,7 @@ date-fns@^3.6.0: resolved "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz" integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== -dayjs@^1.11.10, dayjs@^1.8.15: +dayjs@^1.11.13, dayjs@^1.8.15: version "1.11.13" resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== @@ -5052,6 +5229,13 @@ expo-build-properties@~0.12.4: ajv "^8.11.0" semver "^7.6.0" +expo-cached-image@^51.0.19: + version "51.0.19" + resolved "https://registry.yarnpkg.com/expo-cached-image/-/expo-cached-image-51.0.19.tgz#27447d761a4b7414a2e5fee2e25c9436dd6f073e" + integrity sha512-HcIKolCKyrYcfimWp64S25Tv8YneUsKV47yJ93L4l4NVA7GJulqSS/fr2jf6B3mzw5rZNDU+eDAf1nzcxavfkg== + dependencies: + expo "51" + expo-calendar@~13.0.5: version "13.0.5" resolved "https://registry.npmjs.org/expo-calendar/-/expo-calendar-13.0.5.tgz" @@ -5196,6 +5380,19 @@ expo-modules-autolinking@1.11.2: require-from-string "^2.0.2" resolve-from "^5.0.0" +expo-modules-autolinking@1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/expo-modules-autolinking/-/expo-modules-autolinking-1.11.3.tgz#bc64d278c04015014bb5802e3cfcd942d7c07168" + integrity sha512-oYh8EZEvYF5TYppxEKUTTJmbr8j7eRRnrIxzZtMvxLTXoujThVPMFS/cbnSnf2bFm1lq50TdDNABhmEi7z0ngQ== + dependencies: + chalk "^4.1.0" + commander "^7.2.0" + fast-glob "^3.2.5" + find-up "^5.0.0" + fs-extra "^9.1.0" + require-from-string "^2.0.2" + resolve-from "^5.0.0" + expo-modules-core@1.12.24: version "1.12.24" resolved "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.12.24.tgz" @@ -5203,6 +5400,13 @@ expo-modules-core@1.12.24: dependencies: invariant "^2.2.4" +expo-modules-core@1.12.26: + version "1.12.26" + resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-1.12.26.tgz#86c4087dc6246abfc4d7f5e61097dc8cc4b22262" + integrity sha512-y8yDWjOi+rQRdO+HY+LnUlz8qzHerUaw/LUjKPU/mX8PRXP4UUPEEp5fjAwBU44xjNmYSHWZDwet4IBBE+yQUA== + dependencies: + invariant "^2.2.4" + expo-notifications@~0.28.18: version "0.28.18" resolved "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.28.18.tgz" @@ -5301,6 +5505,27 @@ expo-web-browser@~13.0.0, expo-web-browser@~13.0.3: resolved "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-13.0.3.tgz" integrity sha512-HXb7y82ApVJtqk8tManyudtTrCtx8xcUnVzmJECeHCB0SsWSQ+penVLZxJkcyATWoJOsFMnfVSVdrTcpKKGszQ== +expo@51: + version "51.0.38" + resolved "https://registry.yarnpkg.com/expo/-/expo-51.0.38.tgz#e4127b230454a34a507cfb9f1a2e4b3855cb0579" + integrity sha512-/B9npFkOPmv6WMIhdjQXEY0Z9k/67UZIVkodW8JxGIXwKUZAGHL+z1R5hTtWimpIrvVhyHUFU3f8uhfEKYhHNQ== + dependencies: + "@babel/runtime" "^7.20.0" + "@expo/cli" "0.18.30" + "@expo/config" "9.0.4" + "@expo/config-plugins" "8.0.10" + "@expo/metro-config" "0.18.11" + "@expo/vector-icons" "^14.0.3" + babel-preset-expo "~11.0.15" + expo-asset "~10.0.10" + expo-file-system "~17.0.1" + expo-font "~12.0.10" + expo-keep-awake "~13.0.2" + expo-modules-autolinking "1.11.3" + expo-modules-core "1.12.26" + fbemitter "^3.0.0" + whatwg-url-without-unicode "8.0.0-3" + expo@~51.0.24: version "51.0.34" resolved "https://registry.npmjs.org/expo/-/expo-51.0.34.tgz" @@ -5548,7 +5773,7 @@ find-up@^5.0.0, find-up@~5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-yarn-workspace-root@~2.0.0: +find-yarn-workspace-root@^2.0.0, find-yarn-workspace-root@~2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz" integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== @@ -7220,6 +7445,16 @@ json-schema-traverse@^1.0.0: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-stable-stringify@^1.0.2: + version "1.1.1" + resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz" + integrity sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg== + dependencies: + call-bind "^1.0.5" + isarray "^2.0.5" + jsonify "^0.0.1" + object-keys "^1.1.1" + json5@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" @@ -7248,6 +7483,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + jsonwebtoken@^9.0.0: version "9.0.2" resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz" @@ -7320,6 +7560,13 @@ kind-of@^6.0.0, kind-of@^6.0.1, kind-of@^6.0.2: resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" @@ -8265,7 +8512,7 @@ open@^6.2.0: dependencies: is-wsl "^1.1.0" -open@^7.0.3: +open@^7.0.3, open@^7.4.2: version "7.4.2" resolved "https://registry.npmjs.org/open/-/open-7.4.2.tgz" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== @@ -8439,6 +8686,27 @@ password-prompt@^1.0.4: ansi-escapes "^4.3.2" cross-spawn "^7.0.3" +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + ci-info "^3.7.0" + cross-spawn "^7.0.3" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + json-stable-stringify "^1.0.2" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^7.5.3" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^2.2.2" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" @@ -8564,6 +8832,11 @@ postcss@~8.4.32: picocolors "^1.0.1" source-map-js "^1.2.0" +postinstall-postinstall@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz" + integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== + pretty-bytes@5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz" @@ -8832,13 +9105,13 @@ react-native-base64@0.0.2: resolved "https://registry.npmjs.org/react-native-base64/-/react-native-base64-0.0.2.tgz" integrity sha512-Fu/J1a2y0X22EJDWqJR2oEa1fpP4gTFjYxk8ElJdt1Yak3HOXmFJ7EohLVHU2DaQkgmKfw8qb7u/48gpzveRbg== -react-native-big-calendar@^4.14.0: - version "4.14.0" - resolved "https://registry.npmjs.org/react-native-big-calendar/-/react-native-big-calendar-4.14.0.tgz" - integrity sha512-EYCxqXnRAg8QWsW3Npq3JI/9+lXlo9o6Gri7WttQQSqE/cGkVrVeKXObpvN6Cc4qrIUvnc4cgLAeM/j4+bOb6g== +react-native-big-calendar@^4.15.1: + version "4.15.1" + resolved "https://registry.npmjs.org/react-native-big-calendar/-/react-native-big-calendar-4.15.1.tgz" + integrity sha512-hNrzkM+9Kb2T0J/1fW9AMaeN+AuhakCfNtQPaQL29l3JXgOO14ikJ3iPqQkmNVbuiWYiMrpI25hrmXffiOVIgQ== dependencies: calendarize "^1.1.1" - dayjs "^1.11.10" + dayjs "^1.11.13" react-native-calendars@^1.1306.0: version "1.1306.0" @@ -8857,7 +9130,7 @@ react-native-calendars@^1.1306.0: react-native-element-dropdown@^2.12.2: version "2.12.2" - resolved "https://registry.yarnpkg.com/react-native-element-dropdown/-/react-native-element-dropdown-2.12.2.tgz#48d0c12b87591e2498c73bbde80e18374a4c262e" + resolved "https://registry.npmjs.org/react-native-element-dropdown/-/react-native-element-dropdown-2.12.2.tgz" integrity sha512-Tf8hfRuniYEXo+LGoVgIMoItKWuPLX6jbqlwAFgMbBhmWGTuV+g1OVOAx/ny16kgnwp+NhgJoWpxhVvr7HSmXA== dependencies: lodash "^4.17.21" @@ -9308,6 +9581,13 @@ rimraf@3.0.2, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@~2.6.2: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" @@ -9611,6 +9891,11 @@ sisteransi@^1.0.5: resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" @@ -10931,7 +11216,7 @@ yallist@^4.0.0: resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.2.1: +yaml@^2.2.1, yaml@^2.2.2: version "2.5.0" resolved "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz" integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==