| |
| import type { User } from "@supabase/supabase-js"; |
|
|
| |
| const getSentryDsn = () => process.env.NEXT_PUBLIC_SENTRY_DSN; |
| const isSentryEnabled = () => false; |
|
|
| |
| const getPosthogKey = () => process.env.NEXT_PUBLIC_POSTHOG_KEY; |
| const getPosthogHost = () => process.env.NEXT_PUBLIC_POSTHOG_HOST || "https://app.posthog.com"; |
| const isPosthogEnabled = () => false; |
|
|
| |
| let sentryModule: any = null; |
| |
| let posthogClient: any = null; |
|
|
| |
| async function getSentry(): Promise<any> { |
| if (!isSentryEnabled()) return null; |
| if (!sentryModule) { |
| try { |
| |
| sentryModule = await import("@sentry/nextjs"); |
| } catch { |
| console.warn("Sentry not installed"); |
| return null; |
| } |
| } |
| return sentryModule; |
| } |
|
|
| |
| async function getPostHog(): Promise<any> { |
| if (!isPosthogEnabled()) return null; |
| if (!posthogClient) { |
| try { |
| |
| |
| const posthog = await import("posthog-js") as any; |
| posthogClient = posthog.default.init(getPosthogKey()!, { |
| api_host: getPosthogHost(), |
| capture_pageview: true, |
| capture_pageleave: true, |
| persistence: "localStorage", |
| loaded: (ph: { opt_out_capturing: () => void }) => { |
| if (process.env.NODE_ENV === "development") { |
| ph.opt_out_capturing(); |
| } |
| }, |
| }); |
| } catch { |
| console.warn("PostHog not installed"); |
| return null; |
| } |
| } |
| return posthogClient; |
| } |
|
|
| |
| export async function captureException(error: Error, context?: Record<string, unknown>): Promise<void> { |
| console.error("[Error]", error, context); |
| |
| const sentry = await getSentry(); |
| if (sentry) { |
| if (context) { |
| sentry.withScope((scope: any) => { |
| Object.entries(context).forEach(([key, value]) => { |
| scope.setExtra(key, value); |
| }); |
| scope.captureException(error); |
| }); |
| } else { |
| sentry.captureException(error); |
| } |
| } |
| } |
|
|
| export async function captureMessage(message: string, level: "info" | "warning" | "error" = "info", context?: Record<string, unknown>): Promise<void> { |
| console.log(`[${level.toUpperCase()}]`, message, context); |
| |
| const sentry = await getSentry(); |
| if (sentry) { |
| if (context) { |
| sentry.withScope((scope: any) => { |
| Object.entries(context).forEach(([key, value]) => { |
| scope.setExtra(key, value); |
| }); |
| scope.captureMessage(message, level); |
| }); |
| } else { |
| sentry.captureMessage(message, level); |
| } |
| } |
| } |
|
|
| |
| export async function identifyUser(user: User, organizationId?: string): Promise<void> { |
| const posthog = await getPostHog(); |
| if (posthog) { |
| posthog.identify(user.id, { |
| email: user.email, |
| organizationId, |
| }); |
| } |
| |
| const sentry = await getSentry(); |
| if (sentry) { |
| sentry.setUser({ |
| id: user.id, |
| email: user.email, |
| }); |
| if (organizationId) { |
| sentry.setTag("organizationId", organizationId); |
| } |
| } |
| } |
|
|
| export async function resetUser(): Promise<void> { |
| const posthog = await getPostHog(); |
| if (posthog) { |
| posthog.reset(); |
| } |
| |
| const sentry = await getSentry(); |
| if (sentry) { |
| sentry.setUser(null); |
| } |
| } |
|
|
| |
| export async function trackEvent( |
| eventName: string, |
| properties?: Record<string, unknown> |
| ): Promise<void> { |
| console.log("[Analytics]", eventName, properties); |
| |
| const posthog = await getPostHog(); |
| if (posthog) { |
| posthog.capture(eventName, properties); |
| } |
| } |
|
|
| |
| export const AnalyticsEvents = { |
| |
| USER_SIGNUP: "user_signup", |
| USER_LOGIN: "user_login", |
| USER_LOGOUT: "user_logout", |
| |
| |
| TENDER_UPLOADED: "tender_uploaded", |
| TENDER_PROCESSING_STARTED: "tender_processing_started", |
| TENDER_ANALYSIS_VIEWED: "tender_analysis_viewed", |
| TENDER_UNLOCKED: "tender_unlocked", |
| |
| |
| DRAFT_GENERATED: "draft_generated", |
| DRAFT_EXPORTED: "draft_exported", |
| DRAFT_DOWNLOADED: "draft_downloaded", |
| |
| |
| PAYMENT_INITIATED: "payment_initiated", |
| PAYMENT_COMPLETED: "payment_completed", |
| PAYMENT_FAILED: "payment_failed", |
| |
| |
| PROFILE_COMPLETED: "profile_completed", |
| PROFILE_UPDATED: "profile_updated", |
| |
| |
| EXTRACTION_FAILED: "extraction_failed", |
| DRAFT_GENERATION_FAILED: "draft_generation_failed", |
| UPLOAD_FAILED: "upload_failed", |
| } as const; |
|
|
| |
| export async function addBreadcrumb( |
| message: string, |
| category?: string, |
| data?: Record<string, unknown> |
| ): Promise<void> { |
| const sentry = await getSentry(); |
| if (sentry) { |
| sentry.addBreadcrumb({ |
| message, |
| category, |
| data, |
| level: "info", |
| }); |
| } |
| } |
|
|
| |
| export async function startSpanSafe( |
| name: string, |
| op: string |
| ): Promise<{ finish: () => void } | null> { |
| const sentry = await getSentry(); |
| if (!sentry) return null; |
|
|
| |
| if (typeof sentry.startSpan === "function") { |
| try { |
| sentry.startSpan({ name, op }, () => {}); |
| } catch { |
| |
| } |
| } |
|
|
| |
| return { finish: () => {} }; |
| } |
|
|
| |
| export async function initMonitoring(): Promise<void> { |
| if (isSentryEnabled()) { |
| await getSentry(); |
| console.log("[Monitoring] Sentry initialized"); |
| } |
| if (isPosthogEnabled()) { |
| await getPostHog(); |
| console.log("[Monitoring] PostHog initialized"); |
| } |
| } |
|
|