mirror of
https://github.com/lukevella/rallly.git
synced 2025-07-01 16:47:28 +02:00
📈 Posthog package (#1431)
This commit is contained in:
parent
0fc7d0a0c8
commit
a5da319d82
43 changed files with 189 additions and 133 deletions
|
@ -22,6 +22,8 @@ const nextConfig = {
|
||||||
"@rallly/icons",
|
"@rallly/icons",
|
||||||
"@rallly/ui",
|
"@rallly/ui",
|
||||||
"@rallly/tailwind-config",
|
"@rallly/tailwind-config",
|
||||||
|
"@rallly/posthog",
|
||||||
|
"@rallly/emails",
|
||||||
],
|
],
|
||||||
webpack(config) {
|
webpack(config) {
|
||||||
config.module.rules.push({
|
config.module.rules.push({
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"@rallly/emails": "*",
|
"@rallly/emails": "*",
|
||||||
"@rallly/icons": "*",
|
"@rallly/icons": "*",
|
||||||
"@rallly/languages": "*",
|
"@rallly/languages": "*",
|
||||||
|
"@rallly/posthog": "*",
|
||||||
"@rallly/tailwind-config": "*",
|
"@rallly/tailwind-config": "*",
|
||||||
"@rallly/ui": "*",
|
"@rallly/ui": "*",
|
||||||
"@sentry/nextjs": "*",
|
"@sentry/nextjs": "*",
|
||||||
|
@ -70,8 +71,6 @@
|
||||||
"next-i18next": "^13.0.3",
|
"next-i18next": "^13.0.3",
|
||||||
"php-serialize": "^4.1.1",
|
"php-serialize": "^4.1.1",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"posthog-js": "^1.154.0",
|
|
||||||
"posthog-node": "^4.0.1",
|
|
||||||
"react-big-calendar": "^1.8.1",
|
"react-big-calendar": "^1.8.1",
|
||||||
"react-hook-form": "^7.42.1",
|
"react-hook-form": "^7.42.1",
|
||||||
"react-hook-form-persist": "^3.0.0",
|
"react-hook-form-persist": "^3.0.0",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import type {
|
import type {
|
||||||
DialogProps} from "@rallly/ui/dialog";
|
DialogProps} from "@rallly/ui/dialog";
|
||||||
|
@ -19,7 +20,6 @@ import { useForm } from "react-hook-form";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { useTranslation } from "@/i18n/client";
|
import { useTranslation } from "@/i18n/client";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
export function DeleteAccountDialog({
|
export function DeleteAccountDialog({
|
||||||
email,
|
email,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { useToast } from "@rallly/ui/hooks/use-toast";
|
import { useToast } from "@rallly/ui/hooks/use-toast";
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
|
@ -10,7 +11,6 @@ import { useUser } from "@/components/user-provider";
|
||||||
import { IfCloudHosted } from "@/contexts/environment";
|
import { IfCloudHosted } from "@/contexts/environment";
|
||||||
import { useTranslation } from "@/i18n/client";
|
import { useTranslation } from "@/i18n/client";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
const allowedMimeTypes = z.enum(["image/jpeg", "image/png"]);
|
const allowedMimeTypes = z.enum(["image/jpeg", "image/png"]);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { DialogTrigger } from "@rallly/ui/dialog";
|
import { DialogTrigger } from "@rallly/ui/dialog";
|
||||||
|
@ -26,7 +27,6 @@ import { Trans } from "@/components/trans";
|
||||||
import { IfGuest, useUser } from "@/components/user-provider";
|
import { IfGuest, useUser } from "@/components/user-provider";
|
||||||
import { IfFreeUser } from "@/contexts/plan";
|
import { IfFreeUser } from "@/contexts/plan";
|
||||||
import type { IconComponent } from "@/types";
|
import type { IconComponent } from "@/types";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
function NavItem({
|
function NavItem({
|
||||||
href,
|
href,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@rallly/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@rallly/ui/alert";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { Input } from "@rallly/ui/input";
|
import { Input } from "@rallly/ui/input";
|
||||||
|
@ -16,7 +17,6 @@ import { VerifyCode, verifyCode } from "@/components/auth/auth-forms";
|
||||||
import { Spinner } from "@/components/spinner";
|
import { Spinner } from "@/components/spinner";
|
||||||
import { isSelfHosted } from "@/utils/constants";
|
import { isSelfHosted } from "@/utils/constants";
|
||||||
import { validEmail } from "@/utils/form-validation";
|
import { validEmail } from "@/utils/form-validation";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
const allowGuestAccess = !isSelfHosted;
|
const allowGuestAccess = !isSelfHosted;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
|
@ -15,7 +16,6 @@ import Link from "next/link";
|
||||||
import { useParams, useSearchParams } from "next/navigation";
|
import { useParams, useSearchParams } from "next/navigation";
|
||||||
import { signIn } from "next-auth/react";
|
import { signIn } from "next-auth/react";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import { usePostHog } from "posthog-js/react";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
@ -9,7 +10,6 @@ import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
|
||||||
import { Skeleton } from "@/components/skeleton";
|
import { Skeleton } from "@/components/skeleton";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
type PageProps = { magicLink: string; email: string };
|
type PageProps = { magicLink: string; email: string };
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import React from "react";
|
||||||
|
|
||||||
import { TimeZoneChangeDetector } from "@/app/[locale]/timezone-change-detector";
|
import { TimeZoneChangeDetector } from "@/app/[locale]/timezone-change-detector";
|
||||||
import { Providers } from "@/app/providers";
|
import { Providers } from "@/app/providers";
|
||||||
|
import { getServerSession } from "@/auth";
|
||||||
|
import { SessionProvider } from "@/auth/session-provider";
|
||||||
|
|
||||||
const inter = Inter({
|
const inter = Inter({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
|
@ -21,21 +23,24 @@ export const viewport: Viewport = {
|
||||||
userScalable: false,
|
userScalable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Root({
|
export default async function Root({
|
||||||
children,
|
children,
|
||||||
params: { locale },
|
params: { locale },
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
params: { locale: string };
|
params: { locale: string };
|
||||||
}) {
|
}) {
|
||||||
|
const session = await getServerSession();
|
||||||
return (
|
return (
|
||||||
<html lang={locale} className={inter.className}>
|
<html lang={locale} className={inter.className}>
|
||||||
<body>
|
<body>
|
||||||
<Toaster />
|
<Toaster />
|
||||||
|
<SessionProvider session={session}>
|
||||||
<Providers>
|
<Providers>
|
||||||
{children}
|
{children}
|
||||||
<TimeZoneChangeDetector />
|
<TimeZoneChangeDetector />
|
||||||
</Providers>
|
</Providers>
|
||||||
|
</SessionProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import type {
|
import type {
|
||||||
DialogProps} from "@rallly/ui/dialog";
|
DialogProps} from "@rallly/ui/dialog";
|
||||||
|
@ -16,7 +17,6 @@ import { useRouter } from "next/navigation";
|
||||||
import { DuplicateForm } from "@/app/[locale]/poll/[urlId]/duplicate-form";
|
import { DuplicateForm } from "@/app/[locale]/poll/[urlId]/duplicate-form";
|
||||||
import { trpc } from "@/app/providers";
|
import { trpc } from "@/app/providers";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
const formName = "duplicate-form";
|
const formName = "duplicate-form";
|
||||||
export function DuplicateDialog({
|
export function DuplicateDialog({
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
@ -8,7 +9,6 @@ import {
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@rallly/ui/dialog";
|
} from "@rallly/ui/dialog";
|
||||||
import { usePostHog } from "posthog-js/react";
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import type { ButtonProps } from "@rallly/ui/button";
|
import type { ButtonProps } from "@rallly/ui/button";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
|
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
export function LogoutButton({
|
export function LogoutButton({
|
||||||
children,
|
children,
|
||||||
onClick,
|
onClick,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { randomid } from "@rallly/utils/nanoid";
|
||||||
import languageParser from "accept-language-parser";
|
import languageParser from "accept-language-parser";
|
||||||
import type { NextRequest, NextResponse } from "next/server";
|
import type { NextRequest, NextResponse } from "next/server";
|
||||||
import type { JWT } from "next-auth/jwt";
|
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);
|
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) {
|
export async function initGuest(req: NextRequest, res: NextResponse) {
|
||||||
const { name } = getCookieSettings();
|
const { name } = getCookieSettings();
|
||||||
|
const token = req.cookies.get(name)?.value;
|
||||||
if (req.cookies.has(name)) {
|
if (token) {
|
||||||
// already has a session token
|
try {
|
||||||
return;
|
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);
|
const locale = await getLocaleFromHeader(req);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { PostHogProvider } from "@rallly/posthog/client";
|
||||||
import { TooltipProvider } from "@rallly/ui/tooltip";
|
import { TooltipProvider } from "@rallly/ui/tooltip";
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { createTRPCReact } from "@trpc/react-query";
|
import { createTRPCReact } from "@trpc/react-query";
|
||||||
import { domMax, LazyMotion } from "framer-motion";
|
import { domMax, LazyMotion } from "framer-motion";
|
||||||
import { SessionProvider } from "next-auth/react";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { UserProvider } from "@/components/user-provider";
|
import { UserProvider } from "@/components/user-provider";
|
||||||
|
@ -32,13 +32,13 @@ export function Providers(props: { children: React.ReactNode }) {
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<I18nProvider>
|
<I18nProvider>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<SessionProvider>
|
<PostHogProvider>
|
||||||
<UserProvider>
|
<UserProvider>
|
||||||
<ConnectedDayjsProvider>
|
<ConnectedDayjsProvider>
|
||||||
{props.children}
|
{props.children}
|
||||||
</ConnectedDayjsProvider>
|
</ConnectedDayjsProvider>
|
||||||
</UserProvider>
|
</UserProvider>
|
||||||
</SessionProvider>
|
</PostHogProvider>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</I18nProvider>
|
</I18nProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
|
import { posthog } from "@rallly/posthog/server";
|
||||||
import { absoluteUrl } from "@rallly/utils/absolute-url";
|
import { absoluteUrl } from "@rallly/utils/absolute-url";
|
||||||
import { generateOtp, randomid } from "@rallly/utils/nanoid";
|
import { generateOtp, randomid } from "@rallly/utils/nanoid";
|
||||||
import type {
|
import type {
|
||||||
|
@ -16,15 +17,15 @@ import EmailProvider from "next-auth/providers/email";
|
||||||
import GoogleProvider from "next-auth/providers/google";
|
import GoogleProvider from "next-auth/providers/google";
|
||||||
import type { Provider } from "next-auth/providers/index";
|
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 { env } from "@/env";
|
||||||
import type { RegistrationTokenPayload } from "@/trpc/types";
|
import type { RegistrationTokenPayload } from "@/trpc/types";
|
||||||
import { getEmailClient } from "@/utils/emails";
|
import { getEmailClient } from "@/utils/emails";
|
||||||
import { getValueByPath } from "@/utils/get-value-by-path";
|
import { getValueByPath } from "@/utils/get-value-by-path";
|
||||||
import { decryptToken } from "@/utils/session";
|
import { decryptToken } from "@/utils/session";
|
||||||
|
|
||||||
|
import { CustomPrismaAdapter } from "./auth/custom-prisma-adapter";
|
||||||
|
import { mergeGuestsIntoUser } from "./auth/merge-user";
|
||||||
|
|
||||||
const providers: Provider[] = [
|
const providers: Provider[] = [
|
||||||
// When a user registers, we don't want to go through the email verification process
|
// 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
|
// so this provider allows us exchange the registration token for a session token
|
||||||
|
|
8
apps/web/src/auth/session-provider.tsx
Normal file
8
apps/web/src/auth/session-provider.tsx
Normal 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} />;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
@ -19,7 +20,6 @@ import { Trans } from "@/components/trans";
|
||||||
import { useUser } from "@/components/user-provider";
|
import { useUser } from "@/components/user-provider";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { setCookie } from "@/utils/cookies";
|
import { setCookie } from "@/utils/cookies";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
import type { NewEventData} from "./forms";
|
import type { NewEventData} from "./forms";
|
||||||
import { PollDetailsForm, PollOptionsForm } from "./forms";
|
import { PollDetailsForm, PollOptionsForm } from "./forms";
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import { Badge } from "@rallly/ui/badge";
|
import { Badge } from "@rallly/ui/badge";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
|
@ -37,7 +38,6 @@ import { usePermissions } from "@/contexts/permissions";
|
||||||
import { usePoll } from "@/contexts/poll";
|
import { usePoll } from "@/contexts/poll";
|
||||||
import { useRole } from "@/contexts/role";
|
import { useRole } from "@/contexts/role";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
import { requiredString } from "../../utils/form-validation";
|
import { requiredString } from "../../utils/form-validation";
|
||||||
import TruncatedLinkify from "../poll/truncated-linkify";
|
import TruncatedLinkify from "../poll/truncated-linkify";
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { cn } from "@rallly/ui";
|
import { cn } from "@rallly/ui";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
@ -17,7 +18,6 @@ import { Trans } from "react-i18next";
|
||||||
import { PayWallDialog } from "@/components/pay-wall-dialog";
|
import { PayWallDialog } from "@/components/pay-wall-dialog";
|
||||||
import { ProFeatureBadge } from "@/components/pro-feature-badge";
|
import { ProFeatureBadge } from "@/components/pro-feature-badge";
|
||||||
import { usePlan } from "@/contexts/plan";
|
import { usePlan } from "@/contexts/plan";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
export type PollSettingsFormData = {
|
export type PollSettingsFormData = {
|
||||||
requireParticipantEmail: boolean;
|
requireParticipantEmail: boolean;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
@ -40,7 +41,6 @@ import { useDeleteParticipantMutation } from "@/components/poll/mutations";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { useFormValidation } from "@/utils/form-validation";
|
import { useFormValidation } from "@/utils/form-validation";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
export const ParticipantDropdown = ({
|
export const ParticipantDropdown = ({
|
||||||
participant,
|
participant,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { useDialog } from "@rallly/ui/dialog";
|
import { useDialog } from "@rallly/ui/dialog";
|
||||||
import {
|
import {
|
||||||
|
@ -34,7 +35,6 @@ import { ProFeatureBadge } from "@/components/pro-feature-badge";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { usePlan } from "@/contexts/plan";
|
import { usePlan } from "@/contexts/plan";
|
||||||
import { usePoll } from "@/contexts/poll";
|
import { usePoll } from "@/contexts/poll";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
import { DeletePollDialog } from "./manage-poll/delete-poll-dialog";
|
import { DeletePollDialog } from "./manage-poll/delete-poll-dialog";
|
||||||
import { useCsvExporter } from "./manage-poll/use-csv-exporter";
|
import { useCsvExporter } from "./manage-poll/use-csv-exporter";
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
@ -11,7 +12,6 @@ import * as React from "react";
|
||||||
|
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
export const DeletePollDialog: React.FunctionComponent<{
|
export const DeletePollDialog: React.FunctionComponent<{
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
|
|
||||||
import { usePoll } from "@/components/poll-context";
|
import { usePoll } from "@/components/poll-context";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
import type { ParticipantForm } from "./types";
|
import type { ParticipantForm } from "./types";
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import { Icon } from "@rallly/ui/icon";
|
import { Icon } from "@rallly/ui/icon";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@rallly/ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@rallly/ui/tooltip";
|
||||||
|
@ -10,7 +11,6 @@ import { Skeleton } from "@/components/skeleton";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { useUser } from "@/components/user-provider";
|
import { useUser } from "@/components/user-provider";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
import { usePoll } from "../poll-context";
|
import { usePoll } from "../poll-context";
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import { Button } from "@rallly/ui/button";
|
import { Button } from "@rallly/ui/button";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Trans } from "next-i18next";
|
import { Trans } from "next-i18next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { usePostHog } from "@/utils/posthog";
|
|
||||||
|
|
||||||
export const UpgradeButton = ({
|
export const UpgradeButton = ({
|
||||||
children,
|
children,
|
||||||
annual,
|
annual,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
import { usePostHog } from "@rallly/posthog/client";
|
||||||
import type { Session } from "next-auth";
|
import type { Session } from "next-auth";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { Spinner } from "@/components/spinner";
|
import { Spinner } from "@/components/spinner";
|
||||||
import { useSubscription } from "@/contexts/plan";
|
import { useSubscription } from "@/contexts/plan";
|
||||||
import { PostHogProvider } from "@/contexts/posthog";
|
|
||||||
import { PreferencesProvider } from "@/contexts/preferences";
|
import { PreferencesProvider } from "@/contexts/preferences";
|
||||||
import { useTranslation } from "@/i18n/client";
|
import { useTranslation } from "@/i18n/client";
|
||||||
import { trpc } from "@/trpc/client";
|
import { trpc } from "@/trpc/client";
|
||||||
|
@ -60,6 +60,25 @@ export const UserProvider = (props: { children?: React.ReactNode }) => {
|
||||||
const updatePreferences = trpc.user.updatePreferences.useMutation();
|
const updatePreferences = trpc.user.updatePreferences.useMutation();
|
||||||
const { t, i18n } = useTranslation();
|
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) {
|
if (!user) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen items-center justify-center">
|
<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 (
|
return (
|
||||||
<UserContext.Provider
|
<UserContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
@ -109,7 +125,7 @@ export const UserProvider = (props: { children?: React.ReactNode }) => {
|
||||||
await session.update(newPreferences);
|
await session.update(newPreferences);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PostHogProvider>{props.children}</PostHogProvider>
|
{props.children}
|
||||||
</PreferencesProvider>
|
</PreferencesProvider>
|
||||||
</UserContext.Provider>
|
</UserContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>;
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
import languages from "@rallly/languages";
|
import languages from "@rallly/languages";
|
||||||
|
import { withPostHog } from "@rallly/posthog/next/middleware";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import withAuth from "next-auth/middleware";
|
import withAuth from "next-auth/middleware";
|
||||||
|
|
||||||
|
@ -34,7 +35,11 @@ export const middleware = withAuth(
|
||||||
|
|
||||||
const res = NextResponse.rewrite(newUrl);
|
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;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { posthogApiHandler } from "@rallly/posthog/server";
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
import { posthogApiHandler } from "@/app/posthog";
|
|
||||||
import { AuthApiRoute } from "@/auth";
|
import { AuthApiRoute } from "@/auth";
|
||||||
import { composeApiHandlers } from "@/utils/next";
|
import { composeApiHandlers } from "@/utils/next";
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import type { Stripe } from "@rallly/billing";
|
import type { Stripe } from "@rallly/billing";
|
||||||
import { stripe } from "@rallly/billing";
|
import { stripe } from "@rallly/billing";
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
|
import { posthog, posthogApiHandler } from "@rallly/posthog/server";
|
||||||
import * as Sentry from "@sentry/node";
|
import * as Sentry from "@sentry/node";
|
||||||
import { buffer } from "micro";
|
import { buffer } from "micro";
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { posthog, posthogApiHandler } from "@/app/posthog";
|
|
||||||
import { composeApiHandlers } from "@/utils/next";
|
import { composeApiHandlers } from "@/utils/next";
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import { posthogApiHandler } from "@rallly/posthog/server";
|
||||||
import * as Sentry from "@sentry/nextjs";
|
import * as Sentry from "@sentry/nextjs";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { createNextApiHandler } from "@trpc/server/adapters/next";
|
import { createNextApiHandler } from "@trpc/server/adapters/next";
|
||||||
|
|
||||||
import { posthogApiHandler } from "@/app/posthog";
|
|
||||||
import { getServerSession } from "@/auth";
|
import { getServerSession } from "@/auth";
|
||||||
import type { AppRouter} from "@/trpc/routers";
|
import type { AppRouter } from "@/trpc/routers";
|
||||||
import { appRouter } from "@/trpc/routers";
|
import { appRouter } from "@/trpc/routers";
|
||||||
import { getEmailClient } from "@/utils/emails";
|
import { getEmailClient } from "@/utils/emails";
|
||||||
import { composeApiHandlers } from "@/utils/next";
|
import { composeApiHandlers } from "@/utils/next";
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
|
import { posthog } from "@rallly/posthog/server";
|
||||||
import { generateOtp } from "@rallly/utils/nanoid";
|
import { generateOtp } from "@rallly/utils/nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { posthog } from "@/app/posthog";
|
|
||||||
import { isEmailBlocked } from "@/auth";
|
import { isEmailBlocked } from "@/auth";
|
||||||
import { createToken, decryptToken } from "@/utils/session";
|
import { createToken, decryptToken } from "@/utils/session";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type { PollStatus } from "@rallly/database";
|
import type { PollStatus } from "@rallly/database";
|
||||||
import { prisma } from "@rallly/database";
|
import { prisma } from "@rallly/database";
|
||||||
|
import { posthog } from "@rallly/posthog/server";
|
||||||
import { absoluteUrl, shortUrl } from "@rallly/utils/absolute-url";
|
import { absoluteUrl, shortUrl } from "@rallly/utils/absolute-url";
|
||||||
import { nanoid } from "@rallly/utils/nanoid";
|
import { nanoid } from "@rallly/utils/nanoid";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
@ -7,7 +8,6 @@ import dayjs from "dayjs";
|
||||||
import * as ics from "ics";
|
import * as ics from "ics";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { posthog } from "@/app/posthog";
|
|
||||||
import { getEmailClient } from "@/utils/emails";
|
import { getEmailClient } from "@/utils/emails";
|
||||||
|
|
||||||
import { getTimeZoneAbbreviation } from "../../utils/date";
|
import { getTimeZoneAbbreviation } from "../../utils/date";
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
2
packages/posthog/.eslintrc.js
Normal file
2
packages/posthog/.eslintrc.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/** @type {import("eslint").Linter.Config} */
|
||||||
|
module.exports = require("@rallly/eslint-config/preset")(__dirname);
|
18
packages/posthog/package.json
Normal file
18
packages/posthog/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
2
packages/posthog/src/client/index.ts
Normal file
2
packages/posthog/src/client/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { PostHogProvider } from "./provider";
|
||||||
|
export { usePostHog } from "posthog-js/react";
|
36
packages/posthog/src/client/provider.tsx
Normal file
36
packages/posthog/src/client/provider.tsx
Normal 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>;
|
||||||
|
}
|
1
packages/posthog/src/constants.ts
Normal file
1
packages/posthog/src/constants.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const POSTHOG_BOOTSTAP_DATA_COOKIE_NAME = "posthog_bootstrap_data";
|
22
packages/posthog/src/next/middleware.ts
Normal file
22
packages/posthog/src/next/middleware.ts
Normal 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: "/",
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,13 +1,11 @@
|
||||||
import { waitUntil } from "@vercel/functions";
|
import { waitUntil } from "@vercel/functions";
|
||||||
import { PostHog } from "posthog-node";
|
import { PostHog } from "posthog-node";
|
||||||
|
|
||||||
import { env } from "@/env";
|
|
||||||
|
|
||||||
function PostHogClient() {
|
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, {
|
const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_API_KEY, {
|
||||||
host: env.NEXT_PUBLIC_POSTHOG_API_HOST,
|
host: process.env.NEXT_PUBLIC_POSTHOG_API_HOST,
|
||||||
flushAt: 1,
|
flushAt: 1,
|
||||||
flushInterval: 0,
|
flushInterval: 0,
|
||||||
});
|
});
|
5
packages/posthog/tsconfig.json
Normal file
5
packages/posthog/tsconfig.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"extends": "@rallly/tsconfig/next.json",
|
||||||
|
"include": ["**/*.ts", "**/*.tsx"],
|
||||||
|
"exclude": ["node_modules"],
|
||||||
|
}
|
10
yarn.lock
10
yarn.lock
|
@ -12718,17 +12718,17 @@ postgres-range@^1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863"
|
resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863"
|
||||||
integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==
|
integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==
|
||||||
|
|
||||||
posthog-js@^1.154.0:
|
posthog-js@^1.178.0:
|
||||||
version "1.181.0"
|
version "1.178.0"
|
||||||
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.181.0.tgz#b2119f6a27b27297dee9540bfcd33eddab06905c"
|
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.178.0.tgz#80005798e6c67d4d6565a5648939a0f017b0879b"
|
||||||
integrity sha512-bI+J+f4E8x4JwbGtG6LReQv1Xvss01F6cs7UDlvffHySpVhNq4ptkNjV88B92IVEsrCtNYhy/TjFnGxk6RN0Qw==
|
integrity sha512-ILD4flNh72d5dycc4ZouKORlaVr+pDzl5TlZr1JgP0NBAoduHjhE7XZYwk7zdYkry7u0qAIpfv2306zJCW2vGg==
|
||||||
dependencies:
|
dependencies:
|
||||||
core-js "^3.38.1"
|
core-js "^3.38.1"
|
||||||
fflate "^0.4.8"
|
fflate "^0.4.8"
|
||||||
preact "^10.19.3"
|
preact "^10.19.3"
|
||||||
web-vitals "^4.2.0"
|
web-vitals "^4.2.0"
|
||||||
|
|
||||||
posthog-node@^4.0.1:
|
posthog-node@^4.2.1:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-4.2.1.tgz#c9f077116bebd06dc65a3f9ae282d10db242c660"
|
resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-4.2.1.tgz#c9f077116bebd06dc65a3f9ae282d10db242c660"
|
||||||
integrity sha512-l+fsjYEkTik3m/G0pE7gMr4qBJP84LhK779oQm6MBzhBGpd4By4qieTW+4FUAlNCyzQTynn3Nhsa50c0IELSxQ==
|
integrity sha512-l+fsjYEkTik3m/G0pE7gMr4qBJP84LhK779oQm6MBzhBGpd4By4qieTW+4FUAlNCyzQTynn3Nhsa50c0IELSxQ==
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue