diff --git a/apps/basic-integration/next-js/15-pages-router-saas/.env.example b/apps/basic-integration/next-js/15-pages-router-saas/.env.example index 9f67031a4..b4bea38eb 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/.env.example +++ b/apps/basic-integration/next-js/15-pages-router-saas/.env.example @@ -8,4 +8,8 @@ AUTH_SECRET=*** # Stripe Stub Mode (optional) # Set to 'stub' to use mock Stripe implementation without real API keys -# STRIPE_MODE=stub \ No newline at end of file +# STRIPE_MODE=stub + +# PostHog Configuration +NEXT_PUBLIC_POSTHOG_KEY=your_posthog_project_token_here +NEXT_PUBLIC_POSTHOG_HOST=https://your-posthog-host \ No newline at end of file diff --git a/apps/basic-integration/next-js/15-pages-router-saas/.gitignore b/apps/basic-integration/next-js/15-pages-router-saas/.gitignore new file mode 100644 index 000000000..5003a6f5a --- /dev/null +++ b/apps/basic-integration/next-js/15-pages-router-saas/.gitignore @@ -0,0 +1,2 @@ +.env.local +.env diff --git a/apps/basic-integration/next-js/15-pages-router-saas/components/error-boundary.tsx b/apps/basic-integration/next-js/15-pages-router-saas/components/error-boundary.tsx new file mode 100644 index 000000000..913206be1 --- /dev/null +++ b/apps/basic-integration/next-js/15-pages-router-saas/components/error-boundary.tsx @@ -0,0 +1,40 @@ +import { Component, type ErrorInfo, type ReactNode } from 'react'; +import posthog from 'posthog-js'; + +type ErrorBoundaryProps = { + children: ReactNode; +}; + +type ErrorBoundaryState = { + hasError: boolean; +}; + +export default class ErrorBoundary extends Component< + ErrorBoundaryProps, + ErrorBoundaryState +> { + state: ErrorBoundaryState = { hasError: false }; + + static getDerivedStateFromError(): ErrorBoundaryState { + return { hasError: true }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + if ( + process.env.NEXT_PUBLIC_POSTHOG_KEY && + process.env.NEXT_PUBLIC_POSTHOG_HOST + ) { + posthog.captureException(error, { + component_stack: errorInfo.componentStack + }); + } + } + + render() { + if (this.state.hasError) { + return

Something went wrong. Please refresh the page and try again.

; + } + + return this.props.children; + } +} diff --git a/apps/basic-integration/next-js/15-pages-router-saas/components/header.tsx b/apps/basic-integration/next-js/15-pages-router-saas/components/header.tsx index f9a68851f..c2cd431f6 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/components/header.tsx +++ b/apps/basic-integration/next-js/15-pages-router-saas/components/header.tsx @@ -14,8 +14,13 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { useRouter } from 'next/router'; import { User } from '@/lib/db/schema'; import useSWR, { mutate } from 'swr'; +import posthog from 'posthog-js'; const fetcher = (url: string) => fetch(url).then((res) => res.json()); +const posthogConfigured = Boolean( + process.env.NEXT_PUBLIC_POSTHOG_KEY && + process.env.NEXT_PUBLIC_POSTHOG_HOST +); function UserMenu() { const [isMenuOpen, setIsMenuOpen] = useState(false); @@ -25,10 +30,18 @@ function UserMenu() { async function handleSignOut() { try { // Call sign-out API to delete HttpOnly session cookie - await fetch('/api/auth/sign-out', { + const response = await fetch('/api/auth/sign-out', { method: 'POST' }); + if (!response.ok) { + throw new Error('Failed to sign out'); + } + + if (posthogConfigured) { + posthog.capture('user_signed_out'); + } + // Clear SWR cache mutate('/api/user', null, false); mutate('/api/team', null, false); diff --git a/apps/basic-integration/next-js/15-pages-router-saas/components/login.tsx b/apps/basic-integration/next-js/15-pages-router-saas/components/login.tsx index 325f0cad5..e0baf662a 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/components/login.tsx +++ b/apps/basic-integration/next-js/15-pages-router-saas/components/login.tsx @@ -6,7 +6,10 @@ import { useRouter } from 'next/router'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; +import type { User } from '@/lib/db/schema'; import { CircleIcon, Loader2 } from 'lucide-react'; +import { mutate } from 'swr'; +import posthog from 'posthog-js'; export function Login({ mode = 'signin', @@ -57,6 +60,28 @@ export function Login({ return; } + const user = await mutate('/api/user'); + + if ( + user && + process.env.NEXT_PUBLIC_POSTHOG_KEY && + process.env.NEXT_PUBLIC_POSTHOG_HOST + ) { + const userId = String(user.id); + const identifiedUserId = posthog.get_property('$user_id'); + + if (identifiedUserId && identifiedUserId !== userId) { + posthog.reset(); + } + + posthog.identify(userId, { + email: user.email, + role: user.role, + ...(user.name ? { name: user.name } : {}) + }); + posthog.capture(mode === 'signin' ? 'user_signed_in' : 'user_signed_up'); + } + if (result.success && result.redirectTo) { router.push(result.redirectTo); } else if (result.url) { diff --git a/apps/basic-integration/next-js/15-pages-router-saas/instrumentation-client.ts b/apps/basic-integration/next-js/15-pages-router-saas/instrumentation-client.ts new file mode 100644 index 000000000..b3bf620a8 --- /dev/null +++ b/apps/basic-integration/next-js/15-pages-router-saas/instrumentation-client.ts @@ -0,0 +1,25 @@ +import posthog from 'posthog-js'; + +const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY; +const posthogHost = process.env.NEXT_PUBLIC_POSTHOG_HOST; + +if (!posthogKey) { + if (process.env.NODE_ENV === 'development') { + throw new Error( + 'NEXT_PUBLIC_POSTHOG_KEY variable required by PostHog is missing or un-configured, this causes events to be silently missed. This error stops appearing once NEXT_PUBLIC_POSTHOG_KEY is configured' + ); + } +} else if (!posthogHost) { + if (process.env.NODE_ENV === 'development') { + throw new Error( + 'NEXT_PUBLIC_POSTHOG_HOST variable required by PostHog is missing or un-configured, this causes events to be silently missed. This error stops appearing once NEXT_PUBLIC_POSTHOG_HOST is configured' + ); + } +} else { + posthog.init(posthogKey, { + api_host: posthogHost, + defaults: '2025-05-24', + capture_exceptions: true, + debug: process.env.NODE_ENV === 'development', + }); +} diff --git a/apps/basic-integration/next-js/15-pages-router-saas/instrumentation.ts b/apps/basic-integration/next-js/15-pages-router-saas/instrumentation.ts new file mode 100644 index 000000000..ad975ead7 --- /dev/null +++ b/apps/basic-integration/next-js/15-pages-router-saas/instrumentation.ts @@ -0,0 +1,57 @@ +import { SeverityNumber } from '@opentelemetry/api-logs'; +import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; +import { resourceFromAttributes } from '@opentelemetry/resources'; +import { BatchLogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs'; + +const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY; +const posthogHost = process.env.NEXT_PUBLIC_POSTHOG_HOST; + +let loggerProvider: LoggerProvider | undefined; + +if (!posthogKey) { + if (process.env.NODE_ENV === 'development') { + throw new Error( + 'NEXT_PUBLIC_POSTHOG_KEY variable required by PostHog is missing or un-configured, this causes events to be silently missed. This error stops appearing once NEXT_PUBLIC_POSTHOG_KEY is configured' + ); + } +} else if (!posthogHost) { + if (process.env.NODE_ENV === 'development') { + throw new Error( + 'NEXT_PUBLIC_POSTHOG_HOST variable required by PostHog is missing or un-configured, this causes events to be silently missed. This error stops appearing once NEXT_PUBLIC_POSTHOG_HOST is configured' + ); + } +} else { + loggerProvider = new LoggerProvider({ + resource: resourceFromAttributes({ 'service.name': 'nextjs-saas' }), + processors: [ + new BatchLogRecordProcessor({ + exporter: new OTLPLogExporter({ + url: `${posthogHost.replace(/\/$/, '')}/i/v1/logs`, + headers: { + Authorization: `Bearer ${posthogKey}`, + 'Content-Type': 'application/json' + } + }) + }) + ] + }); +} + +export async function emitPostHogLog( + body: string, + attributes: Record +) { + if (!loggerProvider) { + return; + } + + loggerProvider.getLogger('posthog-integration').emit({ + body, + severityNumber: SeverityNumber.INFO, + attributes + }); + + try { + await loggerProvider.forceFlush(); + } catch {} +} diff --git a/apps/basic-integration/next-js/15-pages-router-saas/package.json b/apps/basic-integration/next-js/15-pages-router-saas/package.json index 485799f45..cf7f8938f 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/package.json +++ b/apps/basic-integration/next-js/15-pages-router-saas/package.json @@ -11,6 +11,10 @@ "db:studio": "drizzle-kit studio" }, "dependencies": { + "@opentelemetry/api-logs": "^0.223.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.300.0", + "@opentelemetry/resources": "^3.0.0", + "@opentelemetry/sdk-logs": "^3.0.0", "@tailwindcss/postcss": "4.1.7", "@types/node": "^22.15.18", "@types/react": "19.1.4", @@ -28,6 +32,7 @@ "next": "15.5.7", "postcss": "^8.5.3", "postgres": "^3.4.5", + "posthog-js": "^1.441.2", "radix-ui": "^1.4.2", "react": "19.1.2", "react-dom": "19.1.2", diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pages/_app.tsx b/apps/basic-integration/next-js/15-pages-router-saas/pages/_app.tsx index 230860636..f9c1c223b 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pages/_app.tsx +++ b/apps/basic-integration/next-js/15-pages-router-saas/pages/_app.tsx @@ -1,20 +1,73 @@ +import ErrorBoundary from '@/components/error-boundary'; import '@/styles/globals.css'; +import type { User } from '@/lib/db/schema'; import type { AppProps } from 'next/app'; import { Manrope } from 'next/font/google'; -import { SWRConfig } from 'swr'; +import posthog from 'posthog-js'; +import { useEffect, useRef } from 'react'; +import useSWR, { SWRConfig } from 'swr'; const manrope = Manrope({ subsets: ['latin'] }); +const fetcher = (url: string) => fetch(url).then((res) => res.json()); + +function PostHogUserIdentification() { + const { data: user } = useSWR('/api/user', fetcher); + const identifiedUserId = useRef(null); + + useEffect(() => { + if ( + !process.env.NEXT_PUBLIC_POSTHOG_KEY || + !process.env.NEXT_PUBLIC_POSTHOG_HOST + ) { + return; + } + + if (!user) { + if (identifiedUserId.current !== null) { + posthog.reset(); + identifiedUserId.current = null; + } + return; + } + + const userId = String(user.id); + + if ( + identifiedUserId.current === user.id || + posthog.get_distinct_id() === userId + ) { + identifiedUserId.current = user.id; + return; + } + + if (identifiedUserId.current !== null) { + posthog.reset(); + } + + posthog.identify(userId, { + email: user.email, + role: user.role, + ...(user.name ? { name: user.name } : {}) + }); + identifiedUserId.current = user.id; + }, [user]); + + return null; +} export default function App({ Component, pageProps }: AppProps) { return (
- - - + + + + + +
); } diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/create-checkout.ts b/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/create-checkout.ts index 789eb16fb..d93eea3bf 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/create-checkout.ts +++ b/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/create-checkout.ts @@ -1,6 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { createCheckoutSession } from '@/lib/payments/stripe'; import { getUser, getTeamForUser } from '@/lib/db/queries'; +import { emitPostHogLog } from '@/instrumentation'; export default async function handler( req: NextApiRequest, @@ -25,6 +26,9 @@ export default async function handler( } const result = await createCheckoutSession({ team, priceId, userId: user.id }); + await emitPostHogLog('checkout_session_created', { + endpoint: '/api/stripe/create-checkout' + }); return res.status(200).json(result); } catch (error) { console.error('Checkout error:', error); diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/customer-portal.ts b/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/customer-portal.ts index 91302967f..cfd87ed10 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/customer-portal.ts +++ b/apps/basic-integration/next-js/15-pages-router-saas/pages/api/stripe/customer-portal.ts @@ -1,6 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import { createCustomerPortalSession } from '@/lib/payments/stripe'; import { getUser, getTeamForUser } from '@/lib/db/queries'; +import { emitPostHogLog } from '@/instrumentation'; export default async function handler( req: NextApiRequest, @@ -25,6 +26,9 @@ export default async function handler( } const portalSession = await createCustomerPortalSession(team); + await emitPostHogLog('customer_portal_session_created', { + endpoint: '/api/stripe/customer-portal' + }); return res.status(200).json({ url: portalSession.url }); } catch (error) { console.error('Customer portal error:', error); diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pages/api/team/invite.ts b/apps/basic-integration/next-js/15-pages-router-saas/pages/api/team/invite.ts index 677c799de..df0cd7ae6 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pages/api/team/invite.ts +++ b/apps/basic-integration/next-js/15-pages-router-saas/pages/api/team/invite.ts @@ -11,6 +11,7 @@ import { ActivityType } from '@/lib/db/schema'; import { getUser, getUserWithTeam } from '@/lib/db/queries'; +import { emitPostHogLog } from '@/instrumentation'; async function logActivity( teamId: number | null | undefined, @@ -108,6 +109,10 @@ export default async function handler( ActivityType.INVITE_TEAM_MEMBER ); + await emitPostHogLog('team_invitation_created', { + endpoint: '/api/team/invite', + invited_role: role + }); return res.status(200).json({ success: 'Invitation sent successfully' }); } catch (error) { console.error('Invite team member error:', error); diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/general.tsx b/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/general.tsx index 74d0dc0e5..d14f5931d 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/general.tsx +++ b/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/general.tsx @@ -14,8 +14,13 @@ import { Loader2 } from 'lucide-react'; import useSWR from 'swr'; import { User } from '@/lib/db/schema'; import { useState, useTransition } from 'react'; +import posthog from 'posthog-js'; const fetcher = (url: string) => fetch(url).then((res) => res.json()); +const posthogConfigured = Boolean( + process.env.NEXT_PUBLIC_POSTHOG_KEY && + process.env.NEXT_PUBLIC_POSTHOG_HOST +); export default function GeneralPage() { const { data: user } = useSWR('/api/user', fetcher); @@ -52,6 +57,9 @@ export default function GeneralPage() { return; } + if (posthogConfigured) { + posthog.capture('account_updated'); + } setSuccess(result.success); setName(result.name); } catch (err) { diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/index.tsx b/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/index.tsx index cc528f768..068e0f3f2 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/index.tsx +++ b/apps/basic-integration/next-js/15-pages-router-saas/pages/dashboard/index.tsx @@ -18,8 +18,13 @@ import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { Loader2, PlusCircle } from 'lucide-react'; import useSWR, { mutate } from 'swr'; import { useState, useTransition } from 'react'; +import posthog from 'posthog-js'; const fetcher = (url: string) => fetch(url).then((res) => res.json()); +const posthogConfigured = Boolean( + process.env.NEXT_PUBLIC_POSTHOG_KEY && + process.env.NEXT_PUBLIC_POSTHOG_HOST +); function ManageSubscription() { const { data: teamData } = useSWR('/api/team', fetcher); @@ -36,6 +41,9 @@ function ManageSubscription() { const result = await response.json(); if (response.ok && result.url) { + if (posthogConfigured) { + posthog.capture('subscription_management_opened'); + } window.location.href = result.url; } } catch (err) { @@ -102,6 +110,10 @@ function TeamMembers() { return; } + if (posthogConfigured) { + posthog.capture('team_member_removed'); + } + // Refresh team data mutate('/api/team'); } catch (err) { @@ -207,6 +219,11 @@ function InviteTeamMember() { return; } + if (posthogConfigured) { + posthog.capture('team_invitation_sent', { + invited_role: data.role + }); + } setSuccess(result.success); // Reset form (e.target as HTMLFormElement).reset(); diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pages/pricing.tsx b/apps/basic-integration/next-js/15-pages-router-saas/pages/pricing.tsx index 0067ec8ed..42bae9b60 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pages/pricing.tsx +++ b/apps/basic-integration/next-js/15-pages-router-saas/pages/pricing.tsx @@ -7,6 +7,12 @@ import { useState, useTransition } from 'react'; import { useRouter } from 'next/router'; import { getUser, getTeamForUser } from '@/lib/db/queries'; import { User, TeamDataWithMembers } from '@/lib/db/schema'; +import posthog from 'posthog-js'; + +const posthogConfigured = Boolean( + process.env.NEXT_PUBLIC_POSTHOG_KEY && + process.env.NEXT_PUBLIC_POSTHOG_HOST +); interface Price { id: string; @@ -76,6 +82,14 @@ function PricingCard({ startTransition(async () => { try { + if (posthogConfigured) { + posthog.capture('checkout_started', { + plan_name: name, + billing_interval: interval, + trial_days: trialDays + }); + } + const response = await fetch('/api/stripe/create-checkout', { method: 'POST', headers: { diff --git a/apps/basic-integration/next-js/15-pages-router-saas/pnpm-lock.yaml b/apps/basic-integration/next-js/15-pages-router-saas/pnpm-lock.yaml index 693ff8558..6b673eb57 100644 --- a/apps/basic-integration/next-js/15-pages-router-saas/pnpm-lock.yaml +++ b/apps/basic-integration/next-js/15-pages-router-saas/pnpm-lock.yaml @@ -8,6 +8,18 @@ importers: .: dependencies: + '@opentelemetry/api-logs': + specifier: ^0.223.0 + version: 0.223.0 + '@opentelemetry/exporter-logs-otlp-http': + specifier: ^0.300.0 + version: 0.300.0(@opentelemetry/api@1.10.0) + '@opentelemetry/resources': + specifier: ^3.0.0 + version: 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/sdk-logs': + specifier: ^3.0.0 + version: 3.0.0(@opentelemetry/api@1.10.0) '@tailwindcss/postcss': specifier: 4.1.7 version: 4.1.7 @@ -40,7 +52,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: ^0.43.1 - version: 0.43.1(postgres@3.4.7) + version: 0.43.1(@opentelemetry/api@1.10.0)(postgres@3.4.7) jose: specifier: ^6.0.11 version: 6.1.3 @@ -52,13 +64,16 @@ importers: version: 10.0.1 next: specifier: 15.5.7 - version: 15.5.7(react-dom@19.1.2(react@19.1.2))(react@19.1.2) + version: 15.5.7(@opentelemetry/api@1.10.0)(react-dom@19.1.2(react@19.1.2))(react@19.1.2) postcss: specifier: ^8.5.3 version: 8.5.6 postgres: specifier: ^3.4.5 version: 3.4.7 + posthog-js: + specifier: ^1.441.2 + version: 1.441.2(@types/react@19.1.4)(react@19.1.2) radix-ui: specifier: ^1.4.2 version: 1.4.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.2(react@19.1.2))(react@19.1.2) @@ -450,89 +465,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -594,24 +625,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@15.5.7': resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@15.5.7': resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@15.5.7': resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@15.5.7': resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} @@ -625,6 +660,75 @@ packages: cpu: [x64] os: [win32] + '@opentelemetry/api-logs@0.223.0': + resolution: {integrity: sha512-Oepm6etVPFCn0VWB1t833iOTgz1eYBDUPxcrOR/XvwzD1+Ag9VzSPSrrKAFNJ/haatj+8CXbG47pZXvdNQKDJw==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api@1.10.0': + resolution: {integrity: sha512-lMkyes8iHrG+mk6WH7X70MdCLI2RS0FwNBY1PyQ8UemaijE2m5mv5A0Niy3HtbYTFrgkUEQjFMXmSAk2hQDuPQ==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/core@3.0.0': + resolution: {integrity: sha512-whOLlww0R/RLtCWGBXhK1fdvL9t2/TL0fqdjZvcaoUUuNilRPjXecqQdzyVwV68s6XEDA5oYbm7/bZT62GXF4A==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': '>=1.10.0 <1.11.0' + + '@opentelemetry/exporter-logs-otlp-http@0.300.0': + resolution: {integrity: sha512-S8yP9Fg33CU9+0fr1pnh/afPfgEpSyxQO4JRUZvmDMhAzgR/RLzvYg93MjWjbC1c2VrXffXROMO68RZ1P/ebgQ==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-exporter-base@0.300.0': + resolution: {integrity: sha512-D+PhzYURtv6p7Kk1rUrilLtV+ZvS218tI0jiKTV5z1agOeELw78C+cFd3o9UUshUx1j+EIpFM62yGk8BuydQvg==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.300.0': + resolution: {integrity: sha512-T55lRmjRwvXWyTFdy/BbJ3T5RRsq3bAwQgxxA7qHFxgRd4+pZzRk02ZwOFsYK5072OXGYjYFNJcp68eQV4i0Ig==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': '>=1.10.0 <1.11.0' + + '@opentelemetry/resources@3.0.0': + resolution: {integrity: sha512-4762KVmlDroRIt+4Ra8AnwcQqdXlkAR55jDrhzna8bzhJx1mUzvHW/Lh/OemFuY9+ouM4xaDc6CbUmoJmM6BFg==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': '>=1.10.0 <1.11.0' + + '@opentelemetry/sdk-logs@3.0.0': + resolution: {integrity: sha512-IysNZWrBk2PqYw4qU9PZcC7pjrZLa+KLk7vcLmPPNBUr97MgeamWhX0DUHsmxwJv3dnjYM6mLRmP8mw69ld+dA==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': '>=1.10.0 <1.11.0' + + '@opentelemetry/sdk-metrics@3.0.0': + resolution: {integrity: sha512-YozyS2rIlizvUNLZwcWxH0x2FhX02/mcZwzM8hsl8yvQk+xeKmAc7vcSieWiO4oSwIB20B8eS/zwdopAd/J5zQ==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': '>=1.10.0 <1.11.0' + + '@opentelemetry/sdk-trace@3.0.0': + resolution: {integrity: sha512-4T0DbDGdtsjNmYK5/lNalHro4fsMZ0UZ3JE+C8fcqYP25xaJC22FHg8kdJNJ21srjJY5XoT7WNFCtj88NNTl4Q==} + engines: {node: '>=22.15.0'} + peerDependencies: + '@opentelemetry/api': '>=1.10.0 <1.11.0' + + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} + engines: {node: '>=14'} + + '@posthog/browser-common@0.10.1': + resolution: {integrity: sha512-gKtBGEsjxNExO/19trnkiXTHFX0075vXn69zZ+lPlXy6P/DkED4644WqjDN/GIWr1Y5en2dcVJPOqUmVO+drkg==} + + '@posthog/core@1.61.1': + resolution: {integrity: sha512-qyMTxPfjeJkHIhpcukOgBN3BWXbCyFRPz8/Voy5qZtVh9NZqj3EhC6LLeYZuJhL3WpqhQTgn2FMIwAo/ag6fmw==} + + '@posthog/types@1.418.0': + resolution: {integrity: sha512-WqDXUWH1R8OilBp2PfDpQIRZSCs3QyOnw7H3YK7lvZLCMIsOqSZAKJrrqYWt4f7FvnVCACRuNGCC0HKh3J/HWw==} + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -1356,24 +1460,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.7': resolution: {integrity: sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.7': resolution: {integrity: sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.7': resolution: {integrity: sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.7': resolution: {integrity: sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A==} @@ -1417,6 +1525,9 @@ packages: '@types/react@19.1.4': resolution: {integrity: sha512-EB1yiiYdvySuIITtD5lhW4yPyJ31RkJkkDw794LaQYrxCSaQV/47y5o1FMC4zF9ZyjUjzJMZwbovEnT5yHTW6g==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + arg@4.1.0: resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==} @@ -1480,6 +1591,9 @@ packages: resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} engines: {node: '>= 0.6'} + core-js@3.51.0: + resolution: {integrity: sha512-7bDKx/5jm5MxzsXxc93g6Z2+4ZsuT/MddrfRmTDJNAkWsYWHU8EVNEsBiIEWnMAMCHMmRfUEjkuo3jeNBOIHRw==} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -1507,6 +1621,9 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dompurify@3.4.17: + resolution: {integrity: sha512-B/pSlYVHQ58kqISD/yDjuJ1yfzI34m1gF4lAod2bwSRhiN4K5Cl3H8Af7hqB2PmTL911tdEudnnXn5FnhRoz0w==} + dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} @@ -1646,6 +1763,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + fflate@0.4.9: + resolution: {integrity: sha512-zdxgIEddhfsyCaWpJ2SdXEP8ZMrKJ6+5jl4OupODcywU0IhRk6gdXuVGcPICyfx2H97hVK7xmJtRLPjkxAX8Vw==} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -1729,24 +1849,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.1: resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.1: resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.1: resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.1: resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} @@ -1847,10 +1971,32 @@ packages: resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} engines: {node: '>=12'} + posthog-js@1.441.2: + resolution: {integrity: sha512-PsELSUSVCx80BfbtMtir8fW6scxVj+2CvsG+Vj2j9eTQYQL1AzsaZr73pqJk1XWEcSt+B1hEfirz3iFVQGVQkQ==} + peerDependencies: + '@types/react': '>=16.8.0' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + + preact@10.29.8: + resolution: {integrity: sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==} + peerDependencies: + preact-render-to-string: '>=5' + peerDependenciesMeta: + preact-render-to-string: + optional: true + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + radix-ui@1.4.3: resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} peerDependencies: @@ -2056,6 +2202,12 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + web-vitals@6.2.1: + resolution: {integrity: sha512-rLcLXA2sx6+9dE88NHFubwTtGxpK4yYBLj6qHPdFoCaLr0cXGb4efOqtKLlm4loGA4OEKHIQKMKzZkKyOh5ctw==} + + web-vitals@6.2.3: + resolution: {integrity: sha512-Dmy+vdO1UPMqXiAtZSNayhl4f794Bxfd94W4HIj2HlYtczEQfEOon969memlcpcHrTuOKLa5baFjX7WbgmOq+A==} + yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} @@ -2391,6 +2543,81 @@ snapshots: '@next/swc-win32-x64-msvc@15.5.7': optional: true + '@opentelemetry/api-logs@0.223.0': + dependencies: + '@opentelemetry/api': 1.10.0 + + '@opentelemetry/api@1.10.0': {} + + '@opentelemetry/core@3.0.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/exporter-logs-otlp-http@0.300.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/otlp-exporter-base': 0.300.0(@opentelemetry/api@1.10.0) + '@opentelemetry/otlp-transformer': 0.300.0(@opentelemetry/api@1.10.0) + '@opentelemetry/sdk-logs': 3.0.0(@opentelemetry/api@1.10.0) + + '@opentelemetry/otlp-exporter-base@0.300.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/core': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/otlp-transformer': 0.300.0(@opentelemetry/api@1.10.0) + + '@opentelemetry/otlp-transformer@0.300.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/core': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/resources': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/sdk-logs': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/sdk-metrics': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/sdk-trace': 3.0.0(@opentelemetry/api@1.10.0) + + '@opentelemetry/resources@3.0.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/core': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-logs@3.0.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/core': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/resources': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-metrics@3.0.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/core': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/resources': 3.0.0(@opentelemetry/api@1.10.0) + + '@opentelemetry/sdk-trace@3.0.0(@opentelemetry/api@1.10.0)': + dependencies: + '@opentelemetry/api': 1.10.0 + '@opentelemetry/core': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/resources': 3.0.0(@opentelemetry/api@1.10.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/semantic-conventions@1.43.0': {} + + '@posthog/browser-common@0.10.1': + dependencies: + '@posthog/core': 1.61.1 + '@posthog/types': 1.418.0 + preact: 10.29.8 + transitivePeerDependencies: + - preact-render-to-string + + '@posthog/core@1.61.1': + dependencies: + '@posthog/types': 1.418.0 + + '@posthog/types@1.418.0': {} + '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.3': {} @@ -3226,6 +3453,9 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/trusted-types@2.0.7': + optional: true + arg@4.1.0: {} aria-hidden@1.2.6: @@ -3282,6 +3512,8 @@ snapshots: content-type@1.0.4: {} + core-js@3.51.0: {} + csstype@3.2.3: {} debug@4.4.3: @@ -3296,6 +3528,10 @@ snapshots: detect-node-es@1.1.0: {} + dompurify@3.4.17: + optionalDependencies: + '@types/trusted-types': 2.0.7 + dotenv@16.6.1: {} drizzle-kit@0.31.7: @@ -3307,8 +3543,9 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.43.1(postgres@3.4.7): + drizzle-orm@0.43.1(@opentelemetry/api@1.10.0)(postgres@3.4.7): optionalDependencies: + '@opentelemetry/api': 1.10.0 postgres: 3.4.7 dunder-proto@1.0.1: @@ -3395,6 +3632,8 @@ snapshots: escalade@3.2.0: {} + fflate@0.4.9: {} + fraction.js@5.3.4: {} function-bind@1.1.2: {} @@ -3522,7 +3761,7 @@ snapshots: nanoid@3.3.11: {} - next@15.5.7(react-dom@19.1.2(react@19.1.2))(react@19.1.2): + next@15.5.7(@opentelemetry/api@1.10.0)(react-dom@19.1.2(react@19.1.2))(react@19.1.2): dependencies: '@next/env': 15.5.7 '@swc/helpers': 0.5.15 @@ -3540,6 +3779,7 @@ snapshots: '@next/swc-linux-x64-musl': 15.5.7 '@next/swc-win32-arm64-msvc': 15.5.7 '@next/swc-win32-x64-msvc': 15.5.7 + '@opentelemetry/api': 1.10.0 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' @@ -3569,10 +3809,32 @@ snapshots: postgres@3.4.7: {} + posthog-js@1.441.2(@types/react@19.1.4)(react@19.1.2): + dependencies: + '@posthog/browser-common': 0.10.1 + '@posthog/core': 1.61.1 + '@posthog/types': 1.418.0 + core-js: 3.51.0 + dompurify: 3.4.17 + fflate: 0.4.9 + preact: 10.29.8 + query-selector-shadow-dom: 1.0.1 + web-vitals: 6.2.3 + web-vitals-soft-navs: web-vitals@6.2.1 + optionalDependencies: + '@types/react': 19.1.4 + react: 19.1.2 + transitivePeerDependencies: + - preact-render-to-string + + preact@10.29.8: {} + qs@6.14.0: dependencies: side-channel: 1.1.0 + query-selector-shadow-dom@1.0.1: {} + radix-ui@1.4.3(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.2(react@19.1.2))(react@19.1.2): dependencies: '@radix-ui/primitive': 1.1.3 @@ -3829,6 +4091,10 @@ snapshots: dependencies: react: 19.1.2 + web-vitals@6.2.1: {} + + web-vitals@6.2.3: {} + yallist@5.0.0: {} zod@3.25.76: {}