From 5eefa7ff16fbf858015f7794a3cdc666053fa049 Mon Sep 17 00:00:00 2001 From: Giancarlo Buomprisco Date: Mon, 22 Jul 2024 14:03:03 +0800 Subject: [PATCH] Add events handling and enhance analytics tracking (#47) * Add events handling and enhance analytics tracking Added a new events system to track user actions throughout the application. Specific significant events such as user signup, sign-in, and checkout have dedicated handlers. Updated the analytics system to handle these event triggers and improved analytics reporting. An analytics provider has been implemented to manage event subscriptions and analytics event mappings. * Remove unused dependencies from package.json files Unused packages "@tanstack/react-table" and "next" have been removed from the packages/shared and tooling directories respectively. These changes help ensure that only needed packages are included in the project, reducing potential security risks and unnecessary processing overhead. * Update dependencies Multiple package versions were updated including "@tanstack/react-query" and "lucide-react" --- .../personal-account-checkout-form.tsx | 7 + .../team-account-checkout-form.tsx | 10 + apps/web/components/analytics-provider.tsx | 95 +++++++++ apps/web/components/auth-provider.tsx | 48 +++++ apps/web/components/root-providers.tsx | 68 ++++--- apps/web/package.json | 9 +- package.json | 2 +- packages/analytics/src/analytics-manager.ts | 7 +- .../analytics/src/null-analytics-service.ts | 17 +- packages/billing/gateway/package.json | 2 +- packages/features/accounts/package.json | 4 +- packages/features/admin/package.json | 4 +- packages/features/auth/package.json | 4 +- .../components/magic-link-auth-container.tsx | 14 +- .../components/password-sign-up-container.tsx | 13 +- packages/features/notifications/package.json | 4 +- packages/features/team-accounts/package.json | 4 +- packages/i18n/package.json | 2 +- packages/shared/package.json | 5 +- packages/shared/src/events/index.tsx | 118 +++++++++++ packages/supabase/package.json | 2 +- .../src/hooks/use-auth-change-listener.ts | 15 +- packages/ui/package.json | 4 +- pnpm-lock.yaml | 185 +++++++++--------- tooling/prettier/package.json | 1 - tooling/tailwind/package.json | 1 - 26 files changed, 477 insertions(+), 168 deletions(-) create mode 100644 apps/web/components/analytics-provider.tsx create mode 100644 apps/web/components/auth-provider.tsx create mode 100644 packages/shared/src/events/index.tsx diff --git a/apps/web/app/home/(user)/billing/_components/personal-account-checkout-form.tsx b/apps/web/app/home/(user)/billing/_components/personal-account-checkout-form.tsx index 170312cd5..b764a515e 100644 --- a/apps/web/app/home/(user)/billing/_components/personal-account-checkout-form.tsx +++ b/apps/web/app/home/(user)/billing/_components/personal-account-checkout-form.tsx @@ -7,6 +7,7 @@ import dynamic from 'next/dynamic'; import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { PlanPicker } from '@kit/billing-gateway/components'; +import { useAppEvents } from '@kit/shared/events'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { Card, @@ -40,6 +41,7 @@ export function PersonalAccountCheckoutForm(props: { }) { const [pending, startTransition] = useTransition(); const [error, setError] = useState(false); + const appEvents = useAppEvents(); const [checkoutToken, setCheckoutToken] = useState( undefined, @@ -85,6 +87,11 @@ export function PersonalAccountCheckoutForm(props: { onSubmit={({ planId, productId }) => { startTransition(async () => { try { + appEvents.emit({ + type: 'checkout.started', + payload: { planId }, + }); + const { checkoutToken } = await createPersonalAccountCheckoutSession({ planId, diff --git a/apps/web/app/home/[account]/billing/_components/team-account-checkout-form.tsx b/apps/web/app/home/[account]/billing/_components/team-account-checkout-form.tsx index 6152ac09f..8bfc54cf7 100644 --- a/apps/web/app/home/[account]/billing/_components/team-account-checkout-form.tsx +++ b/apps/web/app/home/[account]/billing/_components/team-account-checkout-form.tsx @@ -6,6 +6,7 @@ import dynamic from 'next/dynamic'; import { useParams } from 'next/navigation'; import { PlanPicker } from '@kit/billing-gateway/components'; +import { useAppEvents } from '@kit/shared/events'; import { Card, CardContent, @@ -38,6 +39,7 @@ export function TeamAccountCheckoutForm(params: { }) { const routeParams = useParams(); const [pending, startTransition] = useTransition(); + const appEvents = useAppEvents(); const [checkoutToken, setCheckoutToken] = useState( undefined, @@ -79,6 +81,14 @@ export function TeamAccountCheckoutForm(params: { startTransition(async () => { const slug = routeParams.account as string; + appEvents.emit({ + type: 'checkout.started', + payload: { + planId, + account: slug, + }, + }); + const { checkoutToken } = await createTeamAccountCheckoutSession({ planId, productId, diff --git a/apps/web/components/analytics-provider.tsx b/apps/web/components/analytics-provider.tsx new file mode 100644 index 000000000..8ccdf82cb --- /dev/null +++ b/apps/web/components/analytics-provider.tsx @@ -0,0 +1,95 @@ +'use client'; + +import { useEffect } from 'react'; + +import { usePathname, useSearchParams } from 'next/navigation'; + +import { analytics } from '@kit/analytics'; +import { + AppEvent, + AppEventType, + ConsumerProvidedEventTypes, + useAppEvents, +} from '@kit/shared/events'; + +type AnalyticsMapping< + T extends ConsumerProvidedEventTypes = NonNullable, +> = { + [K in AppEventType]?: (event: AppEvent) => void; +}; + +/** + * Hook to subscribe to app events and map them to analytics actions + * @param mapping + */ +function useAnalyticsMapping( + mapping: AnalyticsMapping, +) { + const appEvents = useAppEvents(); + + useEffect(() => { + const subscriptions = Object.entries(mapping).map( + ([eventType, handler]) => { + appEvents.on(eventType as AppEventType, handler); + + return () => appEvents.off(eventType as AppEventType, handler); + }, + ); + + return () => { + subscriptions.forEach((unsubscribe) => unsubscribe()); + }; + }, [appEvents, mapping]); +} + +/** + * Define a mapping of app events to analytics actions + * Add new mappings here to track new events in the analytics service from app events + */ +const analyticsMapping: AnalyticsMapping = { + 'user.signedIn': (event) => { + const userId = event.payload.userId; + + if (userId) { + analytics.identify(userId); + } + }, + 'user.signedUp': (event) => { + analytics.trackEvent(event.type, event.payload); + }, + 'checkout.started': (event) => { + analytics.trackEvent(event.type, event.payload); + }, + 'user.updated': (event) => { + analytics.trackEvent(event.type, event.payload); + }, +}; + +/** + * Provider for the analytics service + */ +export function AnalyticsProvider(props: React.PropsWithChildren) { + // Subscribe to app events and map them to analytics actions + useAnalyticsMapping(analyticsMapping); + + // Report page views to the analytics service + useReportPageView((url) => analytics.trackPageView(url)); + + // Render children + return props.children; +} + +/** + * Hook to report page views to the analytics service + * @param reportAnalyticsFn + */ +function useReportPageView(reportAnalyticsFn: (url: string) => void) { + const pathname = usePathname(); + const searchParams = useSearchParams(); + + useEffect(() => { + const url = [pathname, searchParams.toString()].filter(Boolean).join('?'); + + reportAnalyticsFn(url); + }, [pathname, reportAnalyticsFn, searchParams]); +} diff --git a/apps/web/components/auth-provider.tsx b/apps/web/components/auth-provider.tsx new file mode 100644 index 000000000..1cfec12d2 --- /dev/null +++ b/apps/web/components/auth-provider.tsx @@ -0,0 +1,48 @@ +'use client'; + +import { useCallback } from 'react'; + +import { useAppEvents } from '@kit/shared/events'; +import { useAuthChangeListener } from '@kit/supabase/hooks/use-auth-change-listener'; + +import pathsConfig from '~/config/paths.config'; + +export function AuthProvider(props: React.PropsWithChildren) { + const dispatchEvent = useDispatchAppEventFromAuthEvent(); + + useAuthChangeListener({ + appHomePath: pathsConfig.app.home, + onEvent: (event, session) => { + dispatchEvent(event, session?.user.id); + }, + }); + + return props.children; +} + +function useDispatchAppEventFromAuthEvent() { + const { emit } = useAppEvents(); + + return useCallback( + (type: string, userId: string | undefined) => { + switch (type) { + case 'SIGNED_IN': + emit({ + type: 'user.signedIn', + payload: { userId: userId! }, + }); + + break; + + case 'USER_UPDATED': + emit({ + type: 'user.updated', + payload: { userId: userId! }, + }); + + break; + } + }, + [emit], + ); +} diff --git a/apps/web/components/root-providers.tsx b/apps/web/components/root-providers.tsx index 55df9db1d..4d1d7068d 100644 --- a/apps/web/components/root-providers.tsx +++ b/apps/web/components/root-providers.tsx @@ -1,5 +1,7 @@ 'use client'; +import { useMemo } from 'react'; + import dynamic from 'next/dynamic'; import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'; @@ -8,14 +10,15 @@ import { ThemeProvider } from 'next-themes'; import { CaptchaProvider } from '@kit/auth/captcha/client'; import { I18nProvider } from '@kit/i18n/provider'; import { MonitoringProvider } from '@kit/monitoring/components'; -import { useAuthChangeListener } from '@kit/supabase/hooks/use-auth-change-listener'; +import { AppEventsProvider } from '@kit/shared/events'; import { If } from '@kit/ui/if'; import { VersionUpdater } from '@kit/ui/version-updater'; +import { AnalyticsProvider } from '~/components/analytics-provider'; +import { AuthProvider } from '~/components/auth-provider'; import appConfig from '~/config/app.config'; import authConfig from '~/config/auth.config'; import featuresFlagConfig from '~/config/feature-flags.config'; -import pathsConfig from '~/config/paths.config'; import { i18nResolver } from '~/lib/i18n/i18n.resolver'; import { getI18nSettings } from '~/lib/i18n/i18n.settings'; @@ -43,44 +46,39 @@ export function RootProviders({ lang: string; theme?: string; }>) { - const i18nSettings = getI18nSettings(lang); + const i18nSettings = useMemo(() => getI18nSettings(lang), [lang]); return ( - - - - - + + + + + + + - - - {children} - - - + + + {children} + + + - - - - - - + + + + + + + + ); } - -// we place this below React Query since it uses the QueryClient -function AuthProvider(props: React.PropsWithChildren) { - useAuthChangeListener({ - appHomePath: pathsConfig.app.home, - }); - - return props.children; -} diff --git a/apps/web/package.json b/apps/web/package.json index 237ef9ade..eb4550ad5 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -31,10 +31,11 @@ "supabase:db:dump:local": "supabase db dump --local --data-only" }, "dependencies": { - "@edge-csrf/nextjs": "2.2.2", + "@edge-csrf/nextjs": "2.3.0-rc1", "@hookform/resolvers": "^3.9.0", "@kit/accounts": "workspace:^", "@kit/admin": "workspace:^", + "@kit/analytics": "workspace:^", "@kit/auth": "workspace:^", "@kit/billing": "workspace:^", "@kit/billing-gateway": "workspace:^", @@ -55,11 +56,11 @@ "@marsidev/react-turnstile": "^0.7.2", "@radix-ui/react-icons": "^1.3.0", "@supabase/supabase-js": "^2.44.4", - "@tanstack/react-query": "5.51.9", - "@tanstack/react-query-next-experimental": "^5.51.9", + "@tanstack/react-query": "5.51.11", + "@tanstack/react-query-next-experimental": "^5.51.11", "@tanstack/react-table": "^8.19.3", "date-fns": "^3.6.0", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "next": "14.2.5", "next-sitemap": "^4.2.3", "next-themes": "0.3.0", diff --git a/package.json b/package.json index 6d4f821a3..a165c4a9d 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@manypkg/cli": "^0.21.4", "@turbo/gen": "^2.0.9", "cross-env": "^7.0.3", - "pnpm": "^9.5.0", + "pnpm": "^9.6.0", "prettier": "^3.3.3", "turbo": "2.0.9", "typescript": "^5.5.3" diff --git a/packages/analytics/src/analytics-manager.ts b/packages/analytics/src/analytics-manager.ts index ed21feae8..c33ea2093 100644 --- a/packages/analytics/src/analytics-manager.ts +++ b/packages/analytics/src/analytics-manager.ts @@ -1,5 +1,5 @@ import { NullAnalyticsService } from './null-analytics-service'; -import { +import type { AnalyticsManager, AnalyticsService, CreateAnalyticsManagerOptions, @@ -18,7 +18,7 @@ export function createAnalyticsManager( const getActiveService = (): AnalyticsService => { if (activeService === NullAnalyticsService) { - console.warn( + console.debug( 'Analytics service not initialized. Using NullAnalyticsService.', ); } @@ -30,7 +30,7 @@ export function createAnalyticsManager( const factory = options.providers[provider]; if (!factory) { - console.error( + console.warn( `Analytics provider '${provider}' not registered. Using NullAnalyticsService.`, ); @@ -57,6 +57,7 @@ export function createAnalyticsManager( trackPageView: (url: string) => { return getActiveService().trackPageView(url); }, + /** * Track an event with the given name and properties. * @param eventName diff --git a/packages/analytics/src/null-analytics-service.ts b/packages/analytics/src/null-analytics-service.ts index 72d1ed658..7ee7b0eed 100644 --- a/packages/analytics/src/null-analytics-service.ts +++ b/packages/analytics/src/null-analytics-service.ts @@ -1,7 +1,14 @@ import { AnalyticsService } from './types'; -const noop = () => { +const noop = (event: string) => { // do nothing - this is to prevent errors when the analytics service is not initialized + + return (...args: unknown[]) => { + console.debug( + `Noop analytics service called with event: ${event}`, + ...args.filter(Boolean), + ); + }; }; /** @@ -9,8 +16,8 @@ const noop = () => { * the user is calling analytics methods before the analytics service is initialized. */ export const NullAnalyticsService: AnalyticsService = { - initialize: noop, - trackPageView: noop, - trackEvent: noop, - identify: noop, + initialize: noop('initialize'), + trackPageView: noop('trackPageView'), + trackEvent: noop('trackEvent'), + identify: noop('identify'), }; diff --git a/packages/billing/gateway/package.json b/packages/billing/gateway/package.json index fe0de8c9c..e513c84b8 100644 --- a/packages/billing/gateway/package.json +++ b/packages/billing/gateway/package.json @@ -30,7 +30,7 @@ "@supabase/supabase-js": "^2.44.4", "@types/react": "^18.3.3", "date-fns": "^3.6.0", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "next": "14.2.5", "react": "18.3.1", "react-hook-form": "^7.52.1", diff --git a/packages/features/accounts/package.json b/packages/features/accounts/package.json index 512ef0d8e..1f15a61e8 100644 --- a/packages/features/accounts/package.json +++ b/packages/features/accounts/package.json @@ -35,10 +35,10 @@ "@kit/ui": "workspace:^", "@radix-ui/react-icons": "^1.3.0", "@supabase/supabase-js": "^2.44.4", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "next": "14.2.5", "next-themes": "0.3.0", "react": "18.3.1", diff --git a/packages/features/admin/package.json b/packages/features/admin/package.json index 38dc70282..8d49946b7 100644 --- a/packages/features/admin/package.json +++ b/packages/features/admin/package.json @@ -22,10 +22,10 @@ "@makerkit/data-loader-supabase-core": "^0.0.8", "@makerkit/data-loader-supabase-nextjs": "^1.2.3", "@supabase/supabase-js": "^2.44.4", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "@tanstack/react-table": "^8.19.3", "@types/react": "^18.3.3", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "next": "14.2.5", "react": "18.3.1", "react-dom": "18.3.1", diff --git a/packages/features/auth/package.json b/packages/features/auth/package.json index 6a6d0c3bd..cc209264d 100644 --- a/packages/features/auth/package.json +++ b/packages/features/auth/package.json @@ -29,9 +29,9 @@ "@marsidev/react-turnstile": "^0.7.2", "@radix-ui/react-icons": "^1.3.0", "@supabase/supabase-js": "^2.44.4", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "@types/react": "^18.3.3", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "next": "14.2.5", "react-hook-form": "^7.52.1", "react-i18next": "^15.0.0", diff --git a/packages/features/auth/src/components/magic-link-auth-container.tsx b/packages/features/auth/src/components/magic-link-auth-container.tsx index 32a555451..7ab2b34bf 100644 --- a/packages/features/auth/src/components/magic-link-auth-container.tsx +++ b/packages/features/auth/src/components/magic-link-auth-container.tsx @@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next'; import { toast } from 'sonner'; import { z } from 'zod'; +import { useAppEvents } from '@kit/shared/events'; import { useSignInWithOtp } from '@kit/supabase/hooks/use-sign-in-with-otp'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { Button } from '@kit/ui/button'; @@ -44,6 +45,7 @@ export function MagicLinkAuthContainer({ const { captchaToken, resetCaptchaToken } = useCaptchaToken(); const { t } = useTranslation(); const signInWithOtpMutation = useSignInWithOtp(); + const appEvents = useAppEvents(); const form = useForm({ resolver: zodResolver( @@ -65,8 +67,8 @@ export function MagicLinkAuthContainer({ const emailRedirectTo = url.href; - const promise = () => - signInWithOtpMutation.mutateAsync({ + const promise = async () => { + await signInWithOtpMutation.mutateAsync({ email, options: { emailRedirectTo, @@ -75,6 +77,14 @@ export function MagicLinkAuthContainer({ }, }); + appEvents.emit({ + type: 'user.signedUp', + payload: { + method: 'magiclink', + }, + }); + }; + toast.promise(promise, { loading: t('auth:sendingEmailLink'), success: t(`auth:sendLinkSuccessToast`), diff --git a/packages/features/auth/src/components/password-sign-up-container.tsx b/packages/features/auth/src/components/password-sign-up-container.tsx index 547b4f0dd..136ec97a8 100644 --- a/packages/features/auth/src/components/password-sign-up-container.tsx +++ b/packages/features/auth/src/components/password-sign-up-container.tsx @@ -4,6 +4,7 @@ import { useCallback, useRef, useState } from 'react'; import { CheckCircledIcon } from '@radix-ui/react-icons'; +import { useAppEvents } from '@kit/shared/events'; import { useSignUpWithEmailAndPassword } from '@kit/supabase/hooks/use-sign-up-with-email-password'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { If } from '@kit/ui/if'; @@ -33,8 +34,10 @@ export function EmailPasswordSignUpContainer({ const signUpMutation = useSignUpWithEmailAndPassword(); const redirecting = useRef(false); - const loading = signUpMutation.isPending || redirecting.current; const [showVerifyEmailAlert, setShowVerifyEmailAlert] = useState(false); + const appEvents = useAppEvents(); + + const loading = signUpMutation.isPending || redirecting.current; const onSignupRequested = useCallback( async (credentials: { email: string; password: string }) => { @@ -49,6 +52,13 @@ export function EmailPasswordSignUpContainer({ captchaToken, }); + appEvents.emit({ + type: 'user.signedUp', + payload: { + method: 'password', + }, + }); + setShowVerifyEmailAlert(true); if (onSignUp) { @@ -61,6 +71,7 @@ export function EmailPasswordSignUpContainer({ } }, [ + appEvents, captchaToken, emailRedirectTo, loading, diff --git a/packages/features/notifications/package.json b/packages/features/notifications/package.json index 727d32538..0a05179ca 100644 --- a/packages/features/notifications/package.json +++ b/packages/features/notifications/package.json @@ -21,9 +21,9 @@ "@kit/tsconfig": "workspace:*", "@kit/ui": "workspace:*", "@supabase/supabase-js": "^2.44.4", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "@types/react": "^18.3.3", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "react": "18.3.1", "react-dom": "18.3.1", "react-i18next": "^15.0.0" diff --git a/packages/features/team-accounts/package.json b/packages/features/team-accounts/package.json index 949479ced..9eaf442d8 100644 --- a/packages/features/team-accounts/package.json +++ b/packages/features/team-accounts/package.json @@ -33,13 +33,13 @@ "@kit/tsconfig": "workspace:*", "@kit/ui": "workspace:^", "@supabase/supabase-js": "^2.44.4", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "@tanstack/react-table": "^8.19.3", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "class-variance-authority": "^0.7.0", "date-fns": "^3.6.0", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "next": "14.2.5", "react": "18.3.1", "react-dom": "18.3.1", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index d368fb0f9..adabc4052 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -21,7 +21,7 @@ "@kit/shared": "workspace:^", "@kit/tailwind-config": "workspace:*", "@kit/tsconfig": "workspace:*", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "react-i18next": "^15.0.0" }, "dependencies": { diff --git a/packages/shared/package.json b/packages/shared/package.json index ac1c6a6a9..04d47e0b7 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -12,14 +12,15 @@ "exports": { "./logger": "./src/logger/index.ts", "./utils": "./src/utils.ts", - "./hooks": "./src/hooks/index.ts" + "./hooks": "./src/hooks/index.ts", + "./events": "./src/events/index.tsx" }, "devDependencies": { "@kit/eslint-config": "workspace:*", "@kit/prettier-config": "workspace:*", "@kit/tailwind-config": "workspace:*", "@kit/tsconfig": "workspace:*", - "@tanstack/react-table": "^8.19.3" + "@types/react": "^18.3.3" }, "dependencies": { "pino": "^9.3.1" diff --git a/packages/shared/src/events/index.tsx b/packages/shared/src/events/index.tsx new file mode 100644 index 000000000..f51be7440 --- /dev/null +++ b/packages/shared/src/events/index.tsx @@ -0,0 +1,118 @@ +'use client'; + +import { createContext, useCallback, useContext, useRef } from 'react'; + +type EmptyPayload = NonNullable; + +// Base event types +export interface BaseAppEventTypes { + 'user.signedIn': { userId: string }; + 'user.signedUp': { method: `magiclink` | `password` }; + 'user.updated': EmptyPayload; + 'checkout.started': { planId: string; account?: string }; + + // Add more base event types here +} + +export type ConsumerProvidedEventTypes = EmptyPayload; + +// Helper type for extending event types +export type ExtendedAppEventTypes< + T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes, +> = BaseAppEventTypes & T; + +// Generic type for the entire module +export type AppEventType = + keyof ExtendedAppEventTypes; + +export type AppEvent< + T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes, + K extends AppEventType = AppEventType, +> = { + type: K; + payload: ExtendedAppEventTypes[K]; +}; + +export type EventCallback< + T extends ConsumerProvidedEventTypes, + K extends AppEventType = AppEventType, +> = (event: AppEvent) => void; + +interface InternalAppEventsContextType< + T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes, + K extends AppEventType = AppEventType, +> { + emit: (event: AppEvent) => void; + on: (eventType: K, callback: EventCallback) => void; + off: (eventType: K, callback: EventCallback) => void; +} + +interface AppEventsContextType { + emit: >(event: AppEvent) => void; + + on: >( + eventType: K, + callback: EventCallback, + ) => void; + + off: >( + eventType: K, + callback: EventCallback, + ) => void; +} + +const AppEventsContext = createContext( + null, +); + +export function AppEventsProvider< + T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes, + K extends AppEventType = AppEventType, +>({ children }: React.PropsWithChildren) { + const listeners = useRef[]>>( + {} as Record[]>, + ); + + const emit = useCallback( + (event: AppEvent) => { + const eventListeners = listeners.current[event.type] ?? []; + + eventListeners.forEach((callback) => callback(event)); + }, + [listeners], + ); + + const on = useCallback((eventType: K, callback: EventCallback) => { + listeners.current = { + ...listeners.current, + [eventType]: [...(listeners.current[eventType] ?? []), callback], + }; + }, []) as AppEventsContextType['on']; + + const off = useCallback((eventType: K, callback: EventCallback) => { + listeners.current = { + ...listeners.current, + [eventType]: (listeners.current[eventType] ?? []).filter( + (cb) => cb !== callback, + ), + }; + }, []) as AppEventsContextType['off']; + + return ( + + {children} + + ); +} + +export function useAppEvents< + T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes, +>(): AppEventsContextType { + const context = useContext(AppEventsContext); + + if (!context) { + throw new Error('useAppEvents must be used within an AppEventsProvider'); + } + + return context as AppEventsContextType; +} diff --git a/packages/supabase/package.json b/packages/supabase/package.json index 034f6c5d9..2e381cee4 100644 --- a/packages/supabase/package.json +++ b/packages/supabase/package.json @@ -29,7 +29,7 @@ "@supabase/gotrue-js": "2.64.4", "@supabase/ssr": "^0.4.0", "@supabase/supabase-js": "^2.44.4", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "@types/react": "^18.3.3", "next": "14.2.5", "react": "18.3.1", diff --git a/packages/supabase/src/hooks/use-auth-change-listener.ts b/packages/supabase/src/hooks/use-auth-change-listener.ts index 0f7923eaa..c86f40a5b 100644 --- a/packages/supabase/src/hooks/use-auth-change-listener.ts +++ b/packages/supabase/src/hooks/use-auth-change-listener.ts @@ -4,6 +4,8 @@ import { useEffect } from 'react'; import { usePathname } from 'next/navigation'; +import type { AuthChangeEvent, Session } from '@supabase/supabase-js'; + import { useSupabase } from './use-supabase'; /** @@ -14,15 +16,18 @@ const PRIVATE_PATH_PREFIXES = ['/home', '/admin', '/join', '/update-password']; /** * @name useAuthChangeListener - * @param privatePathPrefixes - * @param appHomePath + * @param privatePathPrefixes - A list of private path prefixes + * @param appHomePath - The path to redirect to when the user is signed out + * @param onEvent - Callback function to be called when an auth event occurs */ export function useAuthChangeListener({ privatePathPrefixes = PRIVATE_PATH_PREFIXES, appHomePath, + onEvent, }: { appHomePath: string; privatePathPrefixes?: string[]; + onEvent?: (event: AuthChangeEvent, user: Session | null) => void; }) { const client = useSupabase(); const pathName = usePathname(); @@ -30,6 +35,10 @@ export function useAuthChangeListener({ useEffect(() => { // keep this running for the whole session unless the component was unmounted const listener = client.auth.onAuthStateChange((event, user) => { + if (onEvent) { + onEvent(event, user); + } + // log user out if user is falsy // and if the current path is a private route const shouldRedirectUser = @@ -50,7 +59,7 @@ export function useAuthChangeListener({ // destroy listener on un-mounts return () => listener.data.subscription.unsubscribe(); - }, [client.auth, pathName, appHomePath, privatePathPrefixes]); + }, [client.auth, pathName, appHomePath, privatePathPrefixes, onEvent]); } /** diff --git a/packages/ui/package.json b/packages/ui/package.json index 5f6fe697d..35d5c785a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -31,7 +31,7 @@ "clsx": "^2.1.1", "cmdk": "1.0.0", "input-otp": "1.2.4", - "lucide-react": "^0.411.0", + "lucide-react": "^0.412.0", "react-top-loading-bar": "2.3.1", "tailwind-merge": "^2.4.0" }, @@ -41,7 +41,7 @@ "@kit/tailwind-config": "workspace:*", "@kit/tsconfig": "workspace:*", "@radix-ui/react-icons": "^1.3.0", - "@tanstack/react-query": "5.51.9", + "@tanstack/react-query": "5.51.11", "@tanstack/react-table": "^8.19.3", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 77ba919b2..7e178434e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,8 +22,8 @@ importers: specifier: ^7.0.3 version: 7.0.3 pnpm: - specifier: ^9.5.0 - version: 9.5.0 + specifier: ^9.6.0 + version: 9.6.0 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -49,8 +49,8 @@ importers: apps/web: dependencies: '@edge-csrf/nextjs': - specifier: 2.2.2 - version: 2.2.2(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + specifier: 2.3.0-rc1 + version: 2.3.0-rc1(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) '@hookform/resolvers': specifier: ^3.9.0 version: 3.9.0(react-hook-form@7.52.1(react@18.3.1)) @@ -60,6 +60,9 @@ importers: '@kit/admin': specifier: workspace:^ version: link:../../packages/features/admin + '@kit/analytics': + specifier: workspace:^ + version: link:../../packages/analytics '@kit/auth': specifier: workspace:^ version: link:../../packages/features/auth @@ -110,7 +113,7 @@ importers: version: 0.0.8(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4) '@makerkit/data-loader-supabase-nextjs': specifier: ^1.2.3 - version: 1.2.3(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)(@tanstack/react-query@5.51.9(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 1.2.3(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)(@tanstack/react-query@5.51.11(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@marsidev/react-turnstile': specifier: ^0.7.2 version: 0.7.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -121,11 +124,11 @@ importers: specifier: ^2.44.4 version: 2.44.4 '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@tanstack/react-query-next-experimental': - specifier: ^5.51.9 - version: 5.51.9(@tanstack/react-query@5.51.9(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + specifier: ^5.51.11 + version: 5.51.11(@tanstack/react-query@5.51.11(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@tanstack/react-table': specifier: ^8.19.3 version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -133,11 +136,11 @@ importers: specifier: ^3.6.0 version: 3.6.0 lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-sitemap: specifier: ^4.2.3 version: 4.2.3(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) @@ -302,11 +305,11 @@ importers: specifier: ^3.6.0 version: 3.6.0 lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -355,7 +358,7 @@ importers: version: 18.3.3 next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -407,7 +410,7 @@ importers: version: 3.6.0 next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -607,8 +610,8 @@ importers: specifier: ^2.44.4 version: 2.44.4 '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@types/react': specifier: ^18.3.3 version: 18.3.3 @@ -616,11 +619,11 @@ importers: specifier: ^18.3.0 version: 18.3.0 lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: 0.3.0 version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -677,13 +680,13 @@ importers: version: 0.0.8(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4) '@makerkit/data-loader-supabase-nextjs': specifier: ^1.2.3 - version: 1.2.3(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)(@tanstack/react-query@5.51.9(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 1.2.3(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)(@tanstack/react-query@5.51.11(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@supabase/supabase-js': specifier: ^2.44.4 version: 2.44.4 '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@tanstack/react-table': specifier: ^8.19.3 version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -691,11 +694,11 @@ importers: specifier: ^18.3.3 version: 18.3.3 lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -745,17 +748,17 @@ importers: specifier: ^2.44.4 version: 2.44.4 '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@types/react': specifier: ^18.3.3 version: 18.3.3 lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-hook-form: specifier: ^7.52.1 version: 7.52.1(react@18.3.1) @@ -793,14 +796,14 @@ importers: specifier: ^2.44.4 version: 2.44.4 '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@types/react': specifier: ^18.3.3 version: 18.3.3 lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -863,8 +866,8 @@ importers: specifier: ^2.44.4 version: 2.44.4 '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@tanstack/react-table': specifier: ^8.19.3 version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -881,11 +884,11 @@ importers: specifier: ^3.6.0 version: 3.6.0 lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -933,8 +936,8 @@ importers: specifier: workspace:* version: link:../../tooling/typescript '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) react-i18next: specifier: ^15.0.0 version: 15.0.0(i18next@23.12.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1056,7 +1059,7 @@ importers: dependencies: '@sentry/nextjs': specifier: ^8.19.0 - version: 8.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(next@14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) + version: 8.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0) devDependencies: '@kit/eslint-config': specifier: workspace:* @@ -1108,7 +1111,7 @@ importers: version: 2.44.4 next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zod: specifier: ^3.23.8 version: 3.23.8 @@ -1131,9 +1134,9 @@ importers: '@kit/tsconfig': specifier: workspace:* version: link:../../tooling/typescript - '@tanstack/react-table': - specifier: ^8.19.3 - version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@types/react': + specifier: ^18.3.3 + version: 18.3.3 packages/supabase: devDependencies: @@ -1159,14 +1162,14 @@ importers: specifier: ^2.44.4 version: 2.44.4 '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@types/react': specifier: ^18.3.3 version: 18.3.3 next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -1246,8 +1249,8 @@ importers: specifier: 1.2.4 version: 1.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) lucide-react: - specifier: ^0.411.0 - version: 0.411.0(react@18.3.1) + specifier: ^0.412.0 + version: 0.412.0(react@18.3.1) react-top-loading-bar: specifier: 2.3.1 version: 2.3.1(react@18.3.1) @@ -1271,8 +1274,8 @@ importers: specifier: ^1.3.0 version: 1.3.0(react@18.3.1) '@tanstack/react-query': - specifier: 5.51.9 - version: 5.51.9(react@18.3.1) + specifier: 5.51.11 + version: 5.51.11(react@18.3.1) '@tanstack/react-table': specifier: ^8.19.3 version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1293,7 +1296,7 @@ importers: version: 8.57.0 next: specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: 0.3.0 version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1376,9 +1379,6 @@ importers: '@ianvs/prettier-plugin-sort-imports': specifier: ^4.3.1 version: 4.3.1(prettier@3.3.3) - next: - specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) prettier: specifier: ^3.3.3 version: 3.3.3 @@ -1398,9 +1398,6 @@ importers: autoprefixer: specifier: ^10.4.19 version: 10.4.19(postcss@8.4.39) - next: - specifier: 14.2.5 - version: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) postcss: specifier: 8.4.39 version: 8.4.39 @@ -1609,8 +1606,8 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@edge-csrf/nextjs@2.2.2': - resolution: {integrity: sha512-+RRcNzm2QSGPaXgOcnhE+yw36BMXLBKQnWA3db0xCpAOEOb4dEwQNxVGd7Fz6CKQ4yIdBJuqHasBSmtZB6lHUQ==} + '@edge-csrf/nextjs@2.3.0-rc1': + resolution: {integrity: sha512-2Nchl8TO3pTcAgjSKYYDq8viYmBs4EDWlgZhWI+GX2/o2b3MfptOHUDprTpVPvkUzP8xXLq4WsXp60LUeOkggQ==} peerDependencies: next: ^13.0.0 || ^14.0.0 @@ -3850,15 +3847,15 @@ packages: '@tanstack/query-core@5.51.9': resolution: {integrity: sha512-HsAwaY5J19MD18ykZDS3aVVh+bAt0i7m6uQlFC2b77DLV9djo+xEN7MWQAQQTR8IM+7r/zbozTQ7P0xr0bHuew==} - '@tanstack/react-query-next-experimental@5.51.9': - resolution: {integrity: sha512-DwCeh1GsppH2c3sN8BzJU2MArH887E3UzNtstZBEhb7SBKzxutnWmwbHUPi1JbIe+6KkPXLsgUjlxEGWAxOsQw==} + '@tanstack/react-query-next-experimental@5.51.11': + resolution: {integrity: sha512-gUYTz9KYUbyxSek7U3o1J4efqzfNZICd3XvBhfz5i0rrxx7hKghx18fL87vH2N9UxYS5V5DjjX3dIp4m/u+Nvg==} peerDependencies: - '@tanstack/react-query': ^5.51.9 + '@tanstack/react-query': ^5.51.11 next: ^13 || ^14 || ^15 react: 18.3.1 - '@tanstack/react-query@5.51.9': - resolution: {integrity: sha512-F8j6i42wfKvFrRcxfOyFyYME+bPfNthAGOSkjdv4UwZZXJjnBnBs/yRQGT0bD23LVCTuBzlIfZ0GKSIyclZ9rQ==} + '@tanstack/react-query@5.51.11': + resolution: {integrity: sha512-4Kq2x0XpDlpvSnaLG+8pHNH60zEc3mBvb3B2tOMDjcPCi/o+Du3p/9qpPLwJOTliVxxPJAP27fuIhLrsRdCr7A==} peerDependencies: react: 18.3.1 @@ -5894,8 +5891,8 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - lucide-react@0.411.0: - resolution: {integrity: sha512-bDRvLt/jIIjsq4JVYB3EjyOtLHu8uQGzv7usri2DnVpOtfIRuLln96srS+d8WJsmJ52LBwDnYx7me/TSjZ6AcA==} + lucide-react@0.412.0: + resolution: {integrity: sha512-m7argY/PhSfjhwP2Dxey+VzFBvusfd8ULt+vWWFnzQhURLOtNyD1qWmMVdtJ4Nn+d+DTcoOiILrjThSjY9kaow==} peerDependencies: react: 18.3.1 @@ -6502,8 +6499,8 @@ packages: engines: {node: '>=18'} hasBin: true - pnpm@9.5.0: - resolution: {integrity: sha512-FAA2gwEkYY1iSiGHtQ0EKJ1aCH8ybJ7fwMzXM9dsT1LDoxPU/BSHlKKp2BVTAWAE5nQujPhQZwJopzh/wiDJAw==} + pnpm@9.6.0: + resolution: {integrity: sha512-ONxvuo26NbOTQLlwARLC/h4S8QsXE0cVpKqYzPe7A152/Zgc8Ls4TfqY+NavVIHCvvL0Jmokv6IMNOtxR84LXg==} engines: {node: '>=18.12'} hasBin: true @@ -8046,9 +8043,9 @@ snapshots: '@discoveryjs/json-ext@0.5.7': {} - '@edge-csrf/nextjs@2.2.2(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@edge-csrf/nextjs@2.3.0-rc1(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: - next: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@emotion/babel-plugin@11.11.0': dependencies: @@ -8374,7 +8371,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - next: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - supports-color @@ -8464,7 +8461,7 @@ snapshots: '@keystatic/core': 0.5.27(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/react': 18.3.3 chokidar: 3.6.0 - next: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) server-only: 0.0.1 @@ -8477,12 +8474,12 @@ snapshots: '@supabase/supabase-js': 2.44.4 ts-case-convert: 2.0.7 - '@makerkit/data-loader-supabase-nextjs@1.2.3(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)(@tanstack/react-query@5.51.9(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@makerkit/data-loader-supabase-nextjs@1.2.3(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)(@tanstack/react-query@5.51.11(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@makerkit/data-loader-supabase-core': 0.0.8(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4) '@supabase/supabase-js': 2.44.4 - '@tanstack/react-query': 5.51.9(react@18.3.1) - next: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-query': 5.51.11(react@18.3.1) + next: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 transitivePeerDependencies: - '@supabase/postgrest-js' @@ -10878,7 +10875,7 @@ snapshots: '@sentry/types': 8.19.0 '@sentry/utils': 8.19.0 - '@sentry/nextjs@8.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(next@14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0)': + '@sentry/nextjs@8.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.93.0)': dependencies: '@opentelemetry/instrumentation-http': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.25.1 @@ -10892,7 +10889,7 @@ snapshots: '@sentry/vercel-edge': 8.19.0 '@sentry/webpack-plugin': 2.20.1(webpack@5.93.0) chalk: 3.0.0 - next: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) resolve: 1.22.8 rollup: 3.29.4 stacktrace-parser: 0.1.10 @@ -11074,13 +11071,13 @@ snapshots: '@tanstack/query-core@5.51.9': {} - '@tanstack/react-query-next-experimental@5.51.9(@tanstack/react-query@5.51.9(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@tanstack/react-query-next-experimental@5.51.11(@tanstack/react-query@5.51.11(react@18.3.1))(next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: - '@tanstack/react-query': 5.51.9(react@18.3.1) - next: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tanstack/react-query': 5.51.11(react@18.3.1) + next: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 - '@tanstack/react-query@5.51.9(react@18.3.1)': + '@tanstack/react-query@5.51.11(react@18.3.1)': dependencies: '@tanstack/query-core': 5.51.9 react: 18.3.1 @@ -13384,7 +13381,7 @@ snapshots: lru-cache@7.18.3: {} - lucide-react@0.411.0(react@18.3.1): + lucide-react@0.412.0(react@18.3.1): dependencies: react: 18.3.1 @@ -13913,14 +13910,14 @@ snapshots: '@next/env': 13.5.6 fast-glob: 3.3.2 minimist: 1.2.8 - next: 14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes@0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@14.2.5(@babel/core@7.24.9)(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@14.2.5(@opentelemetry/api@1.9.0)(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 14.2.5 '@swc/helpers': 0.5.5 @@ -13930,7 +13927,7 @@ snapshots: postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(@babel/core@7.24.9)(react@18.3.1) + styled-jsx: 5.1.1(react@18.3.1) optionalDependencies: '@next/swc-darwin-arm64': 14.2.5 '@next/swc-darwin-x64': 14.2.5 @@ -14268,7 +14265,7 @@ snapshots: optionalDependencies: fsevents: 2.3.2 - pnpm@9.5.0: {} + pnpm@9.6.0: {} possible-typed-array-names@1.0.0: {} @@ -14997,12 +14994,10 @@ snapshots: '@types/node': 20.14.11 qs: 6.12.2 - styled-jsx@5.1.1(@babel/core@7.24.9)(react@18.3.1): + styled-jsx@5.1.1(react@18.3.1): dependencies: client-only: 0.0.1 react: 18.3.1 - optionalDependencies: - '@babel/core': 7.24.9 stylis@4.2.0: {} diff --git a/tooling/prettier/package.json b/tooling/prettier/package.json index 3ae19e3d7..e8f5d0715 100644 --- a/tooling/prettier/package.json +++ b/tooling/prettier/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.3.1", - "next": "14.2.5", "prettier": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.5" }, diff --git a/tooling/tailwind/package.json b/tooling/tailwind/package.json index ad9a8e41e..77d9d9cfa 100644 --- a/tooling/tailwind/package.json +++ b/tooling/tailwind/package.json @@ -15,7 +15,6 @@ }, "dependencies": { "autoprefixer": "^10.4.19", - "next": "14.2.5", "postcss": "8.4.39", "tailwindcss": "3.4.6", "tailwindcss-animate": "^1.0.7"