📈 Posthog package (#1431)

This commit is contained in:
Luke Vella 2024-11-09 11:30:14 +00:00 committed by GitHub
parent 0fc7d0a0c8
commit a5da319d82
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 189 additions and 133 deletions

View file

@ -22,6 +22,8 @@ const nextConfig = {
"@rallly/icons",
"@rallly/ui",
"@rallly/tailwind-config",
"@rallly/posthog",
"@rallly/emails",
],
webpack(config) {
config.module.rules.push({

View file

@ -31,6 +31,7 @@
"@rallly/emails": "*",
"@rallly/icons": "*",
"@rallly/languages": "*",
"@rallly/posthog": "*",
"@rallly/tailwind-config": "*",
"@rallly/ui": "*",
"@sentry/nextjs": "*",
@ -70,8 +71,6 @@
"next-i18next": "^13.0.3",
"php-serialize": "^4.1.1",
"postcss": "^8.4.31",
"posthog-js": "^1.154.0",
"posthog-node": "^4.0.1",
"react-big-calendar": "^1.8.1",
"react-hook-form": "^7.42.1",
"react-hook-form-persist": "^3.0.0",

View file

@ -1,4 +1,5 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import type {
DialogProps} from "@rallly/ui/dialog";
@ -19,7 +20,6 @@ import { useForm } from "react-hook-form";
import { Trans } from "@/components/trans";
import { useTranslation } from "@/i18n/client";
import { trpc } from "@/trpc/client";
import { usePostHog } from "@/utils/posthog";
export function DeleteAccountDialog({
email,

View file

@ -1,3 +1,4 @@
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import { useToast } from "@rallly/ui/hooks/use-toast";
import * as Sentry from "@sentry/nextjs";
@ -10,7 +11,6 @@ import { useUser } from "@/components/user-provider";
import { IfCloudHosted } from "@/contexts/environment";
import { useTranslation } from "@/i18n/client";
import { trpc } from "@/trpc/client";
import { usePostHog } from "@/utils/posthog";
const allowedMimeTypes = z.enum(["image/jpeg", "image/png"]);

View file

@ -1,5 +1,6 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { cn } from "@rallly/ui";
import { Button } from "@rallly/ui/button";
import { DialogTrigger } from "@rallly/ui/dialog";
@ -26,7 +27,6 @@ import { Trans } from "@/components/trans";
import { IfGuest, useUser } from "@/components/user-provider";
import { IfFreeUser } from "@/contexts/plan";
import type { IconComponent } from "@/types";
import { usePostHog } from "@/utils/posthog";
function NavItem({
href,

View file

@ -1,4 +1,5 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { Alert, AlertDescription, AlertTitle } from "@rallly/ui/alert";
import { Button } from "@rallly/ui/button";
import { Input } from "@rallly/ui/input";
@ -16,7 +17,6 @@ import { VerifyCode, verifyCode } from "@/components/auth/auth-forms";
import { Spinner } from "@/components/spinner";
import { isSelfHosted } from "@/utils/constants";
import { validEmail } from "@/utils/form-validation";
import { usePostHog } from "@/utils/posthog";
const allowGuestAccess = !isSelfHosted;

View file

@ -1,5 +1,6 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import {
Form,
@ -15,7 +16,6 @@ import Link from "next/link";
import { useParams, useSearchParams } from "next/navigation";
import { signIn } from "next-auth/react";
import { useTranslation } from "next-i18next";
import { usePostHog } from "posthog-js/react";
import React from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";

View file

@ -1,4 +1,5 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import { useMutation } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
@ -9,7 +10,6 @@ import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
import { Skeleton } from "@/components/skeleton";
import { Trans } from "@/components/trans";
import { trpc } from "@/trpc/client";
import { usePostHog } from "@/utils/posthog";
type PageProps = { magicLink: string; email: string };

View file

@ -8,6 +8,8 @@ import React from "react";
import { TimeZoneChangeDetector } from "@/app/[locale]/timezone-change-detector";
import { Providers } from "@/app/providers";
import { getServerSession } from "@/auth";
import { SessionProvider } from "@/auth/session-provider";
const inter = Inter({
subsets: ["latin"],
@ -21,21 +23,24 @@ export const viewport: Viewport = {
userScalable: false,
};
export default function Root({
export default async function Root({
children,
params: { locale },
}: {
children: React.ReactNode;
params: { locale: string };
}) {
const session = await getServerSession();
return (
<html lang={locale} className={inter.className}>
<body>
<Toaster />
<SessionProvider session={session}>
<Providers>
{children}
<TimeZoneChangeDetector />
</Providers>
</SessionProvider>
</body>
</html>
);

View file

@ -1,4 +1,5 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import type {
DialogProps} from "@rallly/ui/dialog";
@ -16,7 +17,6 @@ import { useRouter } from "next/navigation";
import { DuplicateForm } from "@/app/[locale]/poll/[urlId]/duplicate-form";
import { trpc } from "@/app/providers";
import { Trans } from "@/components/trans";
import { usePostHog } from "@/utils/posthog";
const formName = "duplicate-form";
export function DuplicateDialog({

View file

@ -1,5 +1,6 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import {
Dialog,
@ -8,7 +9,6 @@ import {
DialogHeader,
DialogTitle,
} from "@rallly/ui/dialog";
import { usePostHog } from "posthog-js/react";
import React, { useState } from "react";
import { Trans } from "@/components/trans";

View file

@ -1,9 +1,8 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import type { ButtonProps } from "@rallly/ui/button";
import { Button } from "@rallly/ui/button";
import { usePostHog } from "@/utils/posthog";
export function LogoutButton({
children,
onClick,

View file

@ -4,7 +4,7 @@ import { randomid } from "@rallly/utils/nanoid";
import languageParser from "accept-language-parser";
import type { NextRequest, NextResponse } from "next/server";
import type { JWT } from "next-auth/jwt";
import { encode } from "next-auth/jwt";
import { decode, encode } from "next-auth/jwt";
const supportedLocales = Object.keys(languages);
@ -61,10 +61,20 @@ export async function resetUser(req: NextRequest, res: NextResponse) {
export async function initGuest(req: NextRequest, res: NextResponse) {
const { name } = getCookieSettings();
if (req.cookies.has(name)) {
// already has a session token
return;
const token = req.cookies.get(name)?.value;
if (token) {
try {
const jwt = await decode({
token,
secret: process.env.SECRET_PASSWORD,
});
if (jwt) {
return jwt;
}
} catch (error) {
// invalid token
console.error(error);
}
}
const locale = await getLocaleFromHeader(req);

View file

@ -1,9 +1,9 @@
"use client";
import { PostHogProvider } from "@rallly/posthog/client";
import { TooltipProvider } from "@rallly/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createTRPCReact } from "@trpc/react-query";
import { domMax, LazyMotion } from "framer-motion";
import { SessionProvider } from "next-auth/react";
import { useState } from "react";
import { UserProvider } from "@/components/user-provider";
@ -32,13 +32,13 @@ export function Providers(props: { children: React.ReactNode }) {
<QueryClientProvider client={queryClient}>
<I18nProvider>
<TooltipProvider>
<SessionProvider>
<PostHogProvider>
<UserProvider>
<ConnectedDayjsProvider>
{props.children}
</ConnectedDayjsProvider>
</UserProvider>
</SessionProvider>
</PostHogProvider>
</TooltipProvider>
</I18nProvider>
</QueryClientProvider>

View file

@ -1,4 +1,5 @@
import { prisma } from "@rallly/database";
import { posthog } from "@rallly/posthog/server";
import { absoluteUrl } from "@rallly/utils/absolute-url";
import { generateOtp, randomid } from "@rallly/utils/nanoid";
import type {
@ -16,15 +17,15 @@ import EmailProvider from "next-auth/providers/email";
import GoogleProvider from "next-auth/providers/google";
import type { Provider } from "next-auth/providers/index";
import { posthog } from "@/app/posthog";
import { CustomPrismaAdapter } from "@/auth/custom-prisma-adapter";
import { mergeGuestsIntoUser } from "@/auth/merge-user";
import { env } from "@/env";
import type { RegistrationTokenPayload } from "@/trpc/types";
import { getEmailClient } from "@/utils/emails";
import { getValueByPath } from "@/utils/get-value-by-path";
import { decryptToken } from "@/utils/session";
import { CustomPrismaAdapter } from "./auth/custom-prisma-adapter";
import { mergeGuestsIntoUser } from "./auth/merge-user";
const providers: Provider[] = [
// When a user registers, we don't want to go through the email verification process
// so this provider allows us exchange the registration token for a session token

View file

@ -0,0 +1,8 @@
"use client";
import type { SessionProviderProps } from "next-auth/react";
import { SessionProvider as NextAuthSessionProvider } from "next-auth/react";
export function SessionProvider(props: SessionProviderProps) {
return <NextAuthSessionProvider {...props} />;
}

View file

@ -1,4 +1,5 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import {
Card,
@ -19,7 +20,6 @@ import { Trans } from "@/components/trans";
import { useUser } from "@/components/user-provider";
import { trpc } from "@/trpc/client";
import { setCookie } from "@/utils/cookies";
import { usePostHog } from "@/utils/posthog";
import type { NewEventData} from "./forms";
import { PollDetailsForm, PollOptionsForm } from "./forms";

View file

@ -1,4 +1,5 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import { cn } from "@rallly/ui";
import { Badge } from "@rallly/ui/badge";
import { Button } from "@rallly/ui/button";
@ -37,7 +38,6 @@ import { usePermissions } from "@/contexts/permissions";
import { usePoll } from "@/contexts/poll";
import { useRole } from "@/contexts/role";
import { trpc } from "@/trpc/client";
import { usePostHog } from "@/utils/posthog";
import { requiredString } from "../../utils/form-validation";
import TruncatedLinkify from "../poll/truncated-linkify";

View file

@ -1,3 +1,4 @@
import { usePostHog } from "@rallly/posthog/client";
import { cn } from "@rallly/ui";
import {
Card,
@ -17,7 +18,6 @@ import { Trans } from "react-i18next";
import { PayWallDialog } from "@/components/pay-wall-dialog";
import { ProFeatureBadge } from "@/components/pro-feature-badge";
import { usePlan } from "@/contexts/plan";
import { usePostHog } from "@/utils/posthog";
export type PollSettingsFormData = {
requireParticipantEmail: boolean;

View file

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import {
Dialog,
@ -40,7 +41,6 @@ import { useDeleteParticipantMutation } from "@/components/poll/mutations";
import { Trans } from "@/components/trans";
import { trpc } from "@/trpc/client";
import { useFormValidation } from "@/utils/form-validation";
import { usePostHog } from "@/utils/posthog";
export const ParticipantDropdown = ({
participant,

View file

@ -1,3 +1,4 @@
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import { useDialog } from "@rallly/ui/dialog";
import {
@ -34,7 +35,6 @@ import { ProFeatureBadge } from "@/components/pro-feature-badge";
import { Trans } from "@/components/trans";
import { usePlan } from "@/contexts/plan";
import { usePoll } from "@/contexts/poll";
import { usePostHog } from "@/utils/posthog";
import { DeletePollDialog } from "./manage-poll/delete-poll-dialog";
import { useCsvExporter } from "./manage-poll/use-csv-exporter";

View file

@ -1,3 +1,4 @@
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import {
Dialog,
@ -11,7 +12,6 @@ import * as React from "react";
import { Trans } from "@/components/trans";
import { trpc } from "@/trpc/client";
import { usePostHog } from "@/utils/posthog";
export const DeletePollDialog: React.FunctionComponent<{
open: boolean;

View file

@ -1,6 +1,7 @@
import { usePostHog } from "@rallly/posthog/client";
import { usePoll } from "@/components/poll-context";
import { trpc } from "@/trpc/client";
import { usePostHog } from "@/utils/posthog";
import type { ParticipantForm } from "./types";

View file

@ -1,3 +1,4 @@
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import { Icon } from "@rallly/ui/icon";
import { Tooltip, TooltipContent, TooltipTrigger } from "@rallly/ui/tooltip";
@ -10,7 +11,6 @@ import { Skeleton } from "@/components/skeleton";
import { Trans } from "@/components/trans";
import { useUser } from "@/components/user-provider";
import { trpc } from "@/trpc/client";
import { usePostHog } from "@/utils/posthog";
import { usePoll } from "../poll-context";

View file

@ -1,10 +1,9 @@
import { usePostHog } from "@rallly/posthog/client";
import { Button } from "@rallly/ui/button";
import Link from "next/link";
import { Trans } from "next-i18next";
import React from "react";
import { usePostHog } from "@/utils/posthog";
export const UpgradeButton = ({
children,
annual,

View file

@ -1,11 +1,11 @@
"use client";
import { usePostHog } from "@rallly/posthog/client";
import type { Session } from "next-auth";
import { useSession } from "next-auth/react";
import React from "react";
import { Spinner } from "@/components/spinner";
import { useSubscription } from "@/contexts/plan";
import { PostHogProvider } from "@/contexts/posthog";
import { PreferencesProvider } from "@/contexts/preferences";
import { useTranslation } from "@/i18n/client";
import { trpc } from "@/trpc/client";
@ -60,6 +60,25 @@ export const UserProvider = (props: { children?: React.ReactNode }) => {
const updatePreferences = trpc.user.updatePreferences.useMutation();
const { t, i18n } = useTranslation();
const posthog = usePostHog();
const isGuest = !user?.email;
const tier = isGuest ? "guest" : subscription?.active ? "pro" : "hobby";
React.useEffect(() => {
if (user) {
posthog?.identify(user.id, {
email: user.email,
name: user.name,
tier,
timeZone: user.timeZone ?? null,
image: user.image ?? null,
locale: user.locale ?? i18n.language,
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user?.id]);
if (!user) {
return (
<div className="flex h-screen items-center justify-center">
@ -68,9 +87,6 @@ export const UserProvider = (props: { children?: React.ReactNode }) => {
);
}
const isGuest = !user.email;
const tier = isGuest ? "guest" : subscription?.active ? "pro" : "hobby";
return (
<UserContext.Provider
value={{
@ -109,7 +125,7 @@ export const UserProvider = (props: { children?: React.ReactNode }) => {
await session.update(newPreferences);
}}
>
<PostHogProvider>{props.children}</PostHogProvider>
{props.children}
</PreferencesProvider>
</UserContext.Provider>
);

View file

@ -1,67 +0,0 @@
"use client";
import { usePathname, useSearchParams } from "next/navigation";
import posthog from "posthog-js";
import { PostHogProvider as Provider, usePostHog } from "posthog-js/react";
import React from "react";
import { useMount } from "react-use";
import { useUser } from "@/components/user-provider";
import { env } from "@/env";
type PostHogProviderProps = React.PropsWithChildren;
if (typeof window !== "undefined" && env.NEXT_PUBLIC_POSTHOG_API_KEY) {
posthog.init(env.NEXT_PUBLIC_POSTHOG_API_KEY, {
debug: false,
api_host: env.NEXT_PUBLIC_POSTHOG_API_HOST,
capture_pageview: false,
capture_pageleave: true,
disable_session_recording: true,
enable_heatmaps: false,
persistence: "memory",
autocapture: false,
opt_out_capturing_by_default: false,
});
}
function usePostHogPageView() {
const pathname = usePathname();
const searchParams = useSearchParams();
const posthog = usePostHog();
const previousUrl = React.useRef<string | null>(null);
React.useEffect(() => {
// Track pageviews
if (pathname && posthog) {
let url = window.origin + pathname;
if (searchParams?.toString()) {
url = url + `?${searchParams.toString()}`;
}
if (previousUrl.current !== url) {
posthog.capture("$pageview", {
$current_url: url,
});
previousUrl.current = url;
}
}
}, [pathname, searchParams, posthog]);
}
export function PostHogProvider(props: PostHogProviderProps) {
const { user } = useUser();
usePostHogPageView();
useMount(() => {
if (user.email) {
posthog.identify(user.id, {
email: user.email,
name: user.name,
tier: user.tier,
timeZone: user.timeZone,
locale: user.locale,
});
}
});
return <Provider client={posthog}>{props.children}</Provider>;
}

View file

@ -1,4 +1,5 @@
import languages from "@rallly/languages";
import { withPostHog } from "@rallly/posthog/next/middleware";
import { NextResponse } from "next/server";
import withAuth from "next-auth/middleware";
@ -34,7 +35,11 @@ export const middleware = withAuth(
const res = NextResponse.rewrite(newUrl);
await initGuest(req, res);
const jwt = await initGuest(req, res);
if (jwt?.sub) {
await withPostHog(res, { distinctID: jwt.sub });
}
return res;
},

View file

@ -1,6 +1,6 @@
import { posthogApiHandler } from "@rallly/posthog/server";
import type { NextApiRequest, NextApiResponse } from "next";
import { posthogApiHandler } from "@/app/posthog";
import { AuthApiRoute } from "@/auth";
import { composeApiHandlers } from "@/utils/next";

View file

@ -1,12 +1,12 @@
import type { Stripe } from "@rallly/billing";
import { stripe } from "@rallly/billing";
import { prisma } from "@rallly/database";
import { posthog, posthogApiHandler } from "@rallly/posthog/server";
import * as Sentry from "@sentry/node";
import { buffer } from "micro";
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import { posthog, posthogApiHandler } from "@/app/posthog";
import { composeApiHandlers } from "@/utils/next";
export const config = {

View file

@ -1,10 +1,10 @@
import { posthogApiHandler } from "@rallly/posthog/server";
import * as Sentry from "@sentry/nextjs";
import { TRPCError } from "@trpc/server";
import { createNextApiHandler } from "@trpc/server/adapters/next";
import { posthogApiHandler } from "@/app/posthog";
import { getServerSession } from "@/auth";
import type { AppRouter} from "@/trpc/routers";
import type { AppRouter } from "@/trpc/routers";
import { appRouter } from "@/trpc/routers";
import { getEmailClient } from "@/utils/emails";
import { composeApiHandlers } from "@/utils/next";

View file

@ -1,8 +1,8 @@
import { prisma } from "@rallly/database";
import { posthog } from "@rallly/posthog/server";
import { generateOtp } from "@rallly/utils/nanoid";
import { z } from "zod";
import { posthog } from "@/app/posthog";
import { isEmailBlocked } from "@/auth";
import { createToken, decryptToken } from "@/utils/session";

View file

@ -1,5 +1,6 @@
import type { PollStatus } from "@rallly/database";
import { prisma } from "@rallly/database";
import { posthog } from "@rallly/posthog/server";
import { absoluteUrl, shortUrl } from "@rallly/utils/absolute-url";
import { nanoid } from "@rallly/utils/nanoid";
import { TRPCError } from "@trpc/server";
@ -7,7 +8,6 @@ import dayjs from "dayjs";
import * as ics from "ics";
import { z } from "zod";
import { posthog } from "@/app/posthog";
import { getEmailClient } from "@/utils/emails";
import { getTimeZoneAbbreviation } from "../../utils/date";

View file

@ -1,6 +0,0 @@
import { usePostHog as usePostHogHook } from "posthog-js/react";
export const usePostHog = () => {
const posthog = usePostHogHook();
return process.env.NEXT_PUBLIC_POSTHOG_API_KEY ? posthog : null;
};

View file

@ -0,0 +1,2 @@
/** @type {import("eslint").Linter.Config} */
module.exports = require("@rallly/eslint-config/preset")(__dirname);

View file

@ -0,0 +1,18 @@
{
"name": "@rallly/posthog",
"version": "0.0.0",
"private": true,
"exports": {
"./server": "./src/server/index.ts",
"./client": "./src/client/index.ts",
"./next/middleware": "./src/next/middleware.ts"
},
"dependencies": {
"posthog-js": "^1.178.0",
"posthog-node": "^4.2.1"
},
"peerDependencies": {
"next": "^14.2.13",
"react": "^18.2.0"
}
}

View file

@ -0,0 +1,2 @@
export { PostHogProvider } from "./provider";
export { usePostHog } from "posthog-js/react";

View file

@ -0,0 +1,36 @@
"use client";
import Cookies from "js-cookie";
import posthog from "posthog-js";
import { PostHogProvider as Provider } from "posthog-js/react";
import React from "react";
import { POSTHOG_BOOTSTAP_DATA_COOKIE_NAME } from "../constants";
if (typeof window !== "undefined" && process.env.NEXT_PUBLIC_POSTHOG_API_KEY) {
let bootstrapData = {};
try {
const cookieData = Cookies.get(POSTHOG_BOOTSTAP_DATA_COOKIE_NAME);
if (cookieData) {
bootstrapData = JSON.parse(cookieData);
}
} catch (error) {
console.warn("Failed to parse PostHog bootstrap data:", error);
}
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_API_KEY, {
debug: false,
api_host: process.env.NEXT_PUBLIC_POSTHOG_API_HOST,
capture_pageview: false,
capture_pageleave: true,
disable_session_recording: true,
enable_heatmaps: false,
persistence: "memory",
bootstrap: bootstrapData,
autocapture: false,
opt_out_capturing_by_default: false,
});
}
export function PostHogProvider(props: { children?: React.ReactNode }) {
return <Provider client={posthog}>{props.children}</Provider>;
}

View file

@ -0,0 +1 @@
export const POSTHOG_BOOTSTAP_DATA_COOKIE_NAME = "posthog_bootstrap_data";

View file

@ -0,0 +1,22 @@
import { NextResponse } from "next/server";
import { POSTHOG_BOOTSTAP_DATA_COOKIE_NAME } from "../constants";
const posthogApiKey = process.env.NEXT_PUBLIC_POSTHOG_API_KEY;
export async function withPostHog(
res: NextResponse,
bootstrapData: { distinctID?: string },
) {
if (!posthogApiKey) {
return;
}
res.cookies.set({
name: POSTHOG_BOOTSTAP_DATA_COOKIE_NAME,
value: JSON.stringify(bootstrapData),
httpOnly: false,
secure: true,
sameSite: "lax",
path: "/",
});
}

View file

@ -1,13 +1,11 @@
import { waitUntil } from "@vercel/functions";
import { PostHog } from "posthog-node";
import { env } from "@/env";
function PostHogClient() {
if (!env.NEXT_PUBLIC_POSTHOG_API_KEY) return null;
if (!process.env.NEXT_PUBLIC_POSTHOG_API_KEY) return null;
const posthogClient = new PostHog(env.NEXT_PUBLIC_POSTHOG_API_KEY, {
host: env.NEXT_PUBLIC_POSTHOG_API_HOST,
const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_API_KEY, {
host: process.env.NEXT_PUBLIC_POSTHOG_API_HOST,
flushAt: 1,
flushInterval: 0,
});

View file

@ -0,0 +1,5 @@
{
"extends": "@rallly/tsconfig/next.json",
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"],
}

View file

@ -12718,17 +12718,17 @@ postgres-range@^1.1.1:
resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863"
integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==
posthog-js@^1.154.0:
version "1.181.0"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.181.0.tgz#b2119f6a27b27297dee9540bfcd33eddab06905c"
integrity sha512-bI+J+f4E8x4JwbGtG6LReQv1Xvss01F6cs7UDlvffHySpVhNq4ptkNjV88B92IVEsrCtNYhy/TjFnGxk6RN0Qw==
posthog-js@^1.178.0:
version "1.178.0"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.178.0.tgz#80005798e6c67d4d6565a5648939a0f017b0879b"
integrity sha512-ILD4flNh72d5dycc4ZouKORlaVr+pDzl5TlZr1JgP0NBAoduHjhE7XZYwk7zdYkry7u0qAIpfv2306zJCW2vGg==
dependencies:
core-js "^3.38.1"
fflate "^0.4.8"
preact "^10.19.3"
web-vitals "^4.2.0"
posthog-node@^4.0.1:
posthog-node@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-4.2.1.tgz#c9f077116bebd06dc65a3f9ae282d10db242c660"
integrity sha512-l+fsjYEkTik3m/G0pE7gMr4qBJP84LhK779oQm6MBzhBGpd4By4qieTW+4FUAlNCyzQTynn3Nhsa50c0IELSxQ==