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"
This commit is contained in:
Giancarlo Buomprisco
2024-07-22 14:03:03 +08:00
committed by GitHub
parent 868f907c81
commit 5eefa7ff16
26 changed files with 477 additions and 168 deletions

View File

@@ -7,6 +7,7 @@ import dynamic from 'next/dynamic';
import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { ExclamationTriangleIcon } from '@radix-ui/react-icons';
import { PlanPicker } from '@kit/billing-gateway/components'; import { PlanPicker } from '@kit/billing-gateway/components';
import { useAppEvents } from '@kit/shared/events';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
import { import {
Card, Card,
@@ -40,6 +41,7 @@ export function PersonalAccountCheckoutForm(props: {
}) { }) {
const [pending, startTransition] = useTransition(); const [pending, startTransition] = useTransition();
const [error, setError] = useState(false); const [error, setError] = useState(false);
const appEvents = useAppEvents();
const [checkoutToken, setCheckoutToken] = useState<string | undefined>( const [checkoutToken, setCheckoutToken] = useState<string | undefined>(
undefined, undefined,
@@ -85,6 +87,11 @@ export function PersonalAccountCheckoutForm(props: {
onSubmit={({ planId, productId }) => { onSubmit={({ planId, productId }) => {
startTransition(async () => { startTransition(async () => {
try { try {
appEvents.emit({
type: 'checkout.started',
payload: { planId },
});
const { checkoutToken } = const { checkoutToken } =
await createPersonalAccountCheckoutSession({ await createPersonalAccountCheckoutSession({
planId, planId,

View File

@@ -6,6 +6,7 @@ import dynamic from 'next/dynamic';
import { useParams } from 'next/navigation'; import { useParams } from 'next/navigation';
import { PlanPicker } from '@kit/billing-gateway/components'; import { PlanPicker } from '@kit/billing-gateway/components';
import { useAppEvents } from '@kit/shared/events';
import { import {
Card, Card,
CardContent, CardContent,
@@ -38,6 +39,7 @@ export function TeamAccountCheckoutForm(params: {
}) { }) {
const routeParams = useParams(); const routeParams = useParams();
const [pending, startTransition] = useTransition(); const [pending, startTransition] = useTransition();
const appEvents = useAppEvents();
const [checkoutToken, setCheckoutToken] = useState<string | undefined>( const [checkoutToken, setCheckoutToken] = useState<string | undefined>(
undefined, undefined,
@@ -79,6 +81,14 @@ export function TeamAccountCheckoutForm(params: {
startTransition(async () => { startTransition(async () => {
const slug = routeParams.account as string; const slug = routeParams.account as string;
appEvents.emit({
type: 'checkout.started',
payload: {
planId,
account: slug,
},
});
const { checkoutToken } = await createTeamAccountCheckoutSession({ const { checkoutToken } = await createTeamAccountCheckoutSession({
planId, planId,
productId, productId,

View File

@@ -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<unknown>,
> = {
[K in AppEventType<T>]?: (event: AppEvent<T, K>) => void;
};
/**
* Hook to subscribe to app events and map them to analytics actions
* @param mapping
*/
function useAnalyticsMapping<T extends ConsumerProvidedEventTypes>(
mapping: AnalyticsMapping<T>,
) {
const appEvents = useAppEvents<T>();
useEffect(() => {
const subscriptions = Object.entries(mapping).map(
([eventType, handler]) => {
appEvents.on(eventType as AppEventType<T>, handler);
return () => appEvents.off(eventType as AppEventType<T>, 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]);
}

View File

@@ -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],
);
}

View File

@@ -1,5 +1,7 @@
'use client'; 'use client';
import { useMemo } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'; 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 { CaptchaProvider } from '@kit/auth/captcha/client';
import { I18nProvider } from '@kit/i18n/provider'; import { I18nProvider } from '@kit/i18n/provider';
import { MonitoringProvider } from '@kit/monitoring/components'; 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 { If } from '@kit/ui/if';
import { VersionUpdater } from '@kit/ui/version-updater'; 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 appConfig from '~/config/app.config';
import authConfig from '~/config/auth.config'; import authConfig from '~/config/auth.config';
import featuresFlagConfig from '~/config/feature-flags.config'; import featuresFlagConfig from '~/config/feature-flags.config';
import pathsConfig from '~/config/paths.config';
import { i18nResolver } from '~/lib/i18n/i18n.resolver'; import { i18nResolver } from '~/lib/i18n/i18n.resolver';
import { getI18nSettings } from '~/lib/i18n/i18n.settings'; import { getI18nSettings } from '~/lib/i18n/i18n.settings';
@@ -43,44 +46,39 @@ export function RootProviders({
lang: string; lang: string;
theme?: string; theme?: string;
}>) { }>) {
const i18nSettings = getI18nSettings(lang); const i18nSettings = useMemo(() => getI18nSettings(lang), [lang]);
return ( return (
<MonitoringProvider> <MonitoringProvider>
<ReactQueryProvider> <AppEventsProvider>
<ReactQueryStreamedHydration> <AnalyticsProvider>
<I18nProvider settings={i18nSettings} resolver={i18nResolver}> <ReactQueryProvider>
<CaptchaProvider> <ReactQueryStreamedHydration>
<CaptchaTokenSetter siteKey={captchaSiteKey} /> <I18nProvider settings={i18nSettings} resolver={i18nResolver}>
<CaptchaProvider>
<CaptchaTokenSetter siteKey={captchaSiteKey} />
<AuthProvider> <AuthProvider>
<ThemeProvider <ThemeProvider
attribute="class" attribute="class"
enableSystem enableSystem
disableTransitionOnChange disableTransitionOnChange
defaultTheme={theme} defaultTheme={theme}
enableColorScheme={false} enableColorScheme={false}
> >
{children} {children}
</ThemeProvider> </ThemeProvider>
</AuthProvider> </AuthProvider>
</CaptchaProvider> </CaptchaProvider>
<If condition={featuresFlagConfig.enableVersionUpdater}> <If condition={featuresFlagConfig.enableVersionUpdater}>
<VersionUpdater /> <VersionUpdater />
</If> </If>
</I18nProvider> </I18nProvider>
</ReactQueryStreamedHydration> </ReactQueryStreamedHydration>
</ReactQueryProvider> </ReactQueryProvider>
</AnalyticsProvider>
</AppEventsProvider>
</MonitoringProvider> </MonitoringProvider>
); );
} }
// we place this below React Query since it uses the QueryClient
function AuthProvider(props: React.PropsWithChildren) {
useAuthChangeListener({
appHomePath: pathsConfig.app.home,
});
return props.children;
}

View File

@@ -31,10 +31,11 @@
"supabase:db:dump:local": "supabase db dump --local --data-only" "supabase:db:dump:local": "supabase db dump --local --data-only"
}, },
"dependencies": { "dependencies": {
"@edge-csrf/nextjs": "2.2.2", "@edge-csrf/nextjs": "2.3.0-rc1",
"@hookform/resolvers": "^3.9.0", "@hookform/resolvers": "^3.9.0",
"@kit/accounts": "workspace:^", "@kit/accounts": "workspace:^",
"@kit/admin": "workspace:^", "@kit/admin": "workspace:^",
"@kit/analytics": "workspace:^",
"@kit/auth": "workspace:^", "@kit/auth": "workspace:^",
"@kit/billing": "workspace:^", "@kit/billing": "workspace:^",
"@kit/billing-gateway": "workspace:^", "@kit/billing-gateway": "workspace:^",
@@ -55,11 +56,11 @@
"@marsidev/react-turnstile": "^0.7.2", "@marsidev/react-turnstile": "^0.7.2",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@supabase/supabase-js": "^2.44.4", "@supabase/supabase-js": "^2.44.4",
"@tanstack/react-query": "5.51.9", "@tanstack/react-query": "5.51.11",
"@tanstack/react-query-next-experimental": "^5.51.9", "@tanstack/react-query-next-experimental": "^5.51.11",
"@tanstack/react-table": "^8.19.3", "@tanstack/react-table": "^8.19.3",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"next": "14.2.5", "next": "14.2.5",
"next-sitemap": "^4.2.3", "next-sitemap": "^4.2.3",
"next-themes": "0.3.0", "next-themes": "0.3.0",

View File

@@ -36,7 +36,7 @@
"@manypkg/cli": "^0.21.4", "@manypkg/cli": "^0.21.4",
"@turbo/gen": "^2.0.9", "@turbo/gen": "^2.0.9",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"pnpm": "^9.5.0", "pnpm": "^9.6.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"turbo": "2.0.9", "turbo": "2.0.9",
"typescript": "^5.5.3" "typescript": "^5.5.3"

View File

@@ -1,5 +1,5 @@
import { NullAnalyticsService } from './null-analytics-service'; import { NullAnalyticsService } from './null-analytics-service';
import { import type {
AnalyticsManager, AnalyticsManager,
AnalyticsService, AnalyticsService,
CreateAnalyticsManagerOptions, CreateAnalyticsManagerOptions,
@@ -18,7 +18,7 @@ export function createAnalyticsManager<T extends string, Config extends object>(
const getActiveService = (): AnalyticsService => { const getActiveService = (): AnalyticsService => {
if (activeService === NullAnalyticsService) { if (activeService === NullAnalyticsService) {
console.warn( console.debug(
'Analytics service not initialized. Using NullAnalyticsService.', 'Analytics service not initialized. Using NullAnalyticsService.',
); );
} }
@@ -30,7 +30,7 @@ export function createAnalyticsManager<T extends string, Config extends object>(
const factory = options.providers[provider]; const factory = options.providers[provider];
if (!factory) { if (!factory) {
console.error( console.warn(
`Analytics provider '${provider}' not registered. Using NullAnalyticsService.`, `Analytics provider '${provider}' not registered. Using NullAnalyticsService.`,
); );
@@ -57,6 +57,7 @@ export function createAnalyticsManager<T extends string, Config extends object>(
trackPageView: (url: string) => { trackPageView: (url: string) => {
return getActiveService().trackPageView(url); return getActiveService().trackPageView(url);
}, },
/** /**
* Track an event with the given name and properties. * Track an event with the given name and properties.
* @param eventName * @param eventName

View File

@@ -1,7 +1,14 @@
import { AnalyticsService } from './types'; import { AnalyticsService } from './types';
const noop = () => { const noop = (event: string) => {
// do nothing - this is to prevent errors when the analytics service is not initialized // 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. * the user is calling analytics methods before the analytics service is initialized.
*/ */
export const NullAnalyticsService: AnalyticsService = { export const NullAnalyticsService: AnalyticsService = {
initialize: noop, initialize: noop('initialize'),
trackPageView: noop, trackPageView: noop('trackPageView'),
trackEvent: noop, trackEvent: noop('trackEvent'),
identify: noop, identify: noop('identify'),
}; };

View File

@@ -30,7 +30,7 @@
"@supabase/supabase-js": "^2.44.4", "@supabase/supabase-js": "^2.44.4",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"next": "14.2.5", "next": "14.2.5",
"react": "18.3.1", "react": "18.3.1",
"react-hook-form": "^7.52.1", "react-hook-form": "^7.52.1",

View File

@@ -35,10 +35,10 @@
"@kit/ui": "workspace:^", "@kit/ui": "workspace:^",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@supabase/supabase-js": "^2.44.4", "@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": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"next": "14.2.5", "next": "14.2.5",
"next-themes": "0.3.0", "next-themes": "0.3.0",
"react": "18.3.1", "react": "18.3.1",

View File

@@ -22,10 +22,10 @@
"@makerkit/data-loader-supabase-core": "^0.0.8", "@makerkit/data-loader-supabase-core": "^0.0.8",
"@makerkit/data-loader-supabase-nextjs": "^1.2.3", "@makerkit/data-loader-supabase-nextjs": "^1.2.3",
"@supabase/supabase-js": "^2.44.4", "@supabase/supabase-js": "^2.44.4",
"@tanstack/react-query": "5.51.9", "@tanstack/react-query": "5.51.11",
"@tanstack/react-table": "^8.19.3", "@tanstack/react-table": "^8.19.3",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"next": "14.2.5", "next": "14.2.5",
"react": "18.3.1", "react": "18.3.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",

View File

@@ -29,9 +29,9 @@
"@marsidev/react-turnstile": "^0.7.2", "@marsidev/react-turnstile": "^0.7.2",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@supabase/supabase-js": "^2.44.4", "@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": "^18.3.3",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"next": "14.2.5", "next": "14.2.5",
"react-hook-form": "^7.52.1", "react-hook-form": "^7.52.1",
"react-i18next": "^15.0.0", "react-i18next": "^15.0.0",

View File

@@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { z } from 'zod'; import { z } from 'zod';
import { useAppEvents } from '@kit/shared/events';
import { useSignInWithOtp } from '@kit/supabase/hooks/use-sign-in-with-otp'; import { useSignInWithOtp } from '@kit/supabase/hooks/use-sign-in-with-otp';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
import { Button } from '@kit/ui/button'; import { Button } from '@kit/ui/button';
@@ -44,6 +45,7 @@ export function MagicLinkAuthContainer({
const { captchaToken, resetCaptchaToken } = useCaptchaToken(); const { captchaToken, resetCaptchaToken } = useCaptchaToken();
const { t } = useTranslation(); const { t } = useTranslation();
const signInWithOtpMutation = useSignInWithOtp(); const signInWithOtpMutation = useSignInWithOtp();
const appEvents = useAppEvents();
const form = useForm({ const form = useForm({
resolver: zodResolver( resolver: zodResolver(
@@ -65,8 +67,8 @@ export function MagicLinkAuthContainer({
const emailRedirectTo = url.href; const emailRedirectTo = url.href;
const promise = () => const promise = async () => {
signInWithOtpMutation.mutateAsync({ await signInWithOtpMutation.mutateAsync({
email, email,
options: { options: {
emailRedirectTo, emailRedirectTo,
@@ -75,6 +77,14 @@ export function MagicLinkAuthContainer({
}, },
}); });
appEvents.emit({
type: 'user.signedUp',
payload: {
method: 'magiclink',
},
});
};
toast.promise(promise, { toast.promise(promise, {
loading: t('auth:sendingEmailLink'), loading: t('auth:sendingEmailLink'),
success: t(`auth:sendLinkSuccessToast`), success: t(`auth:sendLinkSuccessToast`),

View File

@@ -4,6 +4,7 @@ import { useCallback, useRef, useState } from 'react';
import { CheckCircledIcon } from '@radix-ui/react-icons'; 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 { useSignUpWithEmailAndPassword } from '@kit/supabase/hooks/use-sign-up-with-email-password';
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
import { If } from '@kit/ui/if'; import { If } from '@kit/ui/if';
@@ -33,8 +34,10 @@ export function EmailPasswordSignUpContainer({
const signUpMutation = useSignUpWithEmailAndPassword(); const signUpMutation = useSignUpWithEmailAndPassword();
const redirecting = useRef(false); const redirecting = useRef(false);
const loading = signUpMutation.isPending || redirecting.current;
const [showVerifyEmailAlert, setShowVerifyEmailAlert] = useState(false); const [showVerifyEmailAlert, setShowVerifyEmailAlert] = useState(false);
const appEvents = useAppEvents();
const loading = signUpMutation.isPending || redirecting.current;
const onSignupRequested = useCallback( const onSignupRequested = useCallback(
async (credentials: { email: string; password: string }) => { async (credentials: { email: string; password: string }) => {
@@ -49,6 +52,13 @@ export function EmailPasswordSignUpContainer({
captchaToken, captchaToken,
}); });
appEvents.emit({
type: 'user.signedUp',
payload: {
method: 'password',
},
});
setShowVerifyEmailAlert(true); setShowVerifyEmailAlert(true);
if (onSignUp) { if (onSignUp) {
@@ -61,6 +71,7 @@ export function EmailPasswordSignUpContainer({
} }
}, },
[ [
appEvents,
captchaToken, captchaToken,
emailRedirectTo, emailRedirectTo,
loading, loading,

View File

@@ -21,9 +21,9 @@
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@supabase/supabase-js": "^2.44.4", "@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": "^18.3.3",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"react": "18.3.1", "react": "18.3.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-i18next": "^15.0.0" "react-i18next": "^15.0.0"

View File

@@ -33,13 +33,13 @@
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:^", "@kit/ui": "workspace:^",
"@supabase/supabase-js": "^2.44.4", "@supabase/supabase-js": "^2.44.4",
"@tanstack/react-query": "5.51.9", "@tanstack/react-query": "5.51.11",
"@tanstack/react-table": "^8.19.3", "@tanstack/react-table": "^8.19.3",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"next": "14.2.5", "next": "14.2.5",
"react": "18.3.1", "react": "18.3.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",

View File

@@ -21,7 +21,7 @@
"@kit/shared": "workspace:^", "@kit/shared": "workspace:^",
"@kit/tailwind-config": "workspace:*", "@kit/tailwind-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@tanstack/react-query": "5.51.9", "@tanstack/react-query": "5.51.11",
"react-i18next": "^15.0.0" "react-i18next": "^15.0.0"
}, },
"dependencies": { "dependencies": {

View File

@@ -12,14 +12,15 @@
"exports": { "exports": {
"./logger": "./src/logger/index.ts", "./logger": "./src/logger/index.ts",
"./utils": "./src/utils.ts", "./utils": "./src/utils.ts",
"./hooks": "./src/hooks/index.ts" "./hooks": "./src/hooks/index.ts",
"./events": "./src/events/index.tsx"
}, },
"devDependencies": { "devDependencies": {
"@kit/eslint-config": "workspace:*", "@kit/eslint-config": "workspace:*",
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tailwind-config": "workspace:*", "@kit/tailwind-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@tanstack/react-table": "^8.19.3" "@types/react": "^18.3.3"
}, },
"dependencies": { "dependencies": {
"pino": "^9.3.1" "pino": "^9.3.1"

View File

@@ -0,0 +1,118 @@
'use client';
import { createContext, useCallback, useContext, useRef } from 'react';
type EmptyPayload = NonNullable<unknown>;
// 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<T extends ConsumerProvidedEventTypes> =
keyof ExtendedAppEventTypes<T>;
export type AppEvent<
T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes,
K extends AppEventType<T> = AppEventType<T>,
> = {
type: K;
payload: ExtendedAppEventTypes<T>[K];
};
export type EventCallback<
T extends ConsumerProvidedEventTypes,
K extends AppEventType<T> = AppEventType<T>,
> = (event: AppEvent<T, K>) => void;
interface InternalAppEventsContextType<
T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes,
K extends AppEventType<T> = AppEventType<T>,
> {
emit: (event: AppEvent<never, never>) => void;
on: (eventType: K, callback: EventCallback<T, K>) => void;
off: (eventType: K, callback: EventCallback<T, K>) => void;
}
interface AppEventsContextType<T extends ConsumerProvidedEventTypes> {
emit: <K extends AppEventType<T>>(event: AppEvent<T, K>) => void;
on: <K extends AppEventType<T>>(
eventType: K,
callback: EventCallback<T, K>,
) => void;
off: <K extends AppEventType<T>>(
eventType: K,
callback: EventCallback<T, K>,
) => void;
}
const AppEventsContext = createContext<InternalAppEventsContextType | null>(
null,
);
export function AppEventsProvider<
T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes,
K extends AppEventType<T> = AppEventType<T>,
>({ children }: React.PropsWithChildren) {
const listeners = useRef<Record<K, EventCallback<T, K>[]>>(
{} as Record<K, EventCallback<T, K>[]>,
);
const emit = useCallback(
(event: AppEvent<T, K>) => {
const eventListeners = listeners.current[event.type] ?? [];
eventListeners.forEach((callback) => callback(event));
},
[listeners],
);
const on = useCallback((eventType: K, callback: EventCallback<T, K>) => {
listeners.current = {
...listeners.current,
[eventType]: [...(listeners.current[eventType] ?? []), callback],
};
}, []) as AppEventsContextType<T>['on'];
const off = useCallback((eventType: K, callback: EventCallback<T, K>) => {
listeners.current = {
...listeners.current,
[eventType]: (listeners.current[eventType] ?? []).filter(
(cb) => cb !== callback,
),
};
}, []) as AppEventsContextType<T>['off'];
return (
<AppEventsContext.Provider value={{ emit, on, off }}>
{children}
</AppEventsContext.Provider>
);
}
export function useAppEvents<
T extends ConsumerProvidedEventTypes = ConsumerProvidedEventTypes,
>(): AppEventsContextType<T> {
const context = useContext(AppEventsContext);
if (!context) {
throw new Error('useAppEvents must be used within an AppEventsProvider');
}
return context as AppEventsContextType<T>;
}

View File

@@ -29,7 +29,7 @@
"@supabase/gotrue-js": "2.64.4", "@supabase/gotrue-js": "2.64.4",
"@supabase/ssr": "^0.4.0", "@supabase/ssr": "^0.4.0",
"@supabase/supabase-js": "^2.44.4", "@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": "^18.3.3",
"next": "14.2.5", "next": "14.2.5",
"react": "18.3.1", "react": "18.3.1",

View File

@@ -4,6 +4,8 @@ import { useEffect } from 'react';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import type { AuthChangeEvent, Session } from '@supabase/supabase-js';
import { useSupabase } from './use-supabase'; import { useSupabase } from './use-supabase';
/** /**
@@ -14,15 +16,18 @@ const PRIVATE_PATH_PREFIXES = ['/home', '/admin', '/join', '/update-password'];
/** /**
* @name useAuthChangeListener * @name useAuthChangeListener
* @param privatePathPrefixes * @param privatePathPrefixes - A list of private path prefixes
* @param appHomePath * @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({ export function useAuthChangeListener({
privatePathPrefixes = PRIVATE_PATH_PREFIXES, privatePathPrefixes = PRIVATE_PATH_PREFIXES,
appHomePath, appHomePath,
onEvent,
}: { }: {
appHomePath: string; appHomePath: string;
privatePathPrefixes?: string[]; privatePathPrefixes?: string[];
onEvent?: (event: AuthChangeEvent, user: Session | null) => void;
}) { }) {
const client = useSupabase(); const client = useSupabase();
const pathName = usePathname(); const pathName = usePathname();
@@ -30,6 +35,10 @@ export function useAuthChangeListener({
useEffect(() => { useEffect(() => {
// keep this running for the whole session unless the component was unmounted // keep this running for the whole session unless the component was unmounted
const listener = client.auth.onAuthStateChange((event, user) => { const listener = client.auth.onAuthStateChange((event, user) => {
if (onEvent) {
onEvent(event, user);
}
// log user out if user is falsy // log user out if user is falsy
// and if the current path is a private route // and if the current path is a private route
const shouldRedirectUser = const shouldRedirectUser =
@@ -50,7 +59,7 @@ export function useAuthChangeListener({
// destroy listener on un-mounts // destroy listener on un-mounts
return () => listener.data.subscription.unsubscribe(); return () => listener.data.subscription.unsubscribe();
}, [client.auth, pathName, appHomePath, privatePathPrefixes]); }, [client.auth, pathName, appHomePath, privatePathPrefixes, onEvent]);
} }
/** /**

View File

@@ -31,7 +31,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "1.0.0", "cmdk": "1.0.0",
"input-otp": "1.2.4", "input-otp": "1.2.4",
"lucide-react": "^0.411.0", "lucide-react": "^0.412.0",
"react-top-loading-bar": "2.3.1", "react-top-loading-bar": "2.3.1",
"tailwind-merge": "^2.4.0" "tailwind-merge": "^2.4.0"
}, },
@@ -41,7 +41,7 @@
"@kit/tailwind-config": "workspace:*", "@kit/tailwind-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@radix-ui/react-icons": "^1.3.0", "@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", "@tanstack/react-table": "^8.19.3",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",

185
pnpm-lock.yaml generated
View File

@@ -22,8 +22,8 @@ importers:
specifier: ^7.0.3 specifier: ^7.0.3
version: 7.0.3 version: 7.0.3
pnpm: pnpm:
specifier: ^9.5.0 specifier: ^9.6.0
version: 9.5.0 version: 9.6.0
prettier: prettier:
specifier: ^3.3.3 specifier: ^3.3.3
version: 3.3.3 version: 3.3.3
@@ -49,8 +49,8 @@ importers:
apps/web: apps/web:
dependencies: dependencies:
'@edge-csrf/nextjs': '@edge-csrf/nextjs':
specifier: 2.2.2 specifier: 2.3.0-rc1
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)) 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': '@hookform/resolvers':
specifier: ^3.9.0 specifier: ^3.9.0
version: 3.9.0(react-hook-form@7.52.1(react@18.3.1)) version: 3.9.0(react-hook-form@7.52.1(react@18.3.1))
@@ -60,6 +60,9 @@ importers:
'@kit/admin': '@kit/admin':
specifier: workspace:^ specifier: workspace:^
version: link:../../packages/features/admin version: link:../../packages/features/admin
'@kit/analytics':
specifier: workspace:^
version: link:../../packages/analytics
'@kit/auth': '@kit/auth':
specifier: workspace:^ specifier: workspace:^
version: link:../../packages/features/auth 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) version: 0.0.8(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)
'@makerkit/data-loader-supabase-nextjs': '@makerkit/data-loader-supabase-nextjs':
specifier: ^1.2.3 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': '@marsidev/react-turnstile':
specifier: ^0.7.2 specifier: ^0.7.2
version: 0.7.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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 specifier: ^2.44.4
version: 2.44.4 version: 2.44.4
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@tanstack/react-query-next-experimental': '@tanstack/react-query-next-experimental':
specifier: ^5.51.9 specifier: ^5.51.11
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) 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': '@tanstack/react-table':
specifier: ^8.19.3 specifier: ^8.19.3
version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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 specifier: ^3.6.0
version: 3.6.0 version: 3.6.0
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
next: next:
specifier: 14.2.5 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: next-sitemap:
specifier: ^4.2.3 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)) 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 specifier: ^3.6.0
version: 3.6.0 version: 3.6.0
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
next: next:
specifier: 14.2.5 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: react:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1 version: 18.3.1
@@ -355,7 +358,7 @@ importers:
version: 18.3.3 version: 18.3.3
next: next:
specifier: 14.2.5 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: react:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1 version: 18.3.1
@@ -407,7 +410,7 @@ importers:
version: 3.6.0 version: 3.6.0
next: next:
specifier: 14.2.5 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: react:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1 version: 18.3.1
@@ -607,8 +610,8 @@ importers:
specifier: ^2.44.4 specifier: ^2.44.4
version: 2.44.4 version: 2.44.4
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@types/react': '@types/react':
specifier: ^18.3.3 specifier: ^18.3.3
version: 18.3.3 version: 18.3.3
@@ -616,11 +619,11 @@ importers:
specifier: ^18.3.0 specifier: ^18.3.0
version: 18.3.0 version: 18.3.0
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
next: next:
specifier: 14.2.5 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: next-themes:
specifier: 0.3.0 specifier: 0.3.0
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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) version: 0.0.8(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4)
'@makerkit/data-loader-supabase-nextjs': '@makerkit/data-loader-supabase-nextjs':
specifier: ^1.2.3 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': '@supabase/supabase-js':
specifier: ^2.44.4 specifier: ^2.44.4
version: 2.44.4 version: 2.44.4
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@tanstack/react-table': '@tanstack/react-table':
specifier: ^8.19.3 specifier: ^8.19.3
version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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 specifier: ^18.3.3
version: 18.3.3 version: 18.3.3
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
next: next:
specifier: 14.2.5 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: react:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1 version: 18.3.1
@@ -745,17 +748,17 @@ importers:
specifier: ^2.44.4 specifier: ^2.44.4
version: 2.44.4 version: 2.44.4
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@types/react': '@types/react':
specifier: ^18.3.3 specifier: ^18.3.3
version: 18.3.3 version: 18.3.3
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
next: next:
specifier: 14.2.5 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: react-hook-form:
specifier: ^7.52.1 specifier: ^7.52.1
version: 7.52.1(react@18.3.1) version: 7.52.1(react@18.3.1)
@@ -793,14 +796,14 @@ importers:
specifier: ^2.44.4 specifier: ^2.44.4
version: 2.44.4 version: 2.44.4
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@types/react': '@types/react':
specifier: ^18.3.3 specifier: ^18.3.3
version: 18.3.3 version: 18.3.3
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
react: react:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1 version: 18.3.1
@@ -863,8 +866,8 @@ importers:
specifier: ^2.44.4 specifier: ^2.44.4
version: 2.44.4 version: 2.44.4
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@tanstack/react-table': '@tanstack/react-table':
specifier: ^8.19.3 specifier: ^8.19.3
version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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 specifier: ^3.6.0
version: 3.6.0 version: 3.6.0
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
next: next:
specifier: 14.2.5 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: react:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1 version: 18.3.1
@@ -933,8 +936,8 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../../tooling/typescript version: link:../../tooling/typescript
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
react-i18next: react-i18next:
specifier: ^15.0.0 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) 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: dependencies:
'@sentry/nextjs': '@sentry/nextjs':
specifier: ^8.19.0 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: devDependencies:
'@kit/eslint-config': '@kit/eslint-config':
specifier: workspace:* specifier: workspace:*
@@ -1108,7 +1111,7 @@ importers:
version: 2.44.4 version: 2.44.4
next: next:
specifier: 14.2.5 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: zod:
specifier: ^3.23.8 specifier: ^3.23.8
version: 3.23.8 version: 3.23.8
@@ -1131,9 +1134,9 @@ importers:
'@kit/tsconfig': '@kit/tsconfig':
specifier: workspace:* specifier: workspace:*
version: link:../../tooling/typescript version: link:../../tooling/typescript
'@tanstack/react-table': '@types/react':
specifier: ^8.19.3 specifier: ^18.3.3
version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 18.3.3
packages/supabase: packages/supabase:
devDependencies: devDependencies:
@@ -1159,14 +1162,14 @@ importers:
specifier: ^2.44.4 specifier: ^2.44.4
version: 2.44.4 version: 2.44.4
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@types/react': '@types/react':
specifier: ^18.3.3 specifier: ^18.3.3
version: 18.3.3 version: 18.3.3
next: next:
specifier: 14.2.5 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: react:
specifier: 18.3.1 specifier: 18.3.1
version: 18.3.1 version: 18.3.1
@@ -1246,8 +1249,8 @@ importers:
specifier: 1.2.4 specifier: 1.2.4
version: 1.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.2.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
lucide-react: lucide-react:
specifier: ^0.411.0 specifier: ^0.412.0
version: 0.411.0(react@18.3.1) version: 0.412.0(react@18.3.1)
react-top-loading-bar: react-top-loading-bar:
specifier: 2.3.1 specifier: 2.3.1
version: 2.3.1(react@18.3.1) version: 2.3.1(react@18.3.1)
@@ -1271,8 +1274,8 @@ importers:
specifier: ^1.3.0 specifier: ^1.3.0
version: 1.3.0(react@18.3.1) version: 1.3.0(react@18.3.1)
'@tanstack/react-query': '@tanstack/react-query':
specifier: 5.51.9 specifier: 5.51.11
version: 5.51.9(react@18.3.1) version: 5.51.11(react@18.3.1)
'@tanstack/react-table': '@tanstack/react-table':
specifier: ^8.19.3 specifier: ^8.19.3
version: 8.19.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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 version: 8.57.0
next: next:
specifier: 14.2.5 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: next-themes:
specifier: 0.3.0 specifier: 0.3.0
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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': '@ianvs/prettier-plugin-sort-imports':
specifier: ^4.3.1 specifier: ^4.3.1
version: 4.3.1(prettier@3.3.3) 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: prettier:
specifier: ^3.3.3 specifier: ^3.3.3
version: 3.3.3 version: 3.3.3
@@ -1398,9 +1398,6 @@ importers:
autoprefixer: autoprefixer:
specifier: ^10.4.19 specifier: ^10.4.19
version: 10.4.19(postcss@8.4.39) 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: postcss:
specifier: 8.4.39 specifier: 8.4.39
version: 8.4.39 version: 8.4.39
@@ -1609,8 +1606,8 @@ packages:
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
'@edge-csrf/nextjs@2.2.2': '@edge-csrf/nextjs@2.3.0-rc1':
resolution: {integrity: sha512-+RRcNzm2QSGPaXgOcnhE+yw36BMXLBKQnWA3db0xCpAOEOb4dEwQNxVGd7Fz6CKQ4yIdBJuqHasBSmtZB6lHUQ==} resolution: {integrity: sha512-2Nchl8TO3pTcAgjSKYYDq8viYmBs4EDWlgZhWI+GX2/o2b3MfptOHUDprTpVPvkUzP8xXLq4WsXp60LUeOkggQ==}
peerDependencies: peerDependencies:
next: ^13.0.0 || ^14.0.0 next: ^13.0.0 || ^14.0.0
@@ -3850,15 +3847,15 @@ packages:
'@tanstack/query-core@5.51.9': '@tanstack/query-core@5.51.9':
resolution: {integrity: sha512-HsAwaY5J19MD18ykZDS3aVVh+bAt0i7m6uQlFC2b77DLV9djo+xEN7MWQAQQTR8IM+7r/zbozTQ7P0xr0bHuew==} resolution: {integrity: sha512-HsAwaY5J19MD18ykZDS3aVVh+bAt0i7m6uQlFC2b77DLV9djo+xEN7MWQAQQTR8IM+7r/zbozTQ7P0xr0bHuew==}
'@tanstack/react-query-next-experimental@5.51.9': '@tanstack/react-query-next-experimental@5.51.11':
resolution: {integrity: sha512-DwCeh1GsppH2c3sN8BzJU2MArH887E3UzNtstZBEhb7SBKzxutnWmwbHUPi1JbIe+6KkPXLsgUjlxEGWAxOsQw==} resolution: {integrity: sha512-gUYTz9KYUbyxSek7U3o1J4efqzfNZICd3XvBhfz5i0rrxx7hKghx18fL87vH2N9UxYS5V5DjjX3dIp4m/u+Nvg==}
peerDependencies: peerDependencies:
'@tanstack/react-query': ^5.51.9 '@tanstack/react-query': ^5.51.11
next: ^13 || ^14 || ^15 next: ^13 || ^14 || ^15
react: 18.3.1 react: 18.3.1
'@tanstack/react-query@5.51.9': '@tanstack/react-query@5.51.11':
resolution: {integrity: sha512-F8j6i42wfKvFrRcxfOyFyYME+bPfNthAGOSkjdv4UwZZXJjnBnBs/yRQGT0bD23LVCTuBzlIfZ0GKSIyclZ9rQ==} resolution: {integrity: sha512-4Kq2x0XpDlpvSnaLG+8pHNH60zEc3mBvb3B2tOMDjcPCi/o+Du3p/9qpPLwJOTliVxxPJAP27fuIhLrsRdCr7A==}
peerDependencies: peerDependencies:
react: 18.3.1 react: 18.3.1
@@ -5894,8 +5891,8 @@ packages:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
engines: {node: '>=12'} engines: {node: '>=12'}
lucide-react@0.411.0: lucide-react@0.412.0:
resolution: {integrity: sha512-bDRvLt/jIIjsq4JVYB3EjyOtLHu8uQGzv7usri2DnVpOtfIRuLln96srS+d8WJsmJ52LBwDnYx7me/TSjZ6AcA==} resolution: {integrity: sha512-m7argY/PhSfjhwP2Dxey+VzFBvusfd8ULt+vWWFnzQhURLOtNyD1qWmMVdtJ4Nn+d+DTcoOiILrjThSjY9kaow==}
peerDependencies: peerDependencies:
react: 18.3.1 react: 18.3.1
@@ -6502,8 +6499,8 @@ packages:
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
pnpm@9.5.0: pnpm@9.6.0:
resolution: {integrity: sha512-FAA2gwEkYY1iSiGHtQ0EKJ1aCH8ybJ7fwMzXM9dsT1LDoxPU/BSHlKKp2BVTAWAE5nQujPhQZwJopzh/wiDJAw==} resolution: {integrity: sha512-ONxvuo26NbOTQLlwARLC/h4S8QsXE0cVpKqYzPe7A152/Zgc8Ls4TfqY+NavVIHCvvL0Jmokv6IMNOtxR84LXg==}
engines: {node: '>=18.12'} engines: {node: '>=18.12'}
hasBin: true hasBin: true
@@ -8046,9 +8043,9 @@ snapshots:
'@discoveryjs/json-ext@0.5.7': {} '@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: 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': '@emotion/babel-plugin@11.11.0':
dependencies: dependencies:
@@ -8374,7 +8371,7 @@ snapshots:
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
optionalDependencies: 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: transitivePeerDependencies:
- supports-color - 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) '@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 '@types/react': 18.3.3
chokidar: 3.6.0 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: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
server-only: 0.0.1 server-only: 0.0.1
@@ -8477,12 +8474,12 @@ snapshots:
'@supabase/supabase-js': 2.44.4 '@supabase/supabase-js': 2.44.4
ts-case-convert: 2.0.7 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: dependencies:
'@makerkit/data-loader-supabase-core': 0.0.8(@supabase/postgrest-js@1.15.8)(@supabase/supabase-js@2.44.4) '@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 '@supabase/supabase-js': 2.44.4
'@tanstack/react-query': 5.51.9(react@18.3.1) '@tanstack/react-query': 5.51.11(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)
react: 18.3.1 react: 18.3.1
transitivePeerDependencies: transitivePeerDependencies:
- '@supabase/postgrest-js' - '@supabase/postgrest-js'
@@ -10878,7 +10875,7 @@ snapshots:
'@sentry/types': 8.19.0 '@sentry/types': 8.19.0
'@sentry/utils': 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: dependencies:
'@opentelemetry/instrumentation-http': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation-http': 0.52.1(@opentelemetry/api@1.9.0)
'@opentelemetry/semantic-conventions': 1.25.1 '@opentelemetry/semantic-conventions': 1.25.1
@@ -10892,7 +10889,7 @@ snapshots:
'@sentry/vercel-edge': 8.19.0 '@sentry/vercel-edge': 8.19.0
'@sentry/webpack-plugin': 2.20.1(webpack@5.93.0) '@sentry/webpack-plugin': 2.20.1(webpack@5.93.0)
chalk: 3.0.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 resolve: 1.22.8
rollup: 3.29.4 rollup: 3.29.4
stacktrace-parser: 0.1.10 stacktrace-parser: 0.1.10
@@ -11074,13 +11071,13 @@ snapshots:
'@tanstack/query-core@5.51.9': {} '@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: dependencies:
'@tanstack/react-query': 5.51.9(react@18.3.1) '@tanstack/react-query': 5.51.11(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)
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: dependencies:
'@tanstack/query-core': 5.51.9 '@tanstack/query-core': 5.51.9
react: 18.3.1 react: 18.3.1
@@ -13384,7 +13381,7 @@ snapshots:
lru-cache@7.18.3: {} lru-cache@7.18.3: {}
lucide-react@0.411.0(react@18.3.1): lucide-react@0.412.0(react@18.3.1):
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -13913,14 +13910,14 @@ snapshots:
'@next/env': 13.5.6 '@next/env': 13.5.6
fast-glob: 3.3.2 fast-glob: 3.3.2
minimist: 1.2.8 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): next-themes@0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(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: dependencies:
'@next/env': 14.2.5 '@next/env': 14.2.5
'@swc/helpers': 0.5.5 '@swc/helpers': 0.5.5
@@ -13930,7 +13927,7 @@ snapshots:
postcss: 8.4.31 postcss: 8.4.31
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(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: optionalDependencies:
'@next/swc-darwin-arm64': 14.2.5 '@next/swc-darwin-arm64': 14.2.5
'@next/swc-darwin-x64': 14.2.5 '@next/swc-darwin-x64': 14.2.5
@@ -14268,7 +14265,7 @@ snapshots:
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: 2.3.2
pnpm@9.5.0: {} pnpm@9.6.0: {}
possible-typed-array-names@1.0.0: {} possible-typed-array-names@1.0.0: {}
@@ -14997,12 +14994,10 @@ snapshots:
'@types/node': 20.14.11 '@types/node': 20.14.11
qs: 6.12.2 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: dependencies:
client-only: 0.0.1 client-only: 0.0.1
react: 18.3.1 react: 18.3.1
optionalDependencies:
'@babel/core': 7.24.9
stylis@4.2.0: {} stylis@4.2.0: {}

View File

@@ -10,7 +10,6 @@
}, },
"dependencies": { "dependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.3.1", "@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"next": "14.2.5",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.5" "prettier-plugin-tailwindcss": "^0.6.5"
}, },

View File

@@ -15,7 +15,6 @@
}, },
"dependencies": { "dependencies": {
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"next": "14.2.5",
"postcss": "8.4.39", "postcss": "8.4.39",
"tailwindcss": "3.4.6", "tailwindcss": "3.4.6",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7"