From ab5ef7ec4ab434a418264126f8e8d37e43569e73 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Thu, 21 May 2026 21:32:20 -0400 Subject: [PATCH] feat: add client-side PostHog analytics and refactor `/api/events` to use `posthog-node` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `src/components/posthog-provider.tsx` — initializes the `posthog-js` browser SDK once (guarded by `VITE_PUBLIC_POSTHOG_KEY` and `posthog.__loaded`) with history-based pageview capture, pageleave tracking, and session replay + autocapture disabled; wraps the app shell in `__root.tsx` via `` - Add `src/lib/analytics.ts` with a `useAnalytics` hook that returns a stable `capture` callback bound to the PostHog singleton (no-ops when the key is absent or the SDK is uninitialized) and a `selectionProperties` helper that flattens slot/addon selections into a consistent event property shape across events - Wire `capture` into `Builder` (`builder_module_selected`, `builder_module_deselected`, `builder_addon_toggled`) and `CommandPreview` (`builder_command_copied` with `package_manager`, `command`, `name_customized`, `module_count`, and per-slot properties); add an `onCopied` callback prop to `CopyButton` to fire the capture after a successful clipboard write - Add `src/server/posthog.server.ts` — a lazy singleton that constructs a `posthog-node` `PostHog` client from `VITE_PUBLIC_POSTHOG_KEY`/`VITE_PUBLIC_POSTHOG_HOST` and returns `null` when unconfigured; refactor `/api/events` to use this client instead of a raw `fetch` to PostHog's `/batch/` endpoint, and flush via `waitUntil` from `@vercel/functions` so the serverless function stays alive past the response without blocking it --- apps/web/package.json | 3 + apps/web/src/components/builder/index.tsx | 12 +- apps/web/src/components/command-preview.tsx | 21 +- apps/web/src/components/copy-button.tsx | 5 +- apps/web/src/components/posthog-provider.tsx | 30 ++ apps/web/src/lib/analytics.ts | 39 +++ apps/web/src/routes/__root.tsx | 27 +- apps/web/src/routes/api.events.ts | 47 +-- apps/web/src/server/posthog.server.ts | 28 ++ pnpm-lock.yaml | 349 ++++++++++++++++++- 10 files changed, 511 insertions(+), 50 deletions(-) create mode 100644 apps/web/src/components/posthog-provider.tsx create mode 100644 apps/web/src/lib/analytics.ts create mode 100644 apps/web/src/server/posthog.server.ts diff --git a/apps/web/package.json b/apps/web/package.json index 7225514..cff0996 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -29,6 +29,7 @@ "@tanstack/react-start": "^1.168.10", "@tanstack/router-plugin": "^1.168.10", "@vercel/analytics": "^2.0.1", + "@vercel/functions": "^3.6.0", "@vercel/og": "^0.11.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -36,6 +37,8 @@ "fumadocs-mdx": "^15.0.7", "fumadocs-ui": "npm:@fumadocs/base-ui@^16.9.0", "nitro": "^3.0.260429-beta", + "posthog-js": "^1.375.0", + "posthog-node": "^5.35.0", "react": "^19.2.6", "react-dom": "^19.2.6", "react-resizable-panels": "^4.11.1", diff --git a/apps/web/src/components/builder/index.tsx b/apps/web/src/components/builder/index.tsx index 8969354..f623605 100644 --- a/apps/web/src/components/builder/index.tsx +++ b/apps/web/src/components/builder/index.tsx @@ -5,6 +5,7 @@ import { useCallback } from "react"; import { FilePreview } from "@/components/builder/file-preview"; import { ProjectSetup } from "@/components/builder/project-setup"; import { SlotCards } from "@/components/builder/slot-cards"; +import { useAnalytics } from "@/lib/analytics"; import { type AddonSelections, type BuilderSearch, @@ -19,6 +20,7 @@ import type { BuilderState } from "@/server/builder-state.functions"; export function Builder({ state, search }: { state: BuilderState; search: BuilderSearch }) { const navigate = useNavigate({ from: "/" }); + const capture = useAnalytics(); const { name, selections, addons } = parseSelections(search); const resolved = resolveSelectedAdapters(state.modules, selections); const resolvedAddons = resolveSelectedAddons(state.modules, selections, addons); @@ -42,29 +44,33 @@ export function Builder({ state, search }: { state: BuilderState; search: Builde const next: Selections = { ...selections }; if (id) next[slot] = id; else delete next[slot]; + if (id) capture("builder_module_selected", { slot, module: id }); + else capture("builder_module_deselected", { slot }); void navigate({ search: toSearchParams({ name, selections: next, addons }), replace: true, resetScroll: false, }); }, - [navigate, name, selections, addons], + [capture, navigate, name, selections, addons], ); const toggleAddon = useCallback( (category: AddonCategoryId, id: string) => { const current = addons[category] ?? []; - const nextIds = current.includes(id) ? current.filter((x) => x !== id) : [...current, id]; + const enabled = !current.includes(id); + const nextIds = enabled ? [...current, id] : current.filter((x) => x !== id); const next: AddonSelections = { ...addons }; if (nextIds.length > 0) next[category] = nextIds; else delete next[category]; + capture("builder_addon_toggled", { category, addon: id, enabled }); void navigate({ search: toSearchParams({ name, selections, addons: next }), replace: true, resetScroll: false, }); }, - [navigate, name, selections, addons], + [capture, navigate, name, selections, addons], ); const commandBar = ( diff --git a/apps/web/src/components/command-preview.tsx b/apps/web/src/components/command-preview.tsx index 5a0a83c..b4ffdcc 100644 --- a/apps/web/src/components/command-preview.tsx +++ b/apps/web/src/components/command-preview.tsx @@ -1,7 +1,10 @@ +import { useCallback } from "react"; + import { CopyButton } from "@/components/copy-button"; import { PackageManagerSelect } from "@/components/package-manager-select"; +import { selectionProperties, useAnalytics } from "@/lib/analytics"; import { usePackageManager } from "@/lib/package-manager"; -import { type AddonSelections, buildCommand, type Selections } from "@/lib/selection"; +import { type AddonSelections, buildCommand, DEFAULT_NAME, type Selections } from "@/lib/selection"; /** * The ` create stanza …` command box: a package-manager picker, the command @@ -19,6 +22,20 @@ export function CommandPreview({ }) { const { pm, setPm } = usePackageManager(); const command = buildCommand({ name, selections, addons, pm }); + const capture = useAnalytics(); + + const onCopied = useCallback(() => { + const addonSelections = addons ?? {}; + capture("builder_command_copied", { + package_manager: pm, + command, + name_customized: name !== DEFAULT_NAME, + module_count: + Object.keys(selections).length + + Object.values(addonSelections).reduce((n, ids) => n + (ids?.length ?? 0), 0), + ...selectionProperties(selections, addonSelections), + }); + }, [capture, pm, command, name, selections, addons]); return (
@@ -26,7 +43,7 @@ export function CommandPreview({
         {command}
       
- +
); } diff --git a/apps/web/src/components/copy-button.tsx b/apps/web/src/components/copy-button.tsx index 29c5bef..23fa387 100644 --- a/apps/web/src/components/copy-button.tsx +++ b/apps/web/src/components/copy-button.tsx @@ -10,19 +10,22 @@ export function CopyButton({ value, label = "Copy command", className, + onCopied, }: { value: string; label?: string; className?: string; + onCopied?: () => void; }) { const onCopy = useCallback(async () => { try { await navigator.clipboard.writeText(value); toast.success("Copied to clipboard"); + onCopied?.(); } catch { toast.error("Couldn't access the clipboard"); } - }, [value]); + }, [value, onCopied]); const trigger = useMemo( () => ( diff --git a/apps/web/src/components/posthog-provider.tsx b/apps/web/src/components/posthog-provider.tsx new file mode 100644 index 0000000..48795f4 --- /dev/null +++ b/apps/web/src/components/posthog-provider.tsx @@ -0,0 +1,30 @@ +import posthog from "posthog-js"; +import { PostHogProvider as PostHogReactProvider } from "posthog-js/react"; + +/** + * Client-side PostHog. Initializes the browser SDK once, but only when a key is + * configured (`VITE_PUBLIC_POSTHOG_KEY`) — local dev and self-hosters without + * analytics get an uninitialized singleton that no-ops on capture, mirroring the + * `/api/events` proxy's "no key → do nothing" behavior. + * + * Auto-captures pageviews + pageleaves (history-based, for the SPA router) and + * web vitals; DOM click autocapture and session replay are off. + */ + +const key = import.meta.env.VITE_PUBLIC_POSTHOG_KEY; + +// oxlint-disable-next-line no-underscore-dangle +if (typeof window !== "undefined" && key && !posthog.__loaded) { + posthog.init(key, { + api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST ?? "https://us.i.posthog.com", + defaults: "2026-01-30", + autocapture: false, + capture_pageview: "history_change", + capture_pageleave: true, + disable_session_recording: true, + }); +} + +export function PostHogProvider({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/apps/web/src/lib/analytics.ts b/apps/web/src/lib/analytics.ts new file mode 100644 index 0000000..3917ba1 --- /dev/null +++ b/apps/web/src/lib/analytics.ts @@ -0,0 +1,39 @@ +import { KNOWN_SLOTS } from "@stanza/registry"; +import { usePostHog } from "posthog-js/react"; +import { useCallback } from "react"; + +import type { AddonSelections, Selections } from "@/lib/selection"; + +/** + * Stable `capture(event, properties)` bound to the client-side PostHog instance. + * Safe to call unconditionally: when no key is configured the singleton is + * uninitialized and `capture` is a no-op. + */ +export function useAnalytics(): (event: string, properties?: Record) => void { + const posthog = usePostHog(); + return useCallback( + (event, properties) => { + // oxlint-disable-next-line no-underscore-dangle + if (!posthog.__loaded) return; + posthog.capture(event, properties); + }, + [posthog], + ); +} + +/** + * Flatten the current builder selection into event properties: one key per slot + * (`framework`, `db`, …) plus an `addons` array. Shared across the builder + * events so they all carry the same selection shape. + */ +export function selectionProperties( + selections: Selections, + addons: AddonSelections, +): Record { + const props: Record = {}; + for (const slot of KNOWN_SLOTS) props[slot] = selections[slot] ?? null; + props.addons = Object.entries(addons).flatMap(([category, ids]) => + (ids ?? []).map((id) => `${category}:${id}`), + ); + return props; +} diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index 8fa8426..1e6b860 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -5,6 +5,7 @@ import { Analytics } from "@vercel/analytics/react"; import { Footer } from "@/components/footer"; import { Header } from "@/components/header"; +import { PostHogProvider } from "@/components/posthog-provider"; import { ThemeProvider } from "@/components/theme-provider"; import { Button } from "@/components/ui/button"; import { Toaster } from "@/components/ui/sonner"; @@ -84,18 +85,20 @@ function RootComponent() { - - -
-
-
- -
-
-
- -
-
+ + + +
+
+
+ +
+
+
+ +
+
+
diff --git a/apps/web/src/routes/api.events.ts b/apps/web/src/routes/api.events.ts index d490008..c21154a 100644 --- a/apps/web/src/routes/api.events.ts +++ b/apps/web/src/routes/api.events.ts @@ -1,15 +1,20 @@ import { createFileRoute } from "@tanstack/react-router"; +import { waitUntil } from "@vercel/functions"; + +import { getPostHogServerClient } from "@/server/posthog.server"; /** * `POST /api/events` — analytics ingest for the `@stanza/cli`. The CLI sends * plain `fetch` batches here so it never has to bundle `posthog-node`; this - * route holds the PostHog project key server-side and forwards to PostHog's - * HTTP capture API. + * route holds the PostHog project key server-side and forwards each event via + * the `posthog-node` client. * * Configure via env (set these in the Vercel project for prod): - * POSTHOG_API_KEY — the PostHog project key. When unset the route no-ops - * (returns 204) so local dev / self-hosters never error. - * POSTHOG_HOST — PostHog ingest host. Defaults to https://us.i.posthog.com. + * VITE_PUBLIC_POSTHOG_KEY — the PostHog project key. When unset the route + * no-ops (returns 204) so local dev / self-hosters + * never error. + * VITE_PUBLIC_POSTHOG_HOST — PostHog ingest host. Defaults to + * https://us.i.posthog.com. */ const MAX_EVENTS = 20; @@ -51,30 +56,26 @@ export const Route = createFileRoute("/api/events")({ const payload = parsePayload(body); if (!payload) return new Response("Invalid payload", { status: 400 }); - const apiKey = process.env.VITE_PUBLIC_POSTHOG_KEY; + const posthog = getPostHogServerClient(); // No key configured (local dev / self-host without analytics): accept // and discard so the CLI never sees an error. - if (!apiKey) return new Response(null, { status: 204 }); + if (!posthog) return new Response(null, { status: 204 }); - const host = process.env.VITE_PUBLIC_POSTHOG_HOST ?? "https://us.i.posthog.com"; - const batch = payload.events.map((e) => ({ - event: e.event, - distinct_id: payload.distinctId, - properties: e.properties ?? {}, - timestamp: e.timestamp, - })); - - try { - await fetch(`${host.replace(/\/$/, "")}/batch/`, { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ api_key: apiKey, batch }), - signal: AbortSignal.timeout(5000), + for (const e of payload.events) { + posthog.capture({ + distinctId: payload.distinctId, + event: e.event, + properties: e.properties ?? {}, + timestamp: e.timestamp ? new Date(e.timestamp) : undefined, }); - } catch { - // Telemetry must never surface as a user-facing error — swallow. } + // Serverless functions can freeze before in-flight requests settle, so + // hand the flush to `waitUntil` to keep it alive past the response + // without blocking it. Telemetry must never surface as a user-facing + // error, so swallow failures. + waitUntil(posthog.flush().catch(() => {})); + return new Response(null, { status: 202 }); }, }, diff --git a/apps/web/src/server/posthog.server.ts b/apps/web/src/server/posthog.server.ts new file mode 100644 index 0000000..7172a6c --- /dev/null +++ b/apps/web/src/server/posthog.server.ts @@ -0,0 +1,28 @@ +import { PostHog } from "posthog-node"; + +/** + * Server-only PostHog client. Holds the project key (read from env) and talks + * to PostHog's HTTP API so the `/api/events` proxy never has to hand-roll the + * capture protocol. Returns `null` when no key is configured (local dev / + * self-host without analytics) so callers can no-op. + * + * `flushAt: 1` + `flushInterval: 0` make capture send eagerly; serverless + * handlers should still `await client.flush()` before returning since the + * function may freeze before an in-flight request settles. + */ + +let client: PostHog | null = null; + +export function getPostHogServerClient(): PostHog | null { + const apiKey = process.env.VITE_PUBLIC_POSTHOG_KEY; + if (!apiKey) return null; + + if (!client) { + client = new PostHog(apiKey, { + host: process.env.VITE_PUBLIC_POSTHOG_HOST ?? "https://us.i.posthog.com", + flushAt: 1, + flushInterval: 0, + }); + } + return client; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 662005d..7c6840a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,7 +74,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.7 - version: 4.1.7(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) + version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) apps/web: dependencies: @@ -123,6 +123,9 @@ importers: '@vercel/analytics': specifier: ^2.0.1 version: 2.0.1(react@19.2.6) + '@vercel/functions': + specifier: ^3.6.0 + version: 3.6.0 '@vercel/og': specifier: ^0.11.1 version: 0.11.1 @@ -143,7 +146,13 @@ importers: version: '@fumadocs/base-ui@16.9.0(@tailwindcss/oxide@4.3.0)(@types/mdx@2.0.13)(@types/react@19.2.15)(fumadocs-core@16.9.0(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.15)(lucide-react@1.16.0(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(zod@4.4.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tailwindcss@4.3.0)' nitro: specifier: ^3.0.260429-beta - version: 3.0.260429-beta(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.0)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) + version: 3.0.260429-beta(@vercel/functions@3.6.0)(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.0)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) + posthog-js: + specifier: ^1.375.0 + version: 1.375.0 + posthog-node: + specifier: ^5.35.0 + version: 5.35.0 react: specifier: ^19.2.6 version: 19.2.6 @@ -210,7 +219,7 @@ importers: version: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3) vitest: specifier: ^4.1.7 - version: 4.1.7(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) + version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) web-vitals: specifier: ^5.2.0 version: 5.2.0 @@ -232,7 +241,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.7 - version: 4.1.7(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) + version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) packages/create-stanza: dependencies: @@ -261,7 +270,7 @@ importers: version: 6.0.3 vitest: specifier: ^4.1.7 - version: 4.1.7(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) + version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) registry/modules/auth-better-auth: dependencies: @@ -1200,6 +1209,78 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@opentelemetry/api-logs@0.208.0': + resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/core@2.2.0': + resolution: {integrity: sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.7.1': + resolution: {integrity: sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-logs-otlp-http@0.208.0': + resolution: {integrity: sha512-jOv40Bs9jy9bZVLo/i8FwUiuCvbjWDI+ZW13wimJm4LjnlwJxGgB+N/VWOZUTpM+ah/awXeQqKdNlpLf2EjvYg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-exporter-base@0.208.0': + resolution: {integrity: sha512-gMd39gIfVb2OgxldxUtOwGJYSH8P1kVFFlJLuut32L6KgUC4gl1dMhn+YC2mGn0bDOiQYSk/uHOdSjuKp58vvA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.208.0': + resolution: {integrity: sha512-DCFPY8C6lAQHUNkzcNT9R+qYExvsk6C5Bto2pbNxgicpcSWbe2WHShLxkOxIdNcBiYPdVHv/e7vH7K6TI+C+fQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/resources@2.2.0': + resolution: {integrity: sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/resources@2.7.1': + resolution: {integrity: sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.208.0': + resolution: {integrity: sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@2.2.0': + resolution: {integrity: sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.2.0': + resolution: {integrity: sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.41.1': + resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} + engines: {node: '>=14'} + '@orama/orama@3.1.18': resolution: {integrity: sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==} engines: {node: '>= 20.0.0'} @@ -1587,6 +1668,42 @@ packages: react: ^18.3.1 || ^19.0.0 react-dom: ^18.3.1 || ^19.0.0 + '@posthog/core@1.29.8': + resolution: {integrity: sha512-wdX4/WzZ+sV92z4ppC9SjOWdztY/0bN74SbJFy1X8/1N8+aNTSHsGEKHtbHitkIkJc861oYWr4ZzOoV0iVDP4w==} + + '@posthog/types@1.375.0': + resolution: {integrity: sha512-ykjHtJv1eUnEUQIuCavMi/+lnBhZPRVnFDrbG6m4fS+vZ3ajn8dGooPpbWjF33Uo4g7W4ew51dBtJGf2evvurA==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.2': + resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} @@ -2226,6 +2343,9 @@ packages: '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -2267,10 +2387,23 @@ packages: vue-router: optional: true + '@vercel/functions@3.6.0': + resolution: {integrity: sha512-Xj68JYqqJwtqFWJN7EWmFN7MOiUjv5whjw48UEKqQbg8r7hRkhuJhncTU0ba3jJCh/wxEuLWckrtsKcrHQraxw==} + engines: {node: '>= 20'} + peerDependencies: + '@aws-sdk/credential-provider-web-identity': '*' + peerDependenciesMeta: + '@aws-sdk/credential-provider-web-identity': + optional: true + '@vercel/og@0.11.1': resolution: {integrity: sha512-02rXXRABFq1B03w3aNhcVfxkY+8Ba5QFi4ax0zS0oOiD/LL9WUd/LA7BjVPakrQmVhIBjuo2oBM5U25R9IuXMg==} engines: {node: '>=16'} + '@vercel/oidc@3.4.1': + resolution: {integrity: sha512-H6B+/ig/GoahccL3WZjiHayHw1H5KhvTJNceqYulwfK9kkz5iul2hTmYzcJ7tTCQzyd0dutuL9xYFZCyLUqsog==} + engines: {node: '>= 20'} + '@vitejs/plugin-react@6.0.2': resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2598,6 +2731,9 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + core-js@3.49.0: + resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} + cors@2.8.6: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} @@ -2781,6 +2917,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.4.5: + resolution: {integrity: sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -3026,6 +3165,9 @@ packages: fetchdts@0.1.7: resolution: {integrity: sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==} + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + fflate@0.7.4: resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} @@ -3650,6 +3792,9 @@ packages: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -4205,6 +4350,18 @@ packages: resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.375.0: + resolution: {integrity: sha512-aHr9LPwEmL1/QDv+HpXBXuCtAdFaamDBqUqzTTVEIoHrN+ZZUQVr0kfv3v5w79TvUS7QezvHyUeigDQdCZRbSQ==} + + posthog-node@5.35.0: + resolution: {integrity: sha512-5Hos1mlwrZtzZbh1Pij1FyU9p4R3bajVtAKjPZ3vxhAScsGeyLsF5KqMaEAw3EYWmsX9SQ5CbYZtSlHf+nkw6g==} + engines: {node: ^20.20.0 || >=22.22.0} + peerDependencies: + rxjs: ^7.0.0 + peerDependenciesMeta: + rxjs: + optional: true + powershell-utils@0.1.0: resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} engines: {node: '>=20'} @@ -4214,6 +4371,9 @@ packages: peerDependencies: preact: '>=10 || >= 11.0.0-0' + preact@10.29.2: + resolution: {integrity: sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==} + preact@11.0.0-beta.0: resolution: {integrity: sha512-IcODoASASYwJ9kxz7+MJeiJhvLriwSb4y4mHIyxdgaRZp6kPUud7xytrk/6GZw8U3y6EFJaRb5wi9SrEK+8+lg==} @@ -4242,6 +4402,10 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + protobufjs@7.6.0: + resolution: {integrity: sha512-LtESOsMPTZgyYtwxhvdgdjGL0HmXEaRA/hVD6sol4zA60hVXXXP/SGmxnqDbgGE8gy7pYex7cym+5vYPcmaXBQ==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4260,6 +4424,9 @@ packages: quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -6140,6 +6307,82 @@ snapshots: '@open-draft/until@2.1.0': {} + '@opentelemetry/api-logs@0.208.0': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/api@1.9.1': {} + + '@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/exporter-logs-otlp-http@0.208.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-exporter-base': 0.208.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.208.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.208.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/otlp-exporter-base@0.208.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/otlp-transformer': 0.208.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/otlp-transformer@0.208.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.208.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-metrics': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.1) + protobufjs: 7.6.0 + + '@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/sdk-logs@0.208.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/sdk-metrics@2.2.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.1) + + '@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/semantic-conventions@1.41.1': {} + '@orama/orama@3.1.18': {} '@oxc-parser/binding-android-arm-eabi@0.120.0': @@ -6332,6 +6575,34 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) + '@posthog/core@1.29.8': + dependencies: + '@posthog/types': 1.375.0 + + '@posthog/types@1.375.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.1': {} + '@quansync/fs@1.0.0': dependencies: quansync: 1.0.0 @@ -6990,6 +7261,9 @@ snapshots: '@types/statuses@2.0.6': {} + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -7002,6 +7276,10 @@ snapshots: optionalDependencies: react: 19.2.6 + '@vercel/functions@3.6.0': + dependencies: + '@vercel/oidc': 3.4.1 + '@vercel/og@0.11.1': dependencies: '@resvg/resvg-wasm': 2.4.0 @@ -7009,6 +7287,8 @@ snapshots: optionalDependencies: sharp: 0.34.5 + '@vercel/oidc@3.4.1': {} + '@vitejs/plugin-react@6.0.2(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3))': dependencies: '@rolldown/pluginutils': 1.0.1 @@ -7304,6 +7584,8 @@ snapshots: cookie@1.1.1: {} + core-js@3.49.0: {} + cors@2.8.6: dependencies: object-assign: 4.1.1 @@ -7435,6 +7717,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.4.5: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -7726,6 +8012,8 @@ snapshots: fetchdts@0.1.7: {} + fflate@0.4.8: {} + fflate@0.7.4: {} figures@6.1.0: @@ -8328,6 +8616,8 @@ snapshots: chalk: 5.6.2 is-unicode-supported: 1.3.0 + long@5.3.2: {} + longest-streak@3.1.0: {} lru-cache@11.5.0: {} @@ -8866,7 +9156,7 @@ snapshots: nf3@0.3.17: {} - nitro@3.0.260429-beta(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.0)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)): + nitro@3.0.260429-beta(@vercel/functions@3.6.0)(chokidar@5.0.0)(dotenv@17.4.2)(jiti@2.7.0)(lru-cache@11.5.0)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)): dependencies: consola: 3.4.2 crossws: 0.4.5(srvx@0.11.15) @@ -8881,7 +9171,7 @@ snapshots: rolldown: 1.0.2 srvx: 0.11.15 unenv: 2.0.0-rc.24 - unstorage: 2.0.0-alpha.7(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.0)(ofetch@2.0.0-alpha.3) + unstorage: 2.0.0-alpha.7(@vercel/functions@3.6.0)(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.0)(ofetch@2.0.0-alpha.3) optionalDependencies: dotenv: 17.4.2 jiti: 2.7.0 @@ -9191,12 +9481,34 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + posthog-js@1.375.0: + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/exporter-logs-otlp-http': 0.208.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-logs': 0.208.0(@opentelemetry/api@1.9.1) + '@posthog/core': 1.29.8 + '@posthog/types': 1.375.0 + core-js: 3.49.0 + dompurify: 3.4.5 + fflate: 0.4.8 + preact: 10.29.2 + query-selector-shadow-dom: 1.0.1 + web-vitals: 5.2.0 + + posthog-node@5.35.0: + dependencies: + '@posthog/core': 1.29.8 + powershell-utils@0.1.0: {} preact-render-to-string@6.6.5(preact@11.0.0-beta.0): dependencies: preact: 11.0.0-beta.0 + preact@10.29.2: {} + preact@11.0.0-beta.0: {} prettier@2.8.8: {} @@ -9220,6 +9532,21 @@ snapshots: property-information@7.1.0: {} + protobufjs@7.6.0: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 25.9.1 + long: 5.3.2 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -9235,6 +9562,8 @@ snapshots: quansync@1.0.0: {} + query-selector-shadow-dom@1.0.1: {} + queue-microtask@1.2.3: {} range-parser@1.2.1: {} @@ -9971,8 +10300,9 @@ snapshots: picomatch: 4.0.4 webpack-virtual-modules: 0.6.2 - unstorage@2.0.0-alpha.7(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.0)(ofetch@2.0.0-alpha.3): + unstorage@2.0.0-alpha.7(@vercel/functions@3.6.0)(chokidar@5.0.0)(db0@0.3.4)(lru-cache@11.5.0)(ofetch@2.0.0-alpha.3): optionalDependencies: + '@vercel/functions': 3.6.0 chokidar: 5.0.0 db0: 0.3.4 lru-cache: 11.5.0 @@ -10044,7 +10374,7 @@ snapshots: optionalDependencies: vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3) - vitest@4.1.7(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)): + vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1(@noble/hashes@1.8.0))(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)): dependencies: '@vitest/expect': 4.1.7 '@vitest/mocker': 4.1.7(msw@2.14.6(@types/node@25.9.1)(typescript@6.0.3))(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)) @@ -10067,6 +10397,7 @@ snapshots: vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3) why-is-node-running: 2.3.0 optionalDependencies: + '@opentelemetry/api': 1.9.1 '@types/node': 25.9.1 jsdom: 29.1.1(@noble/hashes@1.8.0) transitivePeerDependencies: