diff --git a/apps/expo/package.json b/apps/expo/package.json index 4ff5a8d..5260680 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -42,6 +42,8 @@ "@rn-primitives/label": "^1.0.3", "@rn-primitives/portal": "^1.0.3", "@rn-primitives/progress": "^1.0.3", + "@rn-primitives/radio-group": "^1.0.3", + "@rn-primitives/select": "^1.0.4", "@rn-primitives/separator": "^1.0.3", "@rn-primitives/slot": "^1.0.3", "@rn-primitives/tooltip": "^1.0.3", diff --git a/apps/expo/src/app/(app)/(tabs)/account.tsx b/apps/expo/src/app/(app)/(tabs)/account.tsx index 5c95f14..cb8d164 100644 --- a/apps/expo/src/app/(app)/(tabs)/account.tsx +++ b/apps/expo/src/app/(app)/(tabs)/account.tsx @@ -8,6 +8,8 @@ import { import DexcomCGMData from "~/components/dexcom/dexcom-data"; import DexcomDevicesList from "~/components/dexcom/dexcom-devices"; import { DexcomLogin } from "~/components/dexcom/dexcom-login"; +import { ChangeRangeSetting } from "~/components/glucose/change-range-setting"; +import { CalculateRecap } from "~/components/glucose/create-recap"; import { ThemeToggle } from "~/components/theme-toggle"; import { Button } from "~/components/ui/button"; import { Text } from "~/components/ui/text"; @@ -41,10 +43,14 @@ export default function AccountScreen() { Account Screen {user?.id && } + + + + ); diff --git a/apps/expo/src/components/calendar/home-calendar.tsx b/apps/expo/src/components/calendar/home-calendar.tsx index 3e86697..30372d4 100644 --- a/apps/expo/src/components/calendar/home-calendar.tsx +++ b/apps/expo/src/components/calendar/home-calendar.tsx @@ -5,38 +5,44 @@ import type { import { useCallback, useMemo, useState } from "react"; import { View } from "react-native"; import { fromDateId, toDateId } from "@marceloterreiro/flash-calendar"; -import { add, endOfMonth, format, startOfMonth, sub } from "date-fns"; +import { add, sub } from "date-fns"; import { format as formatFP } from "date-fns/fp"; import { BasicCalendar } from "~/components/calendar/basic-calendar"; -import { Text } from "~/components/ui/text"; +import { Progress } from "~/components/ui/progress"; import { useDateStore } from "~/stores/date-store"; import { useGlucoseStore } from "~/stores/glucose-store"; import { api } from "~/utils/api"; export function HomeCalendar() { - const { selectedDate, setSelectedDate, setIsCalendarOpen } = useDateStore(); + const { + selectedDate, + setSelectedDate, + setIsCalendarOpen, + updateVisibleDates, + } = useDateStore(); const { rangeView } = useGlucoseStore(); const [currentCalendarMonth, setCurrentCalendarMonth] = useState(selectedDate); - const startDate = startOfMonth(selectedDate); - const endDate = endOfMonth(selectedDate); - - const { data: dailyRecaps, isPending } = api.recap.getDailyRecaps.useQuery({ - startDate: format(startDate, "yyyy-MM-dd"), - endDate: format(endDate, "yyyy-MM-dd"), - }); + const { data: allRecaps, isPending } = api.recap.all.useQuery(); const currentDate = new Date(); + const minDate = allRecaps + ? new Date( + Math.min(...allRecaps.map((recap) => new Date(recap.date).getTime())), + ) + : new Date("2024-08-01"); const handleDayPress = useCallback( (dateId) => { - setCurrentCalendarMonth(fromDateId(dateId)); - setSelectedDate(fromDateId(dateId)); + const newDate = fromDateId(dateId); + setCurrentCalendarMonth(newDate); + setSelectedDate(newDate); + updateVisibleDates(newDate); setIsCalendarOpen(false); // Close the dialog after selecting a date }, - [setSelectedDate, setIsCalendarOpen], + [setSelectedDate, setIsCalendarOpen, updateVisibleDates], ); const calendarActiveDateRanges = useMemo( @@ -57,16 +63,12 @@ export function HomeCalendar() { setCurrentCalendarMonth(add(currentCalendarMonth, { months: 1 })); }, [currentCalendarMonth]); - if (isPending) { - return Loading...; - } - return ( + {isPending && } ); } diff --git a/apps/expo/src/components/glucose/change-range-setting.tsx b/apps/expo/src/components/glucose/change-range-setting.tsx new file mode 100644 index 0000000..27d2b68 --- /dev/null +++ b/apps/expo/src/components/glucose/change-range-setting.tsx @@ -0,0 +1,77 @@ +import React from "react"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; + +import type { GlucoseRangeTypes } from "@hyper/db/schema"; + +import { Label } from "~/components/ui/label"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from "~/components/ui/select"; +import { useGlucoseStore } from "~/stores/glucose-store"; + +interface RangeOption { + value: GlucoseRangeTypes; + label: string; +} + +function ChangeRangeSetting() { + const insets = useSafeAreaInsets(); + const contentInsets = { + top: insets.top, + bottom: insets.bottom, + left: insets.left, + right: insets.right, + }; + + const { rangeView, setRangeView } = useGlucoseStore(); + + console.log(rangeView); + + const capitalizeFirstLetter = (string: string) => { + return string.charAt(0).toUpperCase() + string.slice(1); + }; + + const rangeOptions: RangeOption[] = [ + { value: "standard", label: capitalizeFirstLetter("standard") }, + { value: "tight", label: capitalizeFirstLetter("tight") }, + { value: "optimal", label: capitalizeFirstLetter("optimal") }, + ]; + + const currentOption = + rangeOptions.find((option) => option.value === rangeView) ?? + rangeOptions[0]; + + return ( + <> + + + + ); +} + +export { ChangeRangeSetting }; diff --git a/apps/expo/src/components/glucose/create-recap.tsx b/apps/expo/src/components/glucose/create-recap.tsx new file mode 100644 index 0000000..975216f --- /dev/null +++ b/apps/expo/src/components/glucose/create-recap.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { Alert, View } from "react-native"; + +import { Button } from "~/components/ui/button"; +import { Text } from "~/components/ui/text"; +import { api } from "~/utils/api"; + +const CalculateRecap: React.FC = () => { + const utils = api.useUtils(); + + const mutation = api.recap.calculateAndStoreRecapsForRange.useMutation({ + onSuccess: async (data) => { + Alert.alert( + "Success", + `Recaps calculated and stored successfully for ${data.length} days.`, + ); + await utils.recap.getDailyRecaps.invalidate(); + }, + onError: (error) => { + Alert.alert("Error", `Failed to calculate recaps: ${error.message}`); + }, + }); + + const handleCalculateRecaps = () => { + const augustStart = new Date("2024-08-01T00:00:00Z"); + const augustEnd = new Date("2024-08-31T23:59:59Z"); + + const queryInput = { + startDate: augustStart.toISOString(), + endDate: augustEnd.toISOString(), + }; + + mutation.mutate(queryInput); + }; + + return ( + + + {mutation.isError ? ( + An error occurred: {mutation.error.message} + ) : null} + {mutation.isSuccess ? ( + Last calculated: {new Date().toLocaleString()} + ) : null} + + ); +}; + +export { CalculateRecap }; diff --git a/apps/expo/src/components/home/day-slider.tsx b/apps/expo/src/components/home/day-slider.tsx index 16ec181..28f556e 100644 --- a/apps/expo/src/components/home/day-slider.tsx +++ b/apps/expo/src/components/home/day-slider.tsx @@ -1,10 +1,11 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react"; import { Dimensions, Pressable, View } from "react-native"; import { FlashList } from "@shopify/flash-list"; -import { endOfDay, format, startOfDay } from "date-fns"; +import { format } from "date-fns"; import type { DailyRecap, GlucoseRangeTypes } from "@hyper/db/schema"; +import { Skeleton } from "~/components/ui/skeleton"; import { Text } from "~/components/ui/text"; import { useColorScheme } from "~/lib/use-color-scheme"; import { cn, getGlucoseRangeColors } from "~/lib/utils"; @@ -19,23 +20,24 @@ const centerOffset = (screenWidth - itemWidth) / 2; const DayItem = React.memo( ({ - item, + date, + recap, isSelected, onPress, isDark, rangeView, + isLoading, }: { - item: DailyRecap; + date: Date; + recap?: DailyRecap; isSelected: boolean; onPress: () => void; isDark: boolean; rangeView: GlucoseRangeTypes; + isLoading: boolean; }) => { - const date = new Date(item.date); - const glucoseColors = getGlucoseRangeColors( - item.timeInRanges?.[rangeView] ?? 0, - isDark, - ); + const timeInRange = recap?.timeInRanges?.[rangeView] ?? 0; + const glucoseColors = getGlucoseRangeColors(timeInRange, isDark); return ( @@ -56,21 +58,25 @@ const DayItem = React.memo( - - + ) : ( + - {item.timeInRanges?.[rangeView] ?? "?"} - - + + {Math.floor(timeInRange)} + + + )} ); @@ -78,30 +84,21 @@ const DayItem = React.memo( ); export function DaySlider() { - const { selectedDate, setSelectedDate } = useDateStore(); + const { selectedDate, setSelectedDate, visibleDates } = useDateStore(); const { rangeView } = useGlucoseStore(); - const listRef = useRef | null>(null); + const listRef = useRef | null>(null); const { colorScheme } = useColorScheme(); const isDark = colorScheme === "dark"; - // Fetch data for the last 30 days - const endDate = endOfDay(new Date()); - const startDate = startOfDay( - new Date(endDate.getTime() - 29 * 24 * 60 * 60 * 1000), - ); - - const { data: dailyRecaps, isPending } = api.recap.getDailyRecaps.useQuery({ - startDate: startDate.toISOString(), - endDate: endDate.toISOString(), - }); + const { data: allRecaps, isPending } = api.recap.all.useQuery(); - const sortedData = useMemo(() => { - return dailyRecaps - ? [...dailyRecaps].sort( - (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(), - ) - : []; - }, [dailyRecaps]); + const recapsMap = useMemo(() => { + const map = new Map(); + allRecaps?.forEach((recap) => { + map.set(new Date(recap.date).toDateString(), recap); + }); + return map; + }, [allRecaps]); // const scrollToIndex = useCallback((index: number) => { // listRef.current?.scrollToIndex({ @@ -120,55 +117,50 @@ export function DaySlider() { }, []); const scrollToSelectedDate = useCallback(() => { - const selectedIndex = sortedData.findIndex( - (item) => - new Date(item.date).toDateString() === selectedDate.toDateString(), + const selectedIndex = visibleDates.findIndex( + (date) => date.toDateString() === selectedDate.toDateString(), ); if (selectedIndex !== -1) { // scrollToIndex(selectedIndex); scrollToOffset(selectedIndex); } - }, [selectedDate, scrollToOffset, sortedData]); + }, [selectedDate, scrollToOffset, visibleDates]); useEffect(() => { scrollToSelectedDate(); }, [selectedDate, scrollToSelectedDate]); const renderItem = useCallback( - ({ item }: { item: DailyRecap }) => { - const itemDate = new Date(item.date); - const isSelected = - itemDate.toDateString() === selectedDate.toDateString(); + ({ item: date }: { item: Date }) => { + const isSelected = date.toDateString() === selectedDate.toDateString(); + const recap = recapsMap.get(date.toDateString()); + const isLoading = !recap && isPending; + return ( { - setSelectedDate(itemDate); + setSelectedDate(date); }} isDark={isDark} rangeView={rangeView} + isLoading={isLoading} /> ); }, - [selectedDate, setSelectedDate, isDark, rangeView], - ); - - const keyExtractor = useCallback( - (item: DailyRecap) => item.date.toDateString(), - [], + [selectedDate, setSelectedDate, isDark, rangeView, recapsMap, isPending], ); - if (isPending) { - return Loading...; - } + const keyExtractor = useCallback((date: Date) => date.toDateString(), []); return ( , + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + return ( + + ); +}); +RadioGroup.displayName = RadioGroupPrimitive.Root.displayName; + +const RadioGroupItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + return ( + + + + + + ); +}); +RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName; + +export { RadioGroup, RadioGroupItem }; diff --git a/apps/expo/src/components/ui/select.tsx b/apps/expo/src/components/ui/select.tsx new file mode 100644 index 0000000..61e3812 --- /dev/null +++ b/apps/expo/src/components/ui/select.tsx @@ -0,0 +1,199 @@ +import * as React from "react"; +import { Platform, StyleSheet, View } from "react-native"; +import Animated, { FadeIn, FadeOut } from "react-native-reanimated"; +import * as SelectPrimitive from "@rn-primitives/select"; + +import { Check } from "~/lib/icons/check"; +import { ChevronDown } from "~/lib/icons/chevron-down"; +import { ChevronUp } from "~/lib/icons/chevron-up"; +import { cn } from "~/lib/utils"; + +type Option = SelectPrimitive.Option; + +const Select = SelectPrimitive.Root; + +const SelectGroup = SelectPrimitive.Group; + +const SelectValue = SelectPrimitive.Value; + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + props.disabled && "web:cursor-not-allowed opacity-50", + className, + )} + {...props} + > + <>{children} + + +)); +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; + +/** + * Platform: WEB ONLY + */ +const SelectScrollUpButton = ({ + className, + ...props +}: React.ComponentPropsWithoutRef) => { + if (Platform.OS !== "web") { + return null; + } + return ( + + + + ); +}; + +/** + * Platform: WEB ONLY + */ +const SelectScrollDownButton = ({ + className, + ...props +}: React.ComponentPropsWithoutRef) => { + if (Platform.OS !== "web") { + return null; + } + return ( + + + + ); +}; + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + portalHost?: string; + } +>(({ className, children, position = "popper", portalHost, ...props }, ref) => { + const { open } = SelectPrimitive.useRootContext(); + + return ( + + + + + + + + {children} + + + + + + + + ); +}); +SelectContent.displayName = SelectPrimitive.Content.displayName; + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectLabel.displayName = SelectPrimitive.Label.displayName; + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + + + +)); +SelectItem.displayName = SelectPrimitive.Item.displayName; + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectSeparator.displayName = SelectPrimitive.Separator.displayName; + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, + type Option, +}; diff --git a/apps/expo/src/lib/icons/check.tsx b/apps/expo/src/lib/icons/check.tsx new file mode 100644 index 0000000..f9cd296 --- /dev/null +++ b/apps/expo/src/lib/icons/check.tsx @@ -0,0 +1,6 @@ +import { Check } from "lucide-react-native"; + +import { iconWithClassName } from "~/lib/icons/icon-with-classname"; + +iconWithClassName(Check); +export { Check }; diff --git a/apps/expo/src/lib/icons/chevron-down.tsx b/apps/expo/src/lib/icons/chevron-down.tsx new file mode 100644 index 0000000..51afc9b --- /dev/null +++ b/apps/expo/src/lib/icons/chevron-down.tsx @@ -0,0 +1,6 @@ +import { ChevronDown } from "lucide-react-native"; + +import { iconWithClassName } from "~/lib/icons/icon-with-classname"; + +iconWithClassName(ChevronDown); +export { ChevronDown }; diff --git a/apps/expo/src/lib/icons/chevron-up.tsx b/apps/expo/src/lib/icons/chevron-up.tsx new file mode 100644 index 0000000..ba5971e --- /dev/null +++ b/apps/expo/src/lib/icons/chevron-up.tsx @@ -0,0 +1,6 @@ +import { ChevronUp } from "lucide-react-native"; + +import { iconWithClassName } from "~/lib/icons/icon-with-classname"; + +iconWithClassName(ChevronUp); +export { ChevronUp }; diff --git a/apps/expo/src/stores/date-store.ts b/apps/expo/src/stores/date-store.ts index ce10176..158b9b7 100644 --- a/apps/expo/src/stores/date-store.ts +++ b/apps/expo/src/stores/date-store.ts @@ -1,3 +1,4 @@ +import { addDays, isAfter, isBefore, isSameDay, subDays } from "date-fns"; import { create } from "zustand"; interface DateState { @@ -5,13 +6,42 @@ interface DateState { setSelectedDate: (date: Date) => void; isCalendarOpen: boolean; setIsCalendarOpen: (isOpen: boolean) => void; + visibleDates: Date[]; + updateVisibleDates: (date: Date) => void; } +const generateInitialDates = () => { + const today = new Date(); + return Array.from({ length: 30 }, (_, i) => subDays(today, i)); +}; + +const generateDatesOutsideRange = (centerDate: Date) => { + const endDate = addDays(centerDate, 15); + return Array.from({ length: 31 }, (_, i) => subDays(endDate, i)); +}; + export const useDateStore = create((set) => ({ selectedDate: new Date(), setSelectedDate: (date: Date) => set({ selectedDate: date }), isCalendarOpen: false, setIsCalendarOpen: (isOpen: boolean) => set({ isCalendarOpen: isOpen }), + visibleDates: generateInitialDates(), + updateVisibleDates: (date: Date) => + set(() => { + const today = new Date(); + const thirtyDaysAgo = subDays(today, 30); + + if ( + isSameDay(date, today) || + (isBefore(date, today) && isAfter(date, thirtyDaysAgo)) + ) { + // Case 1: Date is within the last 30 days or is today + return { visibleDates: generateInitialDates() }; + } else { + // Case 2: Date is outside the last 30 days + return { visibleDates: generateDatesOutsideRange(date) }; + } + }), })); // Example persist-middleware with MMKV diff --git a/apps/expo/src/stores/glucose-store.ts b/apps/expo/src/stores/glucose-store.ts index bdab835..a2f9ddf 100644 --- a/apps/expo/src/stores/glucose-store.ts +++ b/apps/expo/src/stores/glucose-store.ts @@ -1,16 +1,14 @@ import { create } from "zustand"; import { createJSONStorage, persist } from "zustand/middleware"; -import { GlucoseRangeTypes } from "@hyper/db/schema"; +import type { GlucoseRangeTypes } from "@hyper/db/schema"; import { zustandStorage } from "~/lib/storage"; -type RangeView = "standard" | "tight" | "optimal"; - interface GlucoseState { rangeView: GlucoseRangeTypes; lastSyncedTime: Date | null; - setRangeView: (view: RangeView) => void; + setRangeView: (view: GlucoseRangeTypes) => void; setLastSyncedTime: (date: Date) => void; } diff --git a/package.json b/package.json index 1ed466b..bd6ba01 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "build": "turbo run build", "clean": "git clean -xdf node_modules", "clean:workspaces": "turbo run clean", + "daemon:restart": "turbo daemon restart", "db:generate": "turbo -F @hyper/db dk-generate", "db:migrate": "turbo -F @hyper/db migrate", "db:push": "turbo -F @hyper/db push", diff --git a/packages/api/src/router/recap.ts b/packages/api/src/router/recap.ts index 8a4d142..46f2001 100644 --- a/packages/api/src/router/recap.ts +++ b/packages/api/src/router/recap.ts @@ -24,6 +24,17 @@ import { } from "../utils/glucose"; export const recapRouter = { + all: protectedProcedure.query(async ({ ctx }) => { + const userId = ctx.user.id; + + const rows = await ctx.db.query.DailyRecap.findMany({ + where: eq(DailyRecap.profileId, userId), + orderBy: desc(DailyRecap.date), + }); + + return rows; + }), + getDailyRecaps: protectedProcedure .input(DateRangeSchema) .query(async ({ ctx, input }) => { diff --git a/packages/db/migrations/0005_stiff_landau.sql b/packages/db/migrations/0005_stiff_landau.sql new file mode 100644 index 0000000..8e29902 --- /dev/null +++ b/packages/db/migrations/0005_stiff_landau.sql @@ -0,0 +1,6 @@ +CREATE INDEX IF NOT EXISTS "cgm_data_profile_id_idx" ON "hyper_cgm_data" USING btree ("profile_id");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "cgm_data_record_id_idx" ON "hyper_cgm_data" USING btree ("record_id");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "daily_recap_profile_id_date_idx" ON "hyper_daily_recap" USING btree ("profile_id","date");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "name_idx" ON "hyper_profile" USING btree ("name");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "email_idx" ON "hyper_profile" USING btree ("email");--> statement-breakpoint +ALTER TABLE "hyper_daily_recap" ADD CONSTRAINT "hyper_daily_recap_date_profile_id_unique" UNIQUE("date","profile_id"); \ No newline at end of file diff --git a/packages/db/migrations/meta/0005_snapshot.json b/packages/db/migrations/meta/0005_snapshot.json new file mode 100644 index 0000000..81cd2a3 --- /dev/null +++ b/packages/db/migrations/meta/0005_snapshot.json @@ -0,0 +1,712 @@ +{ + "id": "967d30c3-8ae0-4d29-af92-6bc8e1648548", + "prevId": "0156dd1e-57ec-4f08-b9dc-534abd95681f", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.hyper_activity": { + "name": "hyper_activity", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "duration": { + "name": "duration", + "type": "interval", + "primaryKey": false, + "notNull": true + }, + "activity_type_id": { + "name": "activity_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hyper_activity_activity_type_id_hyper_activity_type_id_fk": { + "name": "hyper_activity_activity_type_id_hyper_activity_type_id_fk", + "tableFrom": "hyper_activity", + "tableTo": "hyper_activity_type", + "columnsFrom": [ + "activity_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "hyper_activity_profile_id_hyper_profile_id_fk": { + "name": "hyper_activity_profile_id_hyper_profile_id_fk", + "tableFrom": "hyper_activity", + "tableTo": "hyper_profile", + "columnsFrom": [ + "profile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.hyper_activity_type": { + "name": "hyper_activity_type", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hyper_activity_type_name_unique": { + "name": "hyper_activity_type_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "auth.users": { + "name": "users", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.hyper_cgm_data": { + "name": "hyper_cgm_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "dexcom_user_id": { + "name": "dexcom_user_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "record_id": { + "name": "record_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "system_time": { + "name": "system_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "display_time": { + "name": "display_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "transmitter_id": { + "name": "transmitter_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "transmitter_ticks": { + "name": "transmitter_ticks", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "glucose_value": { + "name": "glucose_value", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "trend": { + "name": "trend", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "trend_rate": { + "name": "trend_rate", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "unit": { + "name": "unit", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "rate_unit": { + "name": "rate_unit", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "display_device": { + "name": "display_device", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "transmitter_generation": { + "name": "transmitter_generation", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "cgm_data_profile_id_idx": { + "name": "cgm_data_profile_id_idx", + "columns": [ + { + "expression": "profile_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "cgm_data_record_id_idx": { + "name": "cgm_data_record_id_idx", + "columns": [ + { + "expression": "record_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "hyper_cgm_data_profile_id_hyper_profile_id_fk": { + "name": "hyper_cgm_data_profile_id_hyper_profile_id_fk", + "tableFrom": "hyper_cgm_data", + "tableTo": "hyper_profile", + "columnsFrom": [ + "profile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hyper_cgm_data_record_id_unique": { + "name": "hyper_cgm_data_record_id_unique", + "nullsNotDistinct": false, + "columns": [ + "record_id" + ] + } + } + }, + "public.hyper_daily_recap": { + "name": "hyper_daily_recap", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "average_glucose": { + "name": "average_glucose", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "minimum_glucose": { + "name": "minimum_glucose", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "maximum_glucose": { + "name": "maximum_glucose", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "glucose_variability": { + "name": "glucose_variability", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "time_in_ranges": { + "name": "time_in_ranges", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "total_readings": { + "name": "total_readings", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "daily_recap_profile_id_date_idx": { + "name": "daily_recap_profile_id_date_idx", + "columns": [ + { + "expression": "profile_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "hyper_daily_recap_profile_id_hyper_profile_id_fk": { + "name": "hyper_daily_recap_profile_id_hyper_profile_id_fk", + "tableFrom": "hyper_daily_recap", + "tableTo": "hyper_profile", + "columnsFrom": [ + "profile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hyper_daily_recap_date_profile_id_unique": { + "name": "hyper_daily_recap_date_profile_id_unique", + "nullsNotDistinct": false, + "columns": [ + "date", + "profile_id" + ] + } + } + }, + "public.hyper_profile": { + "name": "hyper_profile", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "last_synced_time": { + "name": "last_synced_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "diabetes_status": { + "name": "diabetes_status", + "type": "diabetes_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "glucose_range_type": { + "name": "glucose_range_type", + "type": "glucose_range_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'tight'" + } + }, + "indexes": { + "name_idx": { + "name": "name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "email_idx": { + "name": "email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "hyper_profile_id_users_id_fk": { + "name": "hyper_profile_id_users_id_fk", + "tableFrom": "hyper_profile", + "tableTo": "users", + "schemaTo": "auth", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.hyper_meal": { + "name": "hyper_meal", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "meal_time": { + "name": "meal_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "carbohydrates": { + "name": "carbohydrates", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "dietary_energy": { + "name": "dietary_energy", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "dietary_sugar": { + "name": "dietary_sugar", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "fiber": { + "name": "fiber", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "protein": { + "name": "protein", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "total_fat": { + "name": "total_fat", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hyper_meal_profile_id_hyper_profile_id_fk": { + "name": "hyper_meal_profile_id_hyper_profile_id_fk", + "tableFrom": "hyper_meal", + "tableTo": "hyper_profile", + "columnsFrom": [ + "profile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.hyper_report": { + "name": "hyper_report", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "profile_id": { + "name": "profile_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hyper_report_profile_id_hyper_profile_id_fk": { + "name": "hyper_report_profile_id_hyper_profile_id_fk", + "tableFrom": "hyper_report", + "tableTo": "hyper_profile", + "columnsFrom": [ + "profile_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "public.diabetes_status": { + "name": "diabetes_status", + "schema": "public", + "values": [ + "none", + "pre", + "type1", + "type2", + "type3" + ] + }, + "public.glucose_range_type": { + "name": "glucose_range_type", + "schema": "public", + "values": [ + "standard", + "tight", + "optimal" + ] + } + }, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 5cf8622..7836916 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -36,6 +36,13 @@ "when": 1725518765059, "tag": "0004_true_doctor_strange", "breakpoints": true + }, + { + "idx": 5, + "version": "7", + "when": 1725660493714, + "tag": "0005_stiff_landau", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/src/schema/cgm-data.ts b/packages/db/src/schema/cgm-data.ts index f3f39da..01ea39a 100644 --- a/packages/db/src/schema/cgm-data.ts +++ b/packages/db/src/schema/cgm-data.ts @@ -1,8 +1,10 @@ import { relations } from "drizzle-orm"; import { doublePrecision, + index, integer, timestamp, + uniqueIndex, uuid, varchar, } from "drizzle-orm/pg-core"; @@ -12,35 +14,44 @@ import { z } from "zod"; import { createTable } from "./_table"; import { Profile } from "./profile"; -export const CGMData = createTable("cgm_data", { - id: uuid("id").primaryKey().defaultRandom(), - dexcomUserId: varchar("dexcom_user_id", { length: 255 }).notNull(), - recordId: varchar("record_id", { length: 255 }).notNull().unique(), - systemTime: timestamp("system_time", { withTimezone: true }).notNull(), - displayTime: timestamp("display_time", { withTimezone: true }).notNull(), - transmitterId: varchar("transmitter_id", { length: 255 }), - transmitterTicks: integer("transmitter_ticks").notNull(), - glucoseValue: integer("glucose_value"), - status: varchar("status", { length: 20 }), - trend: varchar("trend", { length: 20 }), - trendRate: doublePrecision("trend_rate"), - unit: varchar("unit", { length: 10 }).notNull(), - rateUnit: varchar("rate_unit", { length: 20 }).notNull(), - displayDevice: varchar("display_device", { length: 20 }).notNull(), - transmitterGeneration: varchar("transmitter_generation", { - length: 20, - }).notNull(), +export const CGMData = createTable( + "cgm_data", + { + id: uuid("id").primaryKey().defaultRandom(), + dexcomUserId: varchar("dexcom_user_id", { length: 255 }).notNull(), + recordId: varchar("record_id", { length: 255 }).notNull().unique(), + systemTime: timestamp("system_time", { withTimezone: true }).notNull(), + displayTime: timestamp("display_time", { withTimezone: true }).notNull(), + transmitterId: varchar("transmitter_id", { length: 255 }), + transmitterTicks: integer("transmitter_ticks").notNull(), + glucoseValue: integer("glucose_value"), + status: varchar("status", { length: 20 }), + trend: varchar("trend", { length: 20 }), + trendRate: doublePrecision("trend_rate"), + unit: varchar("unit", { length: 10 }).notNull(), + rateUnit: varchar("rate_unit", { length: 20 }).notNull(), + displayDevice: varchar("display_device", { length: 20 }).notNull(), + transmitterGeneration: varchar("transmitter_generation", { + length: 20, + }).notNull(), - profileId: uuid("profile_id") - .notNull() - .references(() => Profile.id), + profileId: uuid("profile_id") + .notNull() + .references(() => Profile.id), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updatedAt", { - mode: "date", - withTimezone: true, - }).$onUpdateFn(() => new Date()), -}); + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updatedAt", { + mode: "date", + withTimezone: true, + }).$onUpdateFn(() => new Date()), + }, + (table) => { + return { + profileIdIdx: index("cgm_data_profile_id_idx").on(table.profileId), + recordIdIdx: uniqueIndex("cgm_data_record_id_idx").on(table.recordId), + }; + }, +); export const CGMDataRelations = relations(CGMData, ({ one }) => ({ profile: one(Profile, { diff --git a/packages/db/src/schema/daily-recap.ts b/packages/db/src/schema/daily-recap.ts index 48e7ac8..a9c7d76 100644 --- a/packages/db/src/schema/daily-recap.ts +++ b/packages/db/src/schema/daily-recap.ts @@ -6,6 +6,8 @@ import { jsonb, numeric, timestamp, + unique, + uniqueIndex, uuid, } from "drizzle-orm/pg-core"; import { createInsertSchema, createSelectSchema } from "drizzle-zod"; @@ -27,26 +29,41 @@ export interface TimeInRanges { veryHigh: number; // >250 mg/dL and <5% } -export const DailyRecap = createTable("daily_recap", { - id: uuid("id").primaryKey().defaultRandom(), - date: date("date", { mode: "date" }).notNull(), - averageGlucose: integer("average_glucose"), - minimumGlucose: integer("minimum_glucose"), - maximumGlucose: integer("maximum_glucose"), - glucoseVariability: numeric("glucose_variability"), // Standard deviation or coefficient of variation - timeInRanges: jsonb("time_in_ranges").$type(), - totalReadings: integer("total_readings"), +export const DailyRecap = createTable( + "daily_recap", + { + id: uuid("id").primaryKey().defaultRandom(), + date: date("date", { mode: "date" }).notNull(), + averageGlucose: integer("average_glucose"), + minimumGlucose: integer("minimum_glucose"), + maximumGlucose: integer("maximum_glucose"), + glucoseVariability: numeric("glucose_variability"), // Standard deviation or coefficient of variation + timeInRanges: jsonb("time_in_ranges").$type(), + totalReadings: integer("total_readings"), - profileId: uuid("profile_id") - .notNull() - .references(() => Profile.id), + profileId: uuid("profile_id") + .notNull() + .references(() => Profile.id), - createdAt: timestamp("created_at").defaultNow().notNull(), - updatedAt: timestamp("updatedAt", { - mode: "date", - withTimezone: true, - }).$onUpdateFn(() => new Date()), -}); + createdAt: timestamp("created_at").defaultNow().notNull(), + updatedAt: timestamp("updatedAt", { + mode: "date", + withTimezone: true, + }).$onUpdateFn(() => new Date()), + }, + (table) => { + return { + profileIdDateIdx: uniqueIndex("daily_recap_profile_id_date_idx").on( + table.profileId, + table.date, + ), + // This unique constraint allows for efficient upserts + // It ensures only one recap per day per profile + // and enables the use of ON CONFLICT for updates + dateProfileUnique: unique().on(table.date, table.profileId), + }; + }, +); export const DailyRecapRelations = relations(DailyRecap, ({ one }) => ({ profile: one(Profile, { diff --git a/packages/db/src/schema/profile.ts b/packages/db/src/schema/profile.ts index c9da1dd..cdb97ae 100644 --- a/packages/db/src/schema/profile.ts +++ b/packages/db/src/schema/profile.ts @@ -1,5 +1,12 @@ import { relations } from "drizzle-orm"; -import { pgEnum, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; +import { + index, + pgEnum, + timestamp, + uniqueIndex, + uuid, + varchar, +} from "drizzle-orm/pg-core"; import { createTable } from "./_table"; import { Users } from "./auth"; @@ -22,22 +29,31 @@ const diabetesStatus = ["none", "pre", "type1", "type2", "type3"] as const; export type DiabetesStatus = (typeof diabetesStatus)[number]; export const diabetesStatusEnum = pgEnum("diabetes_status", diabetesStatus); -export const Profile = createTable("profile", { - // Matches id from auth.users table in Supabase - id: uuid("id") - .primaryKey() - .references(() => Users.id, { onDelete: "cascade" }), - name: varchar("name", { length: 256 }).notNull(), - image: varchar("image", { length: 256 }), - email: varchar("email", { length: 256 }), - lastSyncedTime: timestamp("last_synced_time", { withTimezone: true }), - diabetesStatus: diabetesStatusEnum("diabetes_status") - .notNull() - .default("none"), - glucoseRangeType: glucoseRangeTypeEnum("glucose_range_type") - .notNull() - .default("tight"), -}); +export const Profile = createTable( + "profile", + { + // Matches id from auth.users table in Supabase + id: uuid("id") + .primaryKey() + .references(() => Users.id, { onDelete: "cascade" }), + name: varchar("name", { length: 256 }).notNull(), + image: varchar("image", { length: 256 }), + email: varchar("email", { length: 256 }), + lastSyncedTime: timestamp("last_synced_time", { withTimezone: true }), + diabetesStatus: diabetesStatusEnum("diabetes_status") + .notNull() + .default("none"), + glucoseRangeType: glucoseRangeTypeEnum("glucose_range_type") + .notNull() + .default("tight"), + }, + (table) => { + return { + nameIdx: index("name_idx").on(table.name), + emailIdx: uniqueIndex("email_idx").on(table.email), + }; + }, +); export const ProfileRelations = relations(Profile, ({ many }) => ({ cgmData: many(CGMData), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 873ef6b..b9e21fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,11 +51,11 @@ catalogs: specifier: ^0.5.0 version: 0.5.0 '@supabase/ssr': - specifier: ^0.5.0 - version: 0.5.0 + specifier: ^0.5.1 + version: 0.5.1 '@supabase/supabase-js': - specifier: ^2.45.2 - version: 2.45.2 + specifier: ^2.45.3 + version: 2.45.3 tailwind: tailwindcss: specifier: ^3.4.10 @@ -152,6 +152,12 @@ importers: '@rn-primitives/progress': specifier: ^1.0.3 version: 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + '@rn-primitives/radio-group': + specifier: ^1.0.3 + version: 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + '@rn-primitives/select': + specifier: ^1.0.4 + version: 1.0.4(@rn-primitives/portal@1.0.3(@types/react@18.3.4)(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1))(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) '@rn-primitives/separator': specifier: ^1.0.3 version: 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) @@ -175,10 +181,10 @@ importers: version: 1.3.11(react-native-reanimated@3.15.1(@babel/core@7.25.2)(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) '@supabase/auth-helpers-react': specifier: catalog:supabase - version: 0.5.0(@supabase/supabase-js@2.45.2(bufferutil@4.0.8)) + version: 0.5.0(@supabase/supabase-js@2.45.3(bufferutil@4.0.8)) '@supabase/supabase-js': specifier: catalog:supabase - version: 2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + version: 2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@tanstack/react-query': specifier: 'catalog:' version: 5.52.1(react@18.3.1) @@ -484,10 +490,10 @@ importers: version: link:../../packages/validators '@supabase/ssr': specifier: catalog:supabase - version: 0.5.0(@supabase/supabase-js@2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4)) + version: 0.5.1(@supabase/supabase-js@2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)) '@supabase/supabase-js': specifier: catalog:supabase - version: 2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + version: 2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@t3-oss/env-nextjs': specifier: ^0.11.1 version: 0.11.1(typescript@5.5.4)(zod@3.23.8) @@ -602,7 +608,7 @@ importers: version: link:../validators '@supabase/supabase-js': specifier: catalog:supabase - version: 2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + version: 2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@trpc/server': specifier: 'catalog:' version: 11.0.0-rc.485 @@ -810,7 +816,7 @@ importers: version: 7.35.0(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-react-hooks: specifier: rc - version: 5.1.0-rc-d1afcb43-20240903(eslint@9.9.1(jiti@1.21.6)) + version: 5.1.0-rc-a03254bc-20240905(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-testing-library: specifier: ^6.3.0 version: 6.3.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.5.4) @@ -3042,6 +3048,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-radio-group@1.2.0': + resolution: {integrity: sha512-yv+oiLaicYMBpqgfpSPw6q+RyXlLdIpQWDHZbUKURxe+nEh53hFXPPlfhfQQtYkS5MMK/5IWIa76SksleQZSzw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-roving-focus@1.1.0': resolution: {integrity: sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==} peerDependencies: @@ -3068,6 +3087,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-select@2.1.1': + resolution: {integrity: sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-separator@1.1.0': resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==} peerDependencies: @@ -3214,6 +3246,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-previous@1.1.0': + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-rect@1.1.0': resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} peerDependencies: @@ -3552,6 +3593,31 @@ packages: react-native-web: optional: true + '@rn-primitives/radio-group@1.0.3': + resolution: {integrity: sha512-VIuWiz2WAM1SbCQJThZ/3S2naAXO+ijgROBCbCKcp3H32G0rHn/9M8GReijb8vdqVPuM+CFdoF1DBI2uPyQVDw==} + peerDependencies: + react: '*' + react-native: '*' + react-native-web: '*' + peerDependenciesMeta: + react-native: + optional: true + react-native-web: + optional: true + + '@rn-primitives/select@1.0.4': + resolution: {integrity: sha512-n1qTOjwYgATIEdKC7/Ox5Kjr4zi8zYxAaW0tyh0N16qvWCH2gjAEytvbIimZC/Gn+Q6NiqGparv9jxH5myZW4g==} + peerDependencies: + '@rn-primitives/portal': '*' + react: '*' + react-native: '*' + react-native-web: '*' + peerDependenciesMeta: + react-native: + optional: true + react-native-web: + optional: true + '@rn-primitives/separator@1.0.3': resolution: {integrity: sha512-8X6NS78hCUeJSs3CeVMnK6ndVX+W+Gb07qP/xY0KfKpILXIEbpnyicWR1oMpt32dTbMmBJAptLJKdcj+s4Fq+A==} peerDependencies: @@ -3617,11 +3683,6 @@ packages: resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} engines: {node: '>=14.15'} - '@rollup/rollup-linux-x64-gnu@4.21.0': - resolution: {integrity: sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==} - cpu: [x64] - os: [linux] - '@scena/dragscroll@1.4.0': resolution: {integrity: sha512-3O8daaZD9VXA9CP3dra6xcgt/qrm0mg0xJCwiX6druCteQ9FFsXffkF8PrqxY4Z4VJ58fFKEa0RlKqbsi/XnRA==} @@ -3677,8 +3738,8 @@ packages: peerDependencies: '@supabase/supabase-js': ^2.39.8 - '@supabase/auth-js@2.64.4': - resolution: {integrity: sha512-9ITagy4WP4FLl+mke1rchapOH0RQpf++DI+WSG2sO1OFOZ0rW3cwAM0nCrMOxu+Zw4vJ4zObc08uvQrXx590Tg==} + '@supabase/auth-js@2.65.0': + resolution: {integrity: sha512-+wboHfZufAE2Y612OsKeVP4rVOeGZzzMLD/Ac3HrTQkkY4qXNjI6Af9gtmxwccE5nFvTiF114FEbIQ1hRq5uUw==} '@supabase/functions-js@2.4.1': resolution: {integrity: sha512-8sZ2ibwHlf+WkHDUZJUXqqmPvWQ3UHN0W30behOJngVh/qHHekhJLCFbh0AjkE9/FqqXtf9eoVvmYgfCLk5tNA==} @@ -3693,16 +3754,16 @@ packages: '@supabase/realtime-js@2.10.2': resolution: {integrity: sha512-qyCQaNg90HmJstsvr2aJNxK2zgoKh9ZZA8oqb7UT2LCh3mj9zpa3Iwu167AuyNxsxrUE8eEJ2yH6wLCij4EApA==} - '@supabase/ssr@0.5.0': - resolution: {integrity: sha512-5E0NmPpfXBzfATgYhg7o/nPkVu+38mx7pO5vlhxnk/5sYGnIZcpMHJs3jONb7Jx5IJN2kTPb59luEw66MOOTaA==} + '@supabase/ssr@0.5.1': + resolution: {integrity: sha512-+G94H/GZG0nErZ3FQV9yJmsC5Rj7dmcfCAwOt37hxeR1La+QTl8cE9whzYwPUrTJjMLGNXoO+1BMvVxwBAbz4g==} peerDependencies: '@supabase/supabase-js': ^2.43.4 '@supabase/storage-js@2.7.0': resolution: {integrity: sha512-iZenEdO6Mx9iTR6T7wC7sk6KKsoDPLq8rdu5VRy7+JiT1i8fnqfcOr6mfF2Eaqky9VQzhP8zZKQYjzozB65Rig==} - '@supabase/supabase-js@2.45.2': - resolution: {integrity: sha512-kJKY3ISFusVKQWCP8Kqo20Ebxy2WLp6Ry/Suco0aQsPXH7bvn7clswsdhcfcH/5Tr0MYz/jcCjF0n/27SetiCw==} + '@supabase/supabase-js@2.45.3': + resolution: {integrity: sha512-4wAux6cuVMrdH/qUjKn6p3p3L9AtAO3Une6ojIrtpCj1RaXKVoyIATiacSRAI+pKff6XZBVCGC29v+z4Jo/uSw==} '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -5641,8 +5702,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - eslint-plugin-react-hooks@5.1.0-rc-d1afcb43-20240903: - resolution: {integrity: sha512-/nFI+l7fwC5yg0VIPL9YmtlAPSbzOeeMW7cIcx5JEcsdE8SBN7uXKnsfik1yDQeGbQIgaQzN4nj5fNxfoVh7dQ==} + eslint-plugin-react-hooks@5.1.0-rc-a03254bc-20240905: + resolution: {integrity: sha512-MAQG2WZjBdVBz2mpyWz2l7piMjBoHrSaPiWAQqyJuwbmRRy5YHdVW/jkLXQcKWoct+U02AojaWh+EGKfsL1fgA==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 @@ -12633,6 +12694,24 @@ snapshots: '@types/react': 18.3.4 '@types/react-dom': 18.3.0 + '@radix-ui/react-radio-group@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-roving-focus': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.4)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.4 + '@types/react-dom': 18.3.0 + '@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -12667,6 +12746,35 @@ snapshots: '@types/react': 18.3.4 '@types/react-dom': 18.3.0 + '@radix-ui/react-select@2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.4)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.7(@types/react@18.3.4)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.4 + '@types/react-dom': 18.3.0 + '@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -12801,6 +12909,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.4 + '@radix-ui/react-use-previous@1.1.0(@types/react@18.3.4)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.4 + '@radix-ui/react-use-rect@1.1.0(@types/react@18.3.4)(react@18.3.1)': dependencies: '@radix-ui/rect': 1.1.0 @@ -13353,6 +13467,36 @@ snapshots: - '@types/react-dom' - react-dom + '@rn-primitives/radio-group@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-radio-group': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@rn-primitives/slot': 1.0.3(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + '@rn-primitives/types': 1.0.3(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + react: 18.3.1 + optionalDependencies: + react-native: 0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1) + react-native-web: 0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + - react-dom + + '@rn-primitives/select@1.0.4(@rn-primitives/portal@1.0.3(@types/react@18.3.4)(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1))(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-select': 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@rn-primitives/hooks': 1.0.3(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + '@rn-primitives/portal': 1.0.3(@types/react@18.3.4)(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + '@rn-primitives/slot': 1.0.3(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + '@rn-primitives/types': 1.0.3(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1) + react: 18.3.1 + optionalDependencies: + react-native: 0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1) + react-native-web: 0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + - react-dom + '@rn-primitives/separator@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react-native-web@0.19.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.3.4)(bufferutil@4.0.8)(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-separator': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -13415,9 +13559,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/rollup-linux-x64-gnu@4.21.0': - optional: true - '@scena/dragscroll@1.4.0': dependencies: '@daybrush/utils': 1.13.0 @@ -13471,11 +13612,11 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@supabase/auth-helpers-react@0.5.0(@supabase/supabase-js@2.45.2(bufferutil@4.0.8))': + '@supabase/auth-helpers-react@0.5.0(@supabase/supabase-js@2.45.3(bufferutil@4.0.8))': dependencies: - '@supabase/supabase-js': 2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@supabase/supabase-js': 2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) - '@supabase/auth-js@2.64.4': + '@supabase/auth-js@2.65.0': dependencies: '@supabase/node-fetch': 2.6.15 @@ -13501,20 +13642,18 @@ snapshots: - bufferutil - utf-8-validate - '@supabase/ssr@0.5.0(@supabase/supabase-js@2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4))': + '@supabase/ssr@0.5.1(@supabase/supabase-js@2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4))': dependencies: - '@supabase/supabase-js': 2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@supabase/supabase-js': 2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) cookie: 0.6.0 - optionalDependencies: - '@rollup/rollup-linux-x64-gnu': 4.21.0 '@supabase/storage-js@2.7.0': dependencies: '@supabase/node-fetch': 2.6.15 - '@supabase/supabase-js@2.45.2(bufferutil@4.0.8)(utf-8-validate@6.0.4)': + '@supabase/supabase-js@2.45.3(bufferutil@4.0.8)(utf-8-validate@6.0.4)': dependencies: - '@supabase/auth-js': 2.64.4 + '@supabase/auth-js': 2.65.0 '@supabase/functions-js': 2.4.1 '@supabase/node-fetch': 2.6.15 '@supabase/postgrest-js': 1.15.8 @@ -15746,7 +15885,7 @@ snapshots: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.0 - eslint-plugin-react-hooks@5.1.0-rc-d1afcb43-20240903(eslint@9.9.1(jiti@1.21.6)): + eslint-plugin-react-hooks@5.1.0-rc-a03254bc-20240905(eslint@9.9.1(jiti@1.21.6)): dependencies: eslint: 9.9.1(jiti@1.21.6) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b022333..4907a35 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -21,8 +21,8 @@ catalogs: "@types/react": ^18.3.3 "@types/react-dom": ^18.3.0 supabase: - "@supabase/supabase-js": ^2.45.2 - "@supabase/ssr": ^0.5.0 + "@supabase/supabase-js": ^2.45.3 + "@supabase/ssr": ^0.5.1 "@supabase/auth-helpers-react": ^0.5.0 tailwind: tailwindcss: ^3.4.10