@od-oneapp/analytics 2026.2.1701 → 2026.2.2301-canary

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/{ai-YMnynb-t.mjs → ai-Co8hBoEj.mjs} +2 -2
  3. package/{ai-YMnynb-t.mjs.map → ai-Co8hBoEj.mjs.map} +1 -1
  4. package/{client-D339NFJS.mjs → client-B8gfgflr.mjs} +1 -1
  5. package/{client-D339NFJS.mjs.map → client-B8gfgflr.mjs.map} +1 -1
  6. package/{client-CeOLjbac.mjs → client-C35AzV71.mjs} +21 -6
  7. package/client-C35AzV71.mjs.map +1 -0
  8. package/{client-CcFTauAh.mjs → client-DDehaDSz.mjs} +1 -1
  9. package/{client-CcFTauAh.mjs.map → client-DDehaDSz.mjs.map} +1 -1
  10. package/{client-CTzJVFU5.mjs → client-DK8twEdp.mjs} +2 -2
  11. package/{client-CTzJVFU5.mjs.map → client-DK8twEdp.mjs.map} +1 -1
  12. package/client-next.d.mts +7 -7
  13. package/client-next.d.mts.map +1 -1
  14. package/client-next.mjs +1615 -31
  15. package/client-next.mjs.map +1 -1
  16. package/client.d.mts +9 -9
  17. package/client.mjs +8 -116
  18. package/client.mjs.map +1 -1
  19. package/{config-P6P5adJg.mjs → config-6Mwe7b2O.mjs} +1 -1
  20. package/{config-P6P5adJg.mjs.map → config-6Mwe7b2O.mjs.map} +1 -1
  21. package/{config-DPS6bSYo.d.mts → config-Ciu7O6n1.d.mts} +2 -2
  22. package/{config-DPS6bSYo.d.mts.map → config-Ciu7O6n1.d.mts.map} +1 -1
  23. package/{console-8bND3mMU.mjs → console-BpU88FNF.mjs} +2 -2
  24. package/console-BpU88FNF.mjs.map +1 -0
  25. package/core-DBLE5iTF.mjs +95 -0
  26. package/core-DBLE5iTF.mjs.map +1 -0
  27. package/{ecommerce-Cgu4wlux.mjs → ecommerce-DGG1FbiH.mjs} +2 -2
  28. package/{ecommerce-Cgu4wlux.mjs.map → ecommerce-DGG1FbiH.mjs.map} +1 -1
  29. package/{emitters-DldkVSPp.d.mts → emitters-BDSsleo_.d.mts} +2 -2
  30. package/{emitters-DldkVSPp.d.mts.map → emitters-BDSsleo_.d.mts.map} +1 -1
  31. package/{emitters-6-nKo8i-.mjs → emitters-BvEelkxS.mjs} +1 -1
  32. package/{emitters-6-nKo8i-.mjs.map → emitters-BvEelkxS.mjs.map} +1 -1
  33. package/{index-jPzXRn52.d.mts → index-BWhDEs8u.d.mts} +3 -3
  34. package/{index-jPzXRn52.d.mts.map → index-BWhDEs8u.d.mts.map} +1 -1
  35. package/{index-BkIWe--N.d.mts → index-Cp-N57Zb.d.mts} +2 -2
  36. package/{index-BkIWe--N.d.mts.map → index-Cp-N57Zb.d.mts.map} +1 -1
  37. package/{index-BfNWgfa5.d.mts → index-DTvdqV7H.d.mts} +14 -2
  38. package/{index-BfNWgfa5.d.mts.map → index-DTvdqV7H.d.mts.map} +1 -1
  39. package/{manager-DvRRjza6.d.mts → manager-OJpSKwqb.d.mts} +3 -2
  40. package/manager-OJpSKwqb.d.mts.map +1 -0
  41. package/module-DVAU7zKb.mjs +5850 -0
  42. package/module-DVAU7zKb.mjs.map +1 -0
  43. package/package.json +42 -37
  44. package/{posthog-bootstrap-DWxFrxlt.d.mts → posthog-bootstrap-Bu1BfhVv.d.mts} +3 -3
  45. package/{posthog-bootstrap-DWxFrxlt.d.mts.map → posthog-bootstrap-Bu1BfhVv.d.mts.map} +1 -1
  46. package/{posthog-bootstrap-CYfIy_WS.mjs → posthog-bootstrap-DkPdn-hA.mjs} +81 -46
  47. package/posthog-bootstrap-DkPdn-hA.mjs.map +1 -0
  48. package/providers-http-client.d.mts +1 -1
  49. package/providers-http-client.d.mts.map +1 -1
  50. package/providers-http-client.mjs +35 -7
  51. package/providers-http-client.mjs.map +1 -1
  52. package/providers-http-server.d.mts +1 -1
  53. package/providers-http-server.d.mts.map +1 -1
  54. package/providers-http-server.mjs +19 -3
  55. package/providers-http-server.mjs.map +1 -1
  56. package/providers-http.d.mts +9 -1
  57. package/providers-http.d.mts.map +1 -1
  58. package/server-edge.d.mts +3 -3
  59. package/server-edge.mjs +4 -4
  60. package/server-edge.mjs.map +1 -1
  61. package/server-next.d.mts +9 -9
  62. package/server-next.mjs +5 -5
  63. package/server.d.mts +9 -9
  64. package/server.mjs +5 -5
  65. package/{service-Duqnlppl.mjs → service-NuHnv30x.mjs} +51 -119
  66. package/service-NuHnv30x.mjs.map +1 -0
  67. package/shared.d.mts +4 -4
  68. package/shared.mjs +3 -3
  69. package/{types-CBvxUEaF.d.mts → types-DEcTnnFe.d.mts} +1 -1
  70. package/{types-CBvxUEaF.d.mts.map → types-DEcTnnFe.d.mts.map} +1 -1
  71. package/{types-BxBnNQ0V.d.mts → types-cMMfHIpi.d.mts} +1 -1
  72. package/{types-BxBnNQ0V.d.mts.map → types-cMMfHIpi.d.mts.map} +1 -1
  73. package/types.d.mts +3 -3
  74. package/{vercel-types-lwakUfoI.d.mts → vercel-types-oM7Sn385.d.mts} +1 -1
  75. package/{vercel-types-lwakUfoI.d.mts.map → vercel-types-oM7Sn385.d.mts.map} +1 -1
  76. package/client-CeOLjbac.mjs.map +0 -1
  77. package/console-8bND3mMU.mjs.map +0 -1
  78. package/manager-DvRRjza6.d.mts.map +0 -1
  79. package/posthog-bootstrap-CYfIy_WS.mjs.map +0 -1
  80. package/service-Duqnlppl.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client-next.mjs","names":["globalAnalytics"],"sources":["../src/client/next/manager.ts","../src/client/next/hooks.ts","../src/client/next/components.tsx","../src/client-next.ts"],"sourcesContent":["/**\n * @fileoverview Next.js Client Analytics Manager\n *\n * Next.js client analytics manager with truly dynamic provider loading.\n * Only imports providers that are actually configured to avoid webpack\n * bundling unused dependencies, reducing bundle size.\n *\n * **Features**:\n * - Dynamic provider loading (only configured providers are bundled)\n * - Code splitting via webpack chunks\n * - Lazy initialization support\n * - Next.js App Router optimized\n *\n * @module @od-oneapp/analytics/client/next/manager\n */\n\n// Simple console fallback - observability integration can be added later\nimport { createAnalyticsManager } from '../../shared/utils/manager';\n\nimport type { AnalyticsConfig, AnalyticsManager, ProviderRegistry } from '../../shared/types/types';\nconst logWarn = (_message: string, _context?: any) => {\n // No-op to avoid console warnings in production\n // TODO: Add proper error logging via observability package\n};\n\n/**\n * Create a Next.js client analytics instance with runtime provider loading\n * Only imports providers that are actually configured to avoid webpack bundling unused dependencies\n *\n * @example\n * ```typescript\n * const analytics = await createNextJSClientAnalytics({\n * providers: { posthog: { apiKey: process.env.NEXT_PUBLIC_POSTHOG_KEY! } },\n * });\n * await analytics.track('Dashboard Viewed');\n * ```\n */\nexport async function createNextJSClientAnalytics(\n config: AnalyticsConfig,\n): Promise<AnalyticsManager> {\n const CLIENT_PROVIDERS: ProviderRegistry = {};\n\n // Get configured providers\n const configuredProviders = Object.keys(config.providers);\n\n // Only import configured providers using truly dynamic imports\n const providerPromises = configuredProviders.map(async providerName => {\n switch (providerName) {\n case 'console': {\n const module = await import(\n /* webpackChunkName: \"analytics-console\" */ '../../providers/console/client'\n );\n CLIENT_PROVIDERS.console = config => new module.ConsoleProvider(config);\n break;\n }\n case 'posthog': {\n const module = await import(\n /* webpackChunkName: \"analytics-posthog\" */ '../../providers/posthog/client'\n );\n CLIENT_PROVIDERS.posthog = config => new module.PostHogClientProvider(config);\n break;\n }\n case 'segment': {\n const module = await import(\n /* webpackChunkName: \"analytics-segment\" */ '../../providers/segment/client'\n );\n CLIENT_PROVIDERS.segment = config => new module.SegmentClientProvider(config);\n break;\n }\n case 'vercel': {\n const module = await import(\n /* webpackChunkName: \"analytics-vercel\" */ '../../providers/vercel/client'\n );\n CLIENT_PROVIDERS.vercel = config => new module.VercelClientProvider(config);\n break;\n }\n default:\n // Skip unknown providers\n logWarn('Unknown analytics provider:', { providerName });\n break;\n }\n });\n\n // Wait for all configured providers to load\n await Promise.all(providerPromises);\n\n const manager = createAnalyticsManager(config, CLIENT_PROVIDERS);\n await manager.initialize();\n return manager;\n}\n\n/**\n * Create a Next.js client analytics instance without initializing\n *\n * @example\n * ```typescript\n * const analytics = await createNextJSClientAnalyticsUninitialized(config);\n * // run setup before first event\n * await analytics.initialize();\n * ```\n */\nexport async function createNextJSClientAnalyticsUninitialized(\n config: AnalyticsConfig,\n): Promise<AnalyticsManager> {\n const CLIENT_PROVIDERS: ProviderRegistry = {};\n\n // Get configured providers\n const configuredProviders = Object.keys(config.providers);\n\n // Dynamically import only configured providers\n for (const providerName of configuredProviders) {\n switch (providerName) {\n case 'console': {\n const { ConsoleProvider } = await import('../../providers/console/client');\n CLIENT_PROVIDERS.console = config => new ConsoleProvider(config);\n break;\n }\n case 'posthog': {\n const { PostHogClientProvider } = await import('../../providers/posthog/client');\n CLIENT_PROVIDERS.posthog = config => new PostHogClientProvider(config);\n break;\n }\n case 'segment': {\n const { SegmentClientProvider } = await import('../../providers/segment/client');\n CLIENT_PROVIDERS.segment = config => new SegmentClientProvider(config);\n break;\n }\n case 'vercel': {\n const { VercelClientProvider } = await import('../../providers/vercel/client');\n CLIENT_PROVIDERS.vercel = config => new VercelClientProvider(config);\n break;\n }\n default:\n // Skip unknown providers\n logWarn('Unknown analytics provider:', { providerName });\n break;\n }\n }\n\n return createAnalyticsManager(config, CLIENT_PROVIDERS);\n}\n","/**\n * @fileoverview Next.js Client Hooks for Analytics\n *\n * React hooks for integrating analytics into Next.js applications.\n * Provides hooks for accessing analytics instances, tracking events,\n * and automatic page view tracking.\n *\n * **Hooks**:\n * - `useAnalytics()`: Get or create analytics instance\n * - `usePageTracking()`: Automatic page view tracking in App Router\n * - `useTrackEvent()`: Hook for tracking events\n * - `useIdentifyUser()`: Hook for user identification\n * - `resetAnalytics()`: Utility to reset analytics (useful for testing)\n *\n * **Note**: These hooks use Next.js navigation hooks. For framework-agnostic hooks,\n * use the base hooks from './hooks' or './manager'.\n *\n * @module @od-oneapp/analytics/client/next/hooks\n */\n\n'use client';\n\n// Note: These are Next.js hooks required for App Router integration\n// Client components are already Next.js-specific, so this is acceptable\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { useParams, usePathname, useSearchParams } from 'next/navigation';\n// Type-only imports for Next.js types (compile-time only, no runtime dependency)\n\nimport { createNextJSClientAnalytics } from './manager';\n\nimport type { AnalyticsConfig, AnalyticsManager, TrackingOptions } from '../../shared/types/types';\n\n// Global analytics instance\nlet globalAnalytics: AnalyticsManager | null = null;\n\n/**\n * Hook to get or create analytics instance.\n *\n * @remarks\n * Returns the global analytics instance, creating it if it doesn't exist\n * and config is provided. Returns null if analytics hasn't been initialized.\n *\n * @param config - Optional analytics configuration (only used on first call)\n * @returns Analytics manager instance or null if not initialized\n *\n * @example\n * ```tsx\n * const analytics = useAnalytics(config);\n * useEffect(() => {\n * if (analytics) {\n * analytics.track('ClientReady');\n * }\n * }, [analytics]);\n * ```\n */\nexport function useAnalytics(config?: AnalyticsConfig): AnalyticsManager | null {\n const [analytics, setAnalytics] = useState<AnalyticsManager | null>(null);\n\n useEffect(() => {\n if (!globalAnalytics && config) {\n const initAnalytics = async () => {\n try {\n // Note: Client-side observability handled by manager\n\n const instance = await createNextJSClientAnalytics(config);\n globalAnalytics = instance;\n setAnalytics(instance);\n } catch {\n // Failed to initialize analytics - silently continue\n // TODO: Add proper error logging via observability package\n }\n };\n void initAnalytics();\n } else if (globalAnalytics && analytics !== globalAnalytics) {\n // Use setTimeout to avoid synchronous setState in effect\n setTimeout(() => {\n setAnalytics(globalAnalytics);\n }, 0);\n }\n }, [config]);\n\n return analytics;\n}\n\n/**\n * Hook for automatic page view tracking in App Router.\n *\n * @remarks\n * Automatically tracks page views when the pathname, search params, or route\n * params change. Prevents duplicate tracking for the same page.\n *\n * @param options - Page tracking options\n * @param options.trackSearch - Whether to include search params in tracking (default: false)\n * @param options.trackParams - Whether to include route params in tracking (default: false)\n * @param options.properties - Additional properties to include in page events\n * @param options.skip - Whether to skip tracking (default: false)\n *\n * @example\n * ```tsx\n * usePageTracking({ trackSearch: true, trackParams: true });\n * ```\n */\nexport function usePageTracking(options?: {\n trackSearch?: boolean;\n trackParams?: boolean;\n properties?: Record<string, any>;\n skip?: boolean;\n}) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const params = useParams();\n const tracked = useRef<string>('');\n\n useEffect(() => {\n if (options?.skip || !globalAnalytics) return;\n\n // Create unique key for this page view\n const searchString = options?.trackSearch ? searchParams.toString() : '';\n const pageKey = `${pathname}${searchString}`;\n\n // Avoid duplicate tracking\n if (tracked.current === pageKey) return;\n tracked.current = pageKey;\n\n // Build properties\n const properties: Record<string, any> = {\n ...options?.properties,\n url: window.location.href,\n path: pathname,\n referrer: document.referrer,\n title: document.title,\n };\n\n if (options?.trackSearch) {\n properties.search = searchString;\n properties.search_params = Object.fromEntries(searchParams.entries());\n }\n\n if (options?.trackParams && params) {\n properties.route_params = params;\n }\n\n // Track page view\n void globalAnalytics.page(pathname, properties);\n }, [\n pathname,\n searchParams,\n params,\n options?.skip,\n options?.trackSearch,\n options?.trackParams,\n options?.properties,\n ]);\n}\n\n/**\n * Hook for tracking events.\n *\n * @remarks\n * Returns a callback function for tracking events. The callback is stable\n * across renders and can be safely used in event handlers.\n *\n * @returns Callback function for tracking events\n *\n * @example\n * ```tsx\n * const track = useTrackEvent();\n * track('CTA Clicked', { label: 'Request Demo' });\n * ```\n */\nexport function useTrackEvent() {\n return useCallback((event: string, properties?: any, options?: TrackingOptions) => {\n if (!globalAnalytics) return;\n void globalAnalytics.track(event, properties, options);\n }, []);\n}\n\n/**\n * Hook for user identification.\n *\n * @remarks\n * Returns a callback function for identifying users. The callback is stable\n * across renders and can be safely used in event handlers.\n *\n * @returns Callback function for identifying users\n *\n * @example\n * ```tsx\n * const identify = useIdentifyUser();\n * identify(user.id, { plan: user.plan });\n * ```\n */\nexport function useIdentifyUser() {\n return useCallback((userId: string, traits?: any, options?: TrackingOptions) => {\n if (!globalAnalytics) return;\n void globalAnalytics.identify(userId, traits, options);\n }, []);\n}\n\n/**\n * Utility to reset analytics (useful for testing).\n *\n * @remarks\n * Clears the global analytics instance. Useful in test environments to\n * ensure clean state between tests.\n *\n * @example\n * ```typescript\n * beforeEach(() => {\n * resetAnalytics();\n * });\n * ```\n */\nexport function resetAnalytics() {\n globalAnalytics = null;\n}\n","/**\n * @fileoverview Next.js Client Components for Analytics\n *\n * React components for integrating analytics into Next.js applications.\n * Provides provider components, tracked UI elements, and higher-order\n * components for automatic event tracking.\n *\n * **Components**:\n * - `AnalyticsProvider`: Provider component for App Router\n * - `TrackedButton`: Button component with automatic click tracking\n * - `TrackedLink`: Link component with automatic click tracking\n * - `withViewTracking`: HOC for tracking component views\n *\n * **Note**: This file uses Next.js hooks. For framework-agnostic components,\n * use the base components or accept navigation functions as parameters.\n *\n * @module @od-oneapp/analytics/client/next/components\n */\n\n'use client';\n\nimport { useCallback, useEffect, useRef } from 'react';\n\nimport type { Route } from 'next';\n\nimport { createClientObservability } from '@od-oneapp/observability/client/next';\nimport { useRouter } from 'next/navigation';\n\nimport { usePageTracking, useTrackEvent } from './hooks';\nimport { createNextJSClientAnalytics } from './manager';\n\nimport type { AnalyticsConfig, AnalyticsManager, Properties } from '../../shared/types/types';\nimport type { ObservabilityClient } from '@od-oneapp/observability/client/next';\n\n// Global analytics instance\nlet globalAnalytics: AnalyticsManager | null = null;\n\n// Global logger instance (from @od-oneapp/observability)\n// Using minimal interface for optional fallback error logging\n\nlet logger: ObservabilityClient | null = null;\n\n/**\n * Analytics provider component for App Router.\n *\n * @remarks\n * Wraps your application and provides analytics context to all child components.\n * Automatically initializes analytics and optionally tracks page views.\n *\n * @param props - Component props\n * @param props.children - React children to wrap\n * @param props.config - Analytics configuration\n * @param props.autoPageTracking - Whether to automatically track page views (default: true)\n * @param props.pageTrackingOptions - Options for page tracking\n *\n * @example\n * ```tsx\n * export default function RootLayout({ children }) {\n * return (\n * <AnalyticsProvider\n * config={{\n * providers: {\n * http: { options: { endpoint: process.env.NEXT_PUBLIC_ANALYTICS_ENDPOINT! } }\n * }\n * }}\n * autoPageTracking={true}\n * >\n * {children}\n * </AnalyticsProvider>\n * );\n * }\n * ```\n */\nexport function AnalyticsProvider({\n autoPageTracking = true,\n children,\n config,\n pageTrackingOptions,\n}: {\n children: React.ReactNode;\n config: AnalyticsConfig;\n autoPageTracking?: boolean;\n pageTrackingOptions?: Parameters<typeof usePageTracking>[0];\n}) {\n // Initialize analytics\n useEffect(() => {\n if (!globalAnalytics) {\n const initAnalytics = async () => {\n try {\n // Initialize logger if not already initialized\n logger ??= await createClientObservability();\n\n const instance = await createNextJSClientAnalytics(config);\n globalAnalytics = instance;\n } catch (error) {\n if (logger) {\n logger.captureException(error, {\n message: 'Failed to initialize analytics',\n });\n }\n }\n };\n void initAnalytics();\n }\n }, [config]);\n\n // Auto page tracking\n usePageTracking(autoPageTracking ? pageTrackingOptions : { skip: true });\n\n return children as React.ReactElement;\n}\n\n/**\n * Button component with automatic click tracking.\n *\n * @remarks\n * Wraps a standard button element and automatically tracks click events\n * when the button is clicked.\n *\n * @param props - Button props plus tracking props\n * @param props.eventName - Name of the event to track\n * @param props.properties - Additional properties to include in the event\n * @param props.onClick - Optional click handler (tracking happens before this)\n *\n * @example\n * ```tsx\n * <TrackedButton\n * eventName=\"Sign Up Clicked\"\n * properties={{ location: 'header', variant: 'primary' }}\n * onClick={() => router.push('/signup')}\n * >\n * Sign Up\n * </TrackedButton>\n * ```\n */\nexport function TrackedButton({\n children,\n eventName,\n onClick,\n properties,\n ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement> & {\n eventName: string;\n properties?: Properties;\n}) {\n const track = useTrackEvent();\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n track(eventName, properties);\n onClick?.(e);\n },\n [track, eventName, properties, onClick],\n );\n\n return (\n <button type=\"button\" {...props} onClick={handleClick}>\n {children}\n </button>\n );\n}\n\n/**\n * Link component with automatic click tracking.\n *\n * @remarks\n * Wraps a standard anchor element and automatically tracks click events\n * when the link is clicked. Also handles internal navigation for Next.js.\n *\n * @param props - Anchor props plus tracking props\n * @param props.eventName - Name of the event to track\n * @param props.properties - Additional properties to include in the event\n * @param props.href - Link URL\n * @param props.onClick - Optional click handler (tracking happens before this)\n *\n * @example\n * ```tsx\n * <TrackedLink\n * href=\"/products\"\n * eventName=\"Product Link Clicked\"\n * properties={{ linkText: 'View Products' }}\n * >\n * View Products\n * </TrackedLink>\n * ```\n */\nexport function TrackedLink({\n children,\n eventName,\n href,\n onClick,\n properties,\n ...props\n}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {\n eventName: string;\n properties?: Properties;\n}) {\n const track = useTrackEvent();\n const router = useRouter();\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Track the event\n const enhancedProperties = {\n ...properties,\n href,\n link_text: typeof children === 'string' ? children : undefined,\n };\n track(eventName, enhancedProperties);\n\n // Handle navigation\n if (onClick) {\n onClick(e);\n } else if (href && !props.target && href.startsWith('/')) {\n // Internal navigation\n e.preventDefault();\n router.push(href as Route);\n }\n },\n [track, eventName, properties, href, onClick, router, children, props.target],\n );\n\n return (\n <a {...props} href={href} onClick={handleClick}>\n {children}\n </a>\n );\n}\n\n/**\n * Higher-order component for tracking component views.\n *\n * @remarks\n * Wraps a component and automatically tracks a view event when the component\n * is first rendered. Useful for tracking page sections or feature usage.\n *\n * @param Component - The component to wrap\n * @param eventName - Name of the event to track\n * @param getProperties - Optional function to extract properties from component props\n * @returns Wrapped component with automatic view tracking\n *\n * @example\n * ```tsx\n * const TrackedDashboard = withViewTracking(\n * Dashboard,\n * 'Dashboard Viewed',\n * (props) => ({ userId: props.userId, plan: props.plan })\n * );\n * ```\n */\nexport function withViewTracking<P extends object>(\n Component: React.ComponentType<P>,\n eventName: string,\n getProperties?: (props: P) => Properties,\n) {\n return function TrackedComponent(props: P) {\n const track = useTrackEvent();\n const tracked = useRef(false);\n\n useEffect(() => {\n if (!tracked.current) {\n tracked.current = true;\n const properties = getProperties ? getProperties(props) : {};\n track(eventName, properties);\n }\n }, [track, props]);\n\n return <Component {...props} />;\n };\n}\n","/**\n * @fileoverview Next.js client exports\n *\n * This module provides Next.js-specific client-side analytics functionality.\n * It exports:\n *\n * - **Analytics Managers**: `createNextJSClientAnalytics()`, `createNextJSClientAnalyticsUninitialized()`\n * - **React Hooks**: `useAnalytics()`, `usePageTracking()`, `useTrackEvent()`, `useIdentifyUser()`\n * - **React Components**: `AnalyticsProvider`, `TrackedButton`, `TrackedLink`, `withViewTracking()`\n * - **Emitters**: Type-safe event tracking functions\n * - **Ecommerce Emitters**: Comprehensive ecommerce event tracking\n * - **AI Emitters**: AI product analytics tracking\n * - **Configuration**: Client-safe configuration utilities\n * - **PostHog Utilities**: Bootstrap data and cookie utilities\n *\n * **Usage**: Import from `@od-oneapp/analytics/client/next` for Next.js client components.\n *\n * @module @od-oneapp/analytics/client/next\n */\n\n'use client';\n\n// Export Next.js specific analytics manager\nexport {\n createNextJSClientAnalytics,\n createNextJSClientAnalyticsUninitialized,\n} from './client/next/manager';\n\n// Export Next.js hooks\nexport {\n resetAnalytics,\n useAnalytics,\n useIdentifyUser,\n usePageTracking,\n useTrackEvent,\n} from './client/next/hooks';\n\n// Export Next.js components\nexport {\n AnalyticsProvider,\n TrackedButton,\n TrackedLink,\n withViewTracking,\n} from './client/next/components';\n\n// Export all emitters - these are the preferred way to track events\nexport {\n // Emitter utilities\n ContextBuilder,\n EventBatch,\n PayloadBuilder,\n alias,\n createAnonymousSession,\n createUserSession,\n // Ecommerce emitters namespace\n ecommerce,\n group,\n // Core Segment.io spec emitters\n identify,\n isAliasPayload,\n isGroupPayload,\n isIdentifyPayload,\n isPagePayload,\n // Type guards\n isTrackPayload,\n page,\n screen,\n track,\n withMetadata,\n withUTM,\n} from './shared/emitters';\n\n// Export adapter utilities\nexport {\n createEmitterProcessor,\n // Emitter processing utilities\n processEmitterPayload,\n trackEcommerceEvent,\n} from './shared/utils/emitter-adapter';\n\n// Export client-safe configuration utilities\nexport {\n PROVIDER_REQUIREMENTS,\n createConfigBuilder,\n getAnalyticsConfig,\n validateConfig,\n} from './shared/utils/config-client';\n\n// Validation utilities removed - validation should happen on the server side only\n// This follows the four-file export pattern to avoid importing server-only dependencies\n\n// Export PostHog utilities\nexport {\n createBootstrapData,\n createMinimalBootstrapData,\n generateDistinctId,\n getDistinctIdFromCookies,\n} from './shared/utils/posthog-bootstrap';\n\n// Export types\nexport type * from './types';\n"],"mappings":"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"}
1
+ {"version":3,"file":"client-next.mjs","names":["env","env","safeEnv","safeEnv","env","sentryEnv","betterStackEnv"],"sources":["../src/client/next/manager.ts","../src/client/next/state.ts","../src/client/next/hooks.ts","../../observability/env.ts","../../observability/src/core/manager.ts","../../observability/src/factory/builder.ts","../../observability/src/plugins/betterstack/env.ts","../../observability/src/plugins/betterstack/plugin.ts","../../observability/src/shared.ts","../../observability/src/plugins/console/index.ts","../../observability/src/plugins/sentry/env.ts","../../observability/src/plugins/sentry/plugin.ts","../../observability/src/client-next.ts","../src/client/next/components.tsx","../src/client-next.ts"],"sourcesContent":["/**\n * @fileoverview Next.js Client Analytics Manager\n *\n * Next.js client analytics manager with truly dynamic provider loading.\n * Only imports providers that are actually configured to avoid webpack\n * bundling unused dependencies, reducing bundle size.\n *\n * **Features**:\n * - Dynamic provider loading (only configured providers are bundled)\n * - Code splitting via webpack chunks\n * - Lazy initialization support\n * - Next.js App Router optimized\n *\n * @module @od-oneapp/analytics/client/next/manager\n */\n\nimport { logWarn as reportUnknownProvider } from '@od-oneapp/shared/logger';\n\nimport { createAnalyticsManager } from '../../shared/utils/manager';\n\nimport type { AnalyticsConfig, AnalyticsManager, ProviderRegistry } from '../../shared/types/types';\n\n/**\n * Create a Next.js client analytics instance with runtime provider loading\n * Only imports providers that are actually configured to avoid webpack bundling unused dependencies\n *\n * @example\n * ```typescript\n * const analytics = await createNextJSClientAnalytics({\n * providers: { posthog: { apiKey: process.env.NEXT_PUBLIC_POSTHOG_KEY! } },\n * });\n * await analytics.track('Dashboard Viewed');\n * ```\n */\nexport async function createNextJSClientAnalytics(\n config: AnalyticsConfig,\n): Promise<AnalyticsManager> {\n const CLIENT_PROVIDERS: ProviderRegistry = {};\n\n // Get configured providers\n const configuredProviders = Object.keys(config.providers);\n\n // Only import configured providers using truly dynamic imports\n const providerPromises = configuredProviders.map(async providerName => {\n switch (providerName) {\n case 'console': {\n const module = await import(\n /* webpackChunkName: \"analytics-console\" */ '../../providers/console/client'\n );\n CLIENT_PROVIDERS.console = config => new module.ConsoleProvider(config);\n break;\n }\n case 'posthog': {\n const module = await import(\n /* webpackChunkName: \"analytics-posthog\" */ '../../providers/posthog/client'\n );\n CLIENT_PROVIDERS.posthog = config => new module.PostHogClientProvider(config);\n break;\n }\n case 'segment': {\n const module = await import(\n /* webpackChunkName: \"analytics-segment\" */ '../../providers/segment/client'\n );\n CLIENT_PROVIDERS.segment = config => new module.SegmentClientProvider(config);\n break;\n }\n case 'http': {\n const module = await import(\n /* webpackChunkName: \"analytics-http\" */ '../../providers/http/client'\n );\n CLIENT_PROVIDERS.http = config => new module.HttpClientProvider(config);\n break;\n }\n case 'vercel': {\n const module = await import(\n /* webpackChunkName: \"analytics-vercel\" */ '../../providers/vercel/client'\n );\n CLIENT_PROVIDERS.vercel = config => new module.VercelClientProvider(config);\n break;\n }\n default:\n // Skip unknown providers\n reportUnknownProvider('Unknown analytics provider:', { providerName });\n break;\n }\n });\n\n // Wait for all configured providers to load\n await Promise.all(providerPromises);\n\n const manager = createAnalyticsManager(config, CLIENT_PROVIDERS);\n await manager.initialize();\n return manager;\n}\n\n/**\n * Create a Next.js client analytics instance without initializing\n *\n * @example\n * ```typescript\n * const analytics = await createNextJSClientAnalyticsUninitialized(config);\n * // run setup before first event\n * await analytics.initialize();\n * ```\n */\nexport async function createNextJSClientAnalyticsUninitialized(\n config: AnalyticsConfig,\n): Promise<AnalyticsManager> {\n const CLIENT_PROVIDERS: ProviderRegistry = {};\n\n // Get configured providers\n const configuredProviders = Object.keys(config.providers);\n\n // Dynamically import only configured providers\n for (const providerName of configuredProviders) {\n switch (providerName) {\n case 'console': {\n const { ConsoleProvider } = await import('../../providers/console/client');\n CLIENT_PROVIDERS.console = config => new ConsoleProvider(config);\n break;\n }\n case 'posthog': {\n const { PostHogClientProvider } = await import('../../providers/posthog/client');\n CLIENT_PROVIDERS.posthog = config => new PostHogClientProvider(config);\n break;\n }\n case 'segment': {\n const { SegmentClientProvider } = await import('../../providers/segment/client');\n CLIENT_PROVIDERS.segment = config => new SegmentClientProvider(config);\n break;\n }\n case 'http': {\n const { HttpClientProvider } = await import('../../providers/http/client');\n CLIENT_PROVIDERS.http = config => new HttpClientProvider(config);\n break;\n }\n case 'vercel': {\n const { VercelClientProvider } = await import('../../providers/vercel/client');\n CLIENT_PROVIDERS.vercel = config => new VercelClientProvider(config);\n break;\n }\n default:\n // Skip unknown providers\n reportUnknownProvider('Unknown analytics provider:', { providerName });\n break;\n }\n }\n\n return createAnalyticsManager(config, CLIENT_PROVIDERS);\n}\n","import type { AnalyticsManager } from '../../shared/types/types';\n\nlet globalAnalytics: AnalyticsManager | null = null;\n\nexport function getGlobalAnalytics(): AnalyticsManager | null {\n return globalAnalytics;\n}\n\nexport function setGlobalAnalytics(analytics: AnalyticsManager | null): void {\n globalAnalytics = analytics;\n}\n","/**\n * @fileoverview Next.js Client Hooks for Analytics\n *\n * React hooks for integrating analytics into Next.js applications.\n * Provides hooks for accessing analytics instances, tracking events,\n * and automatic page view tracking.\n *\n * **Hooks**:\n * - `useAnalytics()`: Get or create analytics instance\n * - `usePageTracking()`: Automatic page view tracking in App Router\n * - `useTrackEvent()`: Hook for tracking events\n * - `useIdentifyUser()`: Hook for user identification\n * - `resetAnalytics()`: Utility to reset analytics (useful for testing)\n *\n * **Note**: These hooks use Next.js navigation hooks. For framework-agnostic hooks,\n * use the base hooks from './hooks' or './manager'.\n *\n * @module @od-oneapp/analytics/client/next/hooks\n */\n\n'use client';\n\n// Note: These are Next.js hooks required for App Router integration\n// Client components are already Next.js-specific, so this is acceptable\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { logError } from '@od-oneapp/shared/logger';\nimport { useParams, usePathname, useSearchParams } from 'next/navigation';\n// Type-only imports for Next.js types (compile-time only, no runtime dependency)\n\nimport { createNextJSClientAnalytics } from './manager';\nimport { getGlobalAnalytics, setGlobalAnalytics } from './state';\n\nimport type { AnalyticsConfig, AnalyticsManager, TrackingOptions } from '../../shared/types/types';\n\n/**\n * Hook to get or create analytics instance.\n *\n * @remarks\n * Returns the global analytics instance, creating it if it doesn't exist\n * and config is provided. Returns null if analytics hasn't been initialized.\n *\n * @param config - Optional analytics configuration (only used on first call)\n * @returns Analytics manager instance or null if not initialized\n *\n * @example\n * ```tsx\n * const analytics = useAnalytics(config);\n * useEffect(() => {\n * if (analytics) {\n * analytics.track('ClientReady');\n * }\n * }, [analytics]);\n * ```\n */\nexport function useAnalytics(config?: AnalyticsConfig): AnalyticsManager | null {\n const [analytics, setAnalytics] = useState<AnalyticsManager | null>(null);\n\n useEffect(() => {\n const currentAnalytics = getGlobalAnalytics();\n\n if (!currentAnalytics && config) {\n const initAnalytics = async () => {\n try {\n const instance = await createNextJSClientAnalytics(config);\n setGlobalAnalytics(instance);\n setAnalytics(instance);\n } catch (error) {\n logError('Failed to initialize Next.js analytics client', {\n error: error instanceof Error ? error.message : String(error),\n configProviders: Object.keys(config.providers),\n });\n }\n };\n void initAnalytics();\n } else if (currentAnalytics && analytics !== currentAnalytics) {\n // Use setTimeout to avoid synchronous setState in effect\n setTimeout(() => {\n setAnalytics(currentAnalytics);\n }, 0);\n }\n }, [analytics, config]);\n\n return analytics;\n}\n\n/**\n * Hook for automatic page view tracking in App Router.\n *\n * @remarks\n * Automatically tracks page views when the pathname, search params, or route\n * params change. Prevents duplicate tracking for the same page.\n *\n * @param options - Page tracking options\n * @param options.trackSearch - Whether to include search params in tracking (default: false)\n * @param options.trackParams - Whether to include route params in tracking (default: false)\n * @param options.properties - Additional properties to include in page events\n * @param options.skip - Whether to skip tracking (default: false)\n *\n * @example\n * ```tsx\n * usePageTracking({ trackSearch: true, trackParams: true });\n * ```\n */\nexport function usePageTracking(options?: {\n trackSearch?: boolean;\n trackParams?: boolean;\n properties?: Record<string, any>;\n skip?: boolean;\n}) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const params = useParams();\n const tracked = useRef<string>('');\n\n useEffect(() => {\n const analyticsInstance = getGlobalAnalytics();\n if (options?.skip || !analyticsInstance) return;\n\n // Create unique key for this page view\n const searchString = options?.trackSearch ? searchParams.toString() : '';\n const pageKey = `${pathname}${searchString}`;\n\n // Avoid duplicate tracking\n if (tracked.current === pageKey) return;\n tracked.current = pageKey;\n\n // Build properties\n const properties: Record<string, any> = {\n ...options?.properties,\n url: window.location.href,\n path: pathname,\n referrer: document.referrer,\n title: document.title,\n };\n\n if (options?.trackSearch) {\n properties.search = searchString;\n properties.search_params = Object.fromEntries(searchParams.entries());\n }\n\n if (options?.trackParams && params) {\n properties.route_params = params;\n }\n\n // Track page view\n void analyticsInstance.page(pathname, properties);\n }, [\n pathname,\n searchParams,\n params,\n options?.skip,\n options?.trackSearch,\n options?.trackParams,\n options?.properties,\n ]);\n}\n\n/**\n * Hook for tracking events.\n *\n * @remarks\n * Returns a callback function for tracking events. The callback is stable\n * across renders and can be safely used in event handlers.\n *\n * @returns Callback function for tracking events\n *\n * @example\n * ```tsx\n * const track = useTrackEvent();\n * track('CTA Clicked', { label: 'Request Demo' });\n * ```\n */\nexport function useTrackEvent() {\n return useCallback((event: string, properties?: any, options?: TrackingOptions) => {\n const analyticsInstance = getGlobalAnalytics();\n if (!analyticsInstance) return;\n void analyticsInstance.track(event, properties, options);\n }, []);\n}\n\n/**\n * Hook for user identification.\n *\n * @remarks\n * Returns a callback function for identifying users. The callback is stable\n * across renders and can be safely used in event handlers.\n *\n * @returns Callback function for identifying users\n *\n * @example\n * ```tsx\n * const identify = useIdentifyUser();\n * identify(user.id, { plan: user.plan });\n * ```\n */\nexport function useIdentifyUser() {\n return useCallback((userId: string, traits?: any, options?: TrackingOptions) => {\n const analyticsInstance = getGlobalAnalytics();\n if (!analyticsInstance) return;\n void analyticsInstance.identify(userId, traits, options);\n }, []);\n}\n\n/**\n * Utility to reset analytics (useful for testing).\n *\n * @remarks\n * Clears the global analytics instance. Useful in test environments to\n * ensure clean state between tests.\n *\n * @example\n * ```typescript\n * beforeEach(() => {\n * resetAnalytics();\n * });\n * ```\n */\nexport function resetAnalytics() {\n setGlobalAnalytics(null);\n}\n","/**\n * @fileoverview Core environment configuration for the observability package\n * Core environment configuration for the observability package\n * Provider-specific configurations are handled by their respective plugins\n */\n\nimport { logWarn } from '@od-oneapp/shared/logger';\nimport { createEnv } from '@t3-oss/env-core';\nimport { z } from 'zod/v4';\n\n// Create validated env object\nexport const env = createEnv({\n server: {\n // Core observability config only - providers handle their own\n },\n clientPrefix: 'NEXT_PUBLIC_',\n client: {\n // Core configuration available on both client and server\n NEXT_PUBLIC_NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),\n NEXT_PUBLIC_OBSERVABILITY_DEBUG: z\n .string()\n .optional()\n .transform(val => val === 'true')\n .default(false),\n NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED: z\n .string()\n .optional()\n .transform(val => (val === 'true' ? true : val === 'false' ? false : undefined)),\n },\n runtimeEnv: process.env,\n emptyStringAsUndefined: true,\n onInvalidAccess: (variable: string) => {\n throw new Error(\n `❌ Attempted to access a server-side environment variable on the client: ${variable}`,\n );\n },\n onValidationError: error => {\n logWarn('Observability package environment validation failed', { error });\n // Don't throw in packages - use fallbacks\n return undefined as never;\n },\n});\n\n// Helper for non-Next.js contexts (Node.js, workers, tests)\nexport function safeEnv() {\n try {\n if (env && typeof env === 'object') return env;\n } catch {\n // Environment validation failed, use fallbacks\n }\n\n // Fallback values for resilience\n return {\n // Core configuration only\n NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV ?? 'development',\n NEXT_PUBLIC_OBSERVABILITY_DEBUG: process.env.NEXT_PUBLIC_OBSERVABILITY_DEBUG === 'true',\n NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED:\n process.env.NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED === 'true'\n ? true\n : process.env.NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED === 'false'\n ? false\n : undefined,\n };\n}\n\n// Export type\nexport type Env = typeof env;\n","/**\n * @fileoverview ObservabilityManager - Core orchestrator for multiple observability providers\n * ObservabilityManager - Core orchestrator for multiple observability providers\n */\n\nimport { logError, logWarn } from '@od-oneapp/shared/logs';\n\nimport type { ObservabilityPlugin, ObservabilityServerPlugin, PluginLifecycle } from './plugin';\nimport type {\n Breadcrumb,\n LogLevel,\n ObservabilityContext,\n ObservabilityScope,\n ObservabilityServer,\n ObservabilityUser,\n} from './types';\n\n/**\n * Manager that orchestrates multiple observability plugins\n * Broadcasts all method calls to enabled plugins\n */\nexport class ObservabilityManager implements ObservabilityServer {\n private plugins = new Map<string, ObservabilityPlugin | ObservabilityServerPlugin>();\n private initialized = false;\n private initializationPromise: Promise<void> | null = null;\n private lifecycle: PluginLifecycle = {};\n private initializationError: Error | null = null;\n\n /**\n * Create a new ObservabilityManager instance.\n *\n * @param lifecycle - Optional lifecycle callbacks for plugin events\n */\n constructor(lifecycle?: PluginLifecycle) {\n if (lifecycle) {\n this.lifecycle = lifecycle;\n }\n }\n\n /**\n * Add a plugin to the manager\n */\n addPlugin(plugin: ObservabilityPlugin | ObservabilityServerPlugin): this {\n this.plugins.set(plugin.name, plugin);\n return this;\n }\n\n /**\n * Get a specific plugin by name.\n *\n * @param name - Name of the plugin to retrieve\n * @returns Plugin instance if found, undefined otherwise\n */\n getPlugin<T extends ObservabilityPlugin>(name: string): T | undefined {\n return this.plugins.get(name) as T;\n }\n\n /**\n * Get all registered plugins.\n *\n * @returns Array of all registered plugins\n */\n getPlugins(): ObservabilityPlugin[] {\n return Array.from(this.plugins.values());\n }\n\n /**\n * List all registered plugins (alias for getPlugins).\n *\n * @returns Array of all registered plugins\n */\n listPlugins(): ObservabilityPlugin[] {\n return this.getPlugins();\n }\n\n /**\n * Initialize all plugins\n * Note: Failed initialization is retryable - subsequent calls will re-attempt initialization.\n * This allows recovery from transient failures (network issues, temporary misconfigurations).\n */\n async initialize(): Promise<void> {\n // If there's already an initialization in progress, wait for it\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n\n // If already initialized successfully, return early\n if (this.initialized) {\n return;\n }\n\n // Allow retry if previous attempt failed\n if (this.initializationError) {\n // Log retry attempt for debugging\n logWarn('ObservabilityManager: Retrying failed initialization');\n // Clear previous error to allow fresh attempt\n this.initializationError = null;\n }\n\n // Create the initialization promise and store it to prevent concurrent calls\n this.initializationPromise = this.doInitialize();\n\n try {\n await this.initializationPromise;\n } finally {\n // Clear the promise after initialization completes (success or failure)\n this.initializationPromise = null;\n }\n }\n\n private async doInitialize(): Promise<void> {\n const initPromises = Array.from(this.plugins.values())\n .filter(plugin => plugin.enabled && plugin.initialize)\n .map(async plugin => {\n try {\n if (plugin.initialize) {\n await plugin.initialize();\n }\n this.lifecycle.onInitialized?.(plugin);\n } catch (error) {\n logError(`Failed to initialize plugin ${plugin.name}`, {\n error,\n pluginName: plugin.name,\n });\n this.lifecycle.onError?.(error as Error, plugin);\n // Re-throw to propagate error to Promise.all\n throw error;\n }\n });\n\n try {\n await Promise.all(initPromises);\n this.initialized = true;\n } catch (error) {\n this.initializationError = error instanceof Error ? error : new Error(String(error));\n throw this.initializationError;\n }\n }\n\n /**\n * Check if initialization had an error\n * @returns `true` if initialization failed, `false` otherwise\n */\n hasInitializationError(): boolean {\n return this.initializationError !== null;\n }\n\n /**\n * Get the initialization error if one occurred\n * @returns The initialization error or `null` if no error\n */\n getInitializationError(): Error | null {\n return this.initializationError;\n }\n\n /**\n * Shutdown all plugins\n */\n async shutdown(): Promise<void> {\n const shutdownPromises = Array.from(this.plugins.values())\n .filter(plugin => plugin.shutdown)\n .map(async plugin => {\n try {\n if (plugin.shutdown) {\n await plugin.shutdown();\n }\n this.lifecycle.onShutdown?.(plugin);\n } catch (error) {\n logError(`Failed to shutdown plugin ${plugin.name}`, { error, pluginName: plugin.name });\n this.lifecycle.onError?.(error as Error, plugin);\n }\n });\n\n await Promise.allSettled(shutdownPromises);\n this.initialized = false;\n }\n\n /**\n * Broadcast exception to all enabled plugins.\n *\n * @param error - Error object or unknown error value\n * @param context - Optional additional context data\n */\n captureException(error: Error | unknown, context?: ObservabilityContext): void {\n this.broadcast(plugin => plugin.captureException(error, context));\n }\n\n /**\n * Broadcast message to all enabled plugins.\n *\n * @param message - Message to log\n * @param level - Log level (default: 'info')\n * @param context - Optional additional context data\n */\n captureMessage(message: string, level: LogLevel = 'info', context?: ObservabilityContext): void {\n this.broadcast(plugin => plugin.captureMessage(message, level, context));\n }\n\n /**\n * Validate and sanitize user data to prevent injection and DoS attacks\n * @param user - User data to validate\n * @returns Validated user data with length limits and format validation applied\n */\n private validateUser(user: ObservabilityUser | null): ObservabilityUser | null {\n if (!user) return null;\n\n // Validate required ID field\n const id = String(user.id).trim().slice(0, 255);\n if (!id) {\n // Log warning but don't throw - graceful degradation\n logWarn('ObservabilityManager: User ID is empty, ignoring user data');\n return null;\n }\n\n const validated: ObservabilityUser = { id };\n\n // Validate email format if provided\n if ('email' in user && user.email) {\n const email = String(user.email).trim().slice(0, 255);\n // More robust email validation - RFC 5322 simplified but stricter\n // Allows: alphanumeric, dots, plus, hyphens, underscores before @\n // Requires: valid domain with at least one dot after @\n if (\n email &&\n // eslint-disable-next-line security/detect-unsafe-regex -- Safe: bounded input (max 255 chars), RFC 5322 compliant pattern\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(\n email,\n )\n ) {\n validated.email = email;\n }\n }\n\n // Validate username if provided\n if ('username' in user && user.username) {\n const username = String(user.username).trim().slice(0, 255);\n if (username) {\n validated.username = username;\n }\n }\n\n // Validate IP address format if provided\n if ('ip_address' in user && user.ip_address) {\n const ip = String(user.ip_address).trim();\n // Stricter IP validation\n // IPv4: Each octet must be 0-255\n const isValidIPv4 =\n // eslint-disable-next-line security/detect-unsafe-regex -- Safe: bounded pattern for IPv4 validation, input is trimmed string\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(\n ip,\n );\n // IPv6: Basic format check (full validation is complex, this catches most invalid cases)\n const looksLikeIPv6 =\n /^[0-9a-fA-F:]+$/.test(ip) && ip.includes(':') && ip.split(':').length <= 8;\n\n if (isValidIPv4 || looksLikeIPv6) {\n validated.ip_address = ip.slice(0, 45); // IPv6 max length\n }\n }\n\n return validated;\n }\n\n /**\n * Set user on all enabled plugins\n * User data is validated and sanitized before being set\n * @param user - User data to set (will be validated)\n */\n setUser(user: ObservabilityUser | null): void {\n const validatedUser = this.validateUser(user);\n this.broadcast(plugin => plugin.setUser(validatedUser));\n }\n\n /**\n * Add breadcrumb to all enabled plugins.\n *\n * @param breadcrumb - Breadcrumb data to add\n */\n addBreadcrumb(breadcrumb: Breadcrumb): void {\n this.broadcast(plugin => plugin.addBreadcrumb(breadcrumb));\n }\n\n /**\n * Execute callback within scope for all enabled plugins.\n *\n * @param callback - Callback that receives the scope\n */\n withScope(callback: (scope: ObservabilityScope) => void): void {\n this.broadcast(plugin => plugin.withScope(callback));\n }\n\n /**\n * Flush all plugins that support it.\n *\n * Waits for all enabled plugins with flush capability to send pending events.\n *\n * @param timeout - Maximum time to wait in milliseconds\n * @returns Promise resolving to true if all plugins flushed successfully\n */\n async flush(timeout?: number): Promise<boolean> {\n const flushPromises = Array.from(this.plugins.values())\n .filter((plugin): plugin is ObservabilityServerPlugin => {\n return plugin.enabled && 'flush' in plugin && typeof plugin.flush === 'function';\n })\n .map(plugin => plugin.flush(timeout));\n\n if (flushPromises.length === 0) {\n return true;\n }\n\n const results = await Promise.allSettled(flushPromises);\n return results.every(result => result.status === 'fulfilled' && result.value === true);\n }\n\n /**\n * Helper to broadcast a method call to all enabled plugins\n * Uses nested try-catch to ensure errors in error handling don't prevent other plugins from executing\n */\n private broadcast(fn: (plugin: ObservabilityPlugin) => void): void {\n this.plugins.forEach(plugin => {\n if (plugin.enabled) {\n try {\n fn(plugin);\n } catch (error) {\n // Safely handle error without throwing - nested try-catch ensures resilience\n try {\n logError(`Plugin ${plugin.name} error`, { error, pluginName: plugin.name });\n } catch {\n // Logger unavailable - continue silently\n }\n\n try {\n this.lifecycle.onError?.(error as Error, plugin);\n } catch {\n // Error handler failed - continue to next plugin\n }\n }\n }\n });\n }\n\n /**\n * Check if manager has any enabled plugins.\n *\n * @returns True if at least one plugin is enabled, false otherwise\n */\n hasEnabledPlugins(): boolean {\n return Array.from(this.plugins.values()).some(plugin => plugin.enabled);\n }\n\n /**\n * Get names of all enabled plugins.\n *\n * @returns Array of plugin names that are currently enabled\n */\n getEnabledPluginNames(): string[] {\n return Array.from(this.plugins.values())\n .filter(plugin => plugin.enabled)\n .map(plugin => plugin.name);\n }\n}\n","/**\n * @fileoverview ObservabilityBuilder - Fluent API for building observability instances\n * ObservabilityBuilder - Fluent API for building observability instances\n */\n\nimport { logError } from '@od-oneapp/shared/logs';\n\nimport { ObservabilityManager } from '../core/manager';\n\nimport type {\n ObservabilityPlugin,\n ObservabilityServerPlugin,\n PluginLifecycle,\n} from '../core/plugin';\n\n/**\n * Builder for creating configured ObservabilityManager instances\n */\nexport class ObservabilityBuilder {\n private plugins: (ObservabilityPlugin | ObservabilityServerPlugin)[] = [];\n private lifecycle: PluginLifecycle = {};\n private autoInitialize = true;\n\n /**\n * Add a plugin to the observability stack\n * @param plugin - Observability plugin to add\n * @returns Builder instance for chaining\n */\n withPlugin(plugin: ObservabilityPlugin | ObservabilityServerPlugin): this {\n if (plugin) {\n this.plugins.push(plugin);\n }\n return this;\n }\n\n /**\n * Add multiple plugins at once\n * @param plugins - Array of observability plugins to add\n * @returns Builder instance for chaining\n */\n withPlugins(plugins: (ObservabilityPlugin | ObservabilityServerPlugin)[]): this {\n if (plugins && Array.isArray(plugins)) {\n const validPlugins = plugins.filter(plugin => plugin != null);\n this.plugins.push(...validPlugins);\n }\n return this;\n }\n\n /**\n * Set lifecycle callbacks for plugin management\n * @param lifecycle - Lifecycle callback configuration\n * @returns Builder instance for chaining\n */\n withLifecycle(lifecycle: PluginLifecycle): this {\n this.lifecycle = { ...this.lifecycle, ...lifecycle };\n return this;\n }\n\n /**\n * Configure whether to auto-initialize plugins (default: true)\n */\n withAutoInitialize(autoInitialize: boolean): this {\n this.autoInitialize = autoInitialize;\n return this;\n }\n\n /**\n * Build the ObservabilityManager instance\n * @returns Configured ObservabilityManager instance\n */\n build(): ObservabilityManager {\n const manager = new ObservabilityManager(this.lifecycle);\n\n // Add all plugins\n this.plugins.forEach(plugin => manager.addPlugin(plugin));\n\n // Auto-initialize if enabled and not in edge runtime\n if (\n this.autoInitialize &&\n typeof process !== 'undefined' &&\n process.env.NEXT_RUNTIME !== 'edge'\n ) {\n // Initialize asynchronously with safe error handling\n void (async () => {\n try {\n await manager.initialize();\n } catch (error) {\n // Store error in manager for later inspection\n // Note: We can't directly set private property, but manager stores it internally\n\n // Try logError, but don't fail if unavailable\n try {\n logError('Failed to initialize observability', { error });\n } catch {\n // Logger unavailable - error is stored in manager via initialize() method\n }\n }\n })();\n }\n\n return manager;\n }\n\n /**\n * Build and initialize the ObservabilityManager instance\n * @returns Promise resolving to initialized ObservabilityManager\n */\n async buildWithAutoInit(): Promise<ObservabilityManager> {\n const manager = new ObservabilityManager(this.lifecycle);\n\n // Add all plugins\n this.plugins.forEach(plugin => manager.addPlugin(plugin));\n\n // Initialize all plugins - catch errors but still return manager (graceful degradation)\n try {\n await manager.initialize();\n } catch {\n // Error is stored in manager, but we still return it for graceful degradation\n // This allows the application to continue even if observability initialization fails\n }\n\n return manager;\n }\n\n /**\n * Create a new builder instance\n * @returns New ObservabilityBuilder instance\n */\n static create(): ObservabilityBuilder {\n return new ObservabilityBuilder();\n }\n}\n","/**\n * @fileoverview Better Stack (Logtail) environment configuration\n * Better Stack (Logtail) environment configuration\n * Updated to support official @logtail packages\n */\n\nimport { logWarn } from '@od-oneapp/shared/logger';\nimport { createEnv } from '@t3-oss/env-core';\nimport { z } from 'zod/v4';\n\n// Create validated env object\nexport const env = createEnv({\n server: {\n // Legacy support\n LOGTAIL_SOURCE_TOKEN: z.string().optional(),\n BETTERSTACK_SOURCE_TOKEN: z.string().optional(),\n\n // Official Better Stack environment variables\n BETTER_STACK_SOURCE_TOKEN: z.string().optional(),\n BETTER_STACK_INGESTING_URL: z.string().url().optional(),\n BETTER_STACK_LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error', 'off']).optional(),\n },\n client: {\n // Legacy support\n NEXT_PUBLIC_LOGTAIL_TOKEN: z.string().optional(),\n NEXT_PUBLIC_BETTERSTACK_TOKEN: z.string().optional(),\n\n // Official Better Stack client environment variables\n NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN: z.string().optional(),\n NEXT_PUBLIC_BETTER_STACK_INGESTING_URL: z.string().url().optional(),\n NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL: z\n .enum(['debug', 'info', 'warn', 'error', 'off'])\n .optional(),\n },\n clientPrefix: 'NEXT_PUBLIC_',\n runtimeEnv: process.env,\n emptyStringAsUndefined: true,\n onInvalidAccess: (variable: string) => {\n throw new Error(\n `❌ Attempted to access a server-side environment variable on the client: ${variable}`,\n );\n },\n onValidationError: error => {\n logWarn('Better Stack environment validation failed', { error });\n // Don't throw in packages - use fallbacks\n return undefined as never;\n },\n});\n\n/**\n * Safe environment access for non-Next.js contexts.\n *\n * Provides fallback environment variable access for Node.js, workers, and test environments\n * where the validated env object may not be available. Returns fallback values with proper\n * priority handling for legacy and official Better Stack variable names.\n *\n * @returns Environment object with Better Stack configuration values\n */\nexport function safeEnv() {\n if (env) return env;\n\n // Fallback values for resilience with proper priority\n return {\n // Legacy support\n LOGTAIL_SOURCE_TOKEN:\n process.env.LOGTAIL_SOURCE_TOKEN ?? process.env.BETTERSTACK_SOURCE_TOKEN ?? '',\n BETTERSTACK_SOURCE_TOKEN:\n process.env.BETTERSTACK_SOURCE_TOKEN ?? process.env.LOGTAIL_SOURCE_TOKEN ?? '',\n NEXT_PUBLIC_LOGTAIL_TOKEN:\n process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? '',\n NEXT_PUBLIC_BETTERSTACK_TOKEN:\n process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ?? process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ?? '',\n\n // Official Better Stack (preferred)\n BETTER_STACK_SOURCE_TOKEN:\n process.env.BETTER_STACK_SOURCE_TOKEN ??\n process.env.LOGTAIL_SOURCE_TOKEN ??\n process.env.BETTERSTACK_SOURCE_TOKEN ??\n '',\n BETTER_STACK_INGESTING_URL: process.env.BETTER_STACK_INGESTING_URL ?? '',\n BETTER_STACK_LOG_LEVEL:\n (process.env.BETTER_STACK_LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error' | 'off') ?? 'info',\n NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN:\n process.env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??\n process.env.NEXT_PUBLIC_LOGTAIL_TOKEN ??\n process.env.NEXT_PUBLIC_BETTERSTACK_TOKEN ??\n '',\n NEXT_PUBLIC_BETTER_STACK_INGESTING_URL:\n process.env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL ?? '',\n NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL:\n (process.env.NEXT_PUBLIC_BETTER_STACK_LOG_LEVEL as\n | 'debug'\n | 'info'\n | 'warn'\n | 'error'\n | 'off') ?? 'info',\n };\n}\n\n// Export type\nexport type Env = typeof env;\n","/**\n * @fileoverview Better Stack (Logtail) plugin implementation\n * Better Stack (Logtail) plugin implementation\n * Updated to use official @logtail packages\n */\n\nimport { logError, logWarn } from '@od-oneapp/shared/logger';\n\nimport { safeEnv } from './env';\n\nimport type { ObservabilityServerPlugin } from '../../core/plugin';\nimport type {\n Breadcrumb,\n LogLevel,\n ObservabilityContext,\n ObservabilityUser,\n} from '../../core/types';\n\n/**\n * Maximum number of breadcrumbs to include in error/message context\n * Limits context size to prevent excessive data transmission\n */\nconst MAX_BREADCRUMBS_IN_CONTEXT = 10;\n\n/**\n * Maximum number of breadcrumbs to store in memory\n * Prevents unbounded memory growth while maintaining useful history\n */\nconst MAX_BREADCRUMBS_STORED = 100;\n\n/**\n * Minimal Logtail interface for common methods across all @logtail packages\n */\ninterface LogtailClient {\n info(message: string, data?: any): void;\n warn(message: string, data?: any): void;\n error(message: string, data?: any): void;\n debug(message: string, data?: any): void;\n flush(): Promise<void>;\n}\n\n/**\n * Better Stack plugin configuration\n */\nexport interface BetterStackPluginConfig {\n /**\n * The @logtail package to use (e.g., '@logtail/js', '@logtail/next')\n * If not provided, the plugin will auto-detect based on environment\n */\n logtailPackage?: string;\n\n // Core configuration options\n sourceToken?: string;\n endpoint?: string;\n logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'off';\n enabled?: boolean;\n\n // Advanced options\n batchInterval?: number;\n batchSize?: number;\n retryCount?: number;\n retryBackoff?: boolean;\n middleware?: any[];\n}\n\n/**\n * Better Stack plugin implementation using official @logtail packages\n */\n/**\n * Better Stack (Logtail) plugin implementation.\n *\n * Integrates Better Stack logging service into the observability system.\n * Uses official @logtail packages (@logtail/js or @logtail/next) for unified\n * logging across environments.\n */\nexport class BetterStackPlugin<\n T extends LogtailClient = LogtailClient,\n> implements ObservabilityServerPlugin<T> {\n name = 'betterstack';\n enabled: boolean;\n protected client: T | undefined;\n protected initialized = false;\n protected logtailPackage: string;\n protected currentUser: ObservabilityUser | null = null;\n protected breadcrumbs: Breadcrumb[] = [];\n protected breadcrumbIndex = 0;\n protected config: BetterStackPluginConfig;\n\n /**\n * Create a new BetterStackPlugin instance.\n *\n * @param config - Better Stack plugin configuration\n */\n constructor(config: BetterStackPluginConfig = {}) {\n this.config = config;\n const env = safeEnv();\n // Auto-enable if token is provided\n const hasToken =\n config.sourceToken ??\n env.BETTER_STACK_SOURCE_TOKEN ??\n env.BETTERSTACK_SOURCE_TOKEN ??\n env.LOGTAIL_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_BETTERSTACK_TOKEN ??\n env.NEXT_PUBLIC_LOGTAIL_TOKEN;\n this.enabled = config.enabled ?? Boolean(hasToken);\n\n // Determine Logtail package to use\n this.logtailPackage = config.logtailPackage ?? this.detectLogtailPackage();\n }\n\n /**\n * Detect which Logtail package to use based on the runtime environment.\n *\n * @returns Package name ('@logtail/next' for Next.js, '@logtail/js' otherwise)\n */\n private detectLogtailPackage(): string {\n // Next.js environments use Next.js package\n if (process.env.NEXT_RUNTIME) {\n return '@logtail/next';\n }\n // All other environments use the unified js package (bundles both node and browser)\n return '@logtail/js';\n }\n\n getClient(): T | undefined {\n return this.client;\n }\n\n /**\n * Get safe environment access (for testing/mocking).\n *\n * @returns Environment configuration object\n */\n protected getSafeEnv() {\n return safeEnv();\n }\n\n async initialize(config?: BetterStackPluginConfig): Promise<void> {\n if (this.initialized || !this.enabled) return;\n\n const env = safeEnv();\n const mergedConfig = { ...this.config, ...config };\n\n // Get source token with priority: config > new env vars > legacy env vars\n const sourceToken =\n mergedConfig.sourceToken ??\n env.BETTER_STACK_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??\n env.LOGTAIL_SOURCE_TOKEN ??\n env.BETTERSTACK_SOURCE_TOKEN ??\n env.NEXT_PUBLIC_LOGTAIL_TOKEN ??\n env.NEXT_PUBLIC_BETTERSTACK_TOKEN;\n\n if (!sourceToken) {\n logWarn('Better Stack plugin: No source token provided, skipping initialization');\n this.enabled = false;\n return;\n }\n\n try {\n // Dynamic import of the specified Logtail package\n const LogtailModule = await import(/* webpackIgnore: true */ this.logtailPackage);\n\n // Handle different export patterns\n const LogtailClass = LogtailModule.default ?? LogtailModule.Logtail ?? LogtailModule;\n\n if (!LogtailClass) {\n logError(`Better Stack plugin: Could not find Logtail class in ${this.logtailPackage}`, {\n logtailPackage: this.logtailPackage,\n });\n this.enabled = false;\n return;\n }\n\n // Build configuration object\n const logtailConfig: any = {\n sourceToken,\n };\n\n // Add optional configuration\n if (\n mergedConfig.endpoint ??\n env.BETTER_STACK_INGESTING_URL ??\n env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL\n ) {\n logtailConfig.endpoint =\n mergedConfig.endpoint ??\n env.BETTER_STACK_INGESTING_URL ??\n env.NEXT_PUBLIC_BETTER_STACK_INGESTING_URL;\n }\n\n // Initialize the client\n this.client = new LogtailClass(logtailConfig) as T;\n\n this.initialized = true;\n } catch (error) {\n logError(`Failed to import Logtail package '${this.logtailPackage}'`, {\n error,\n logtailPackage: this.logtailPackage,\n });\n this.enabled = false;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.client && this.initialized) {\n await this.client.flush();\n this.initialized = false;\n }\n }\n\n captureException(error: Error | unknown, context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n const errorObj = error instanceof Error ? error : new Error(String(error));\n\n // Build structured data\n const data = {\n error: {\n name: errorObj.name,\n message: errorObj.message,\n stack: errorObj.stack,\n },\n context: context?.extra,\n tags: context?.tags,\n user: context?.user ?? this.currentUser,\n breadcrumbs: this.getRecentBreadcrumbs(MAX_BREADCRUMBS_IN_CONTEXT),\n };\n\n this.client.error(errorObj.message, data);\n }\n\n captureMessage(message: string, level: LogLevel = 'info', context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n // Build structured data\n const data = {\n level,\n context: context?.extra,\n tags: context?.tags,\n user: context?.user ?? this.currentUser,\n breadcrumbs: this.getRecentBreadcrumbs(MAX_BREADCRUMBS_IN_CONTEXT),\n };\n\n // Map log levels to Logtail methods\n switch (level) {\n case 'debug':\n this.client.debug(message, data);\n break;\n case 'warning':\n this.client.warn(message, data);\n break;\n case 'error':\n this.client.error(message, data);\n break;\n case 'info':\n default:\n this.client.info(message, data);\n break;\n }\n }\n\n setUser(user: ObservabilityUser | null): void {\n if (!this.enabled) return;\n this.currentUser = user;\n }\n\n addBreadcrumb(breadcrumb: Breadcrumb): void {\n if (!this.enabled) return;\n\n const enriched = {\n ...breadcrumb,\n timestamp: breadcrumb.timestamp ?? Date.now() / 1000,\n };\n\n // Use circular buffer to avoid array reallocation\n if (this.breadcrumbs.length < MAX_BREADCRUMBS_STORED) {\n this.breadcrumbs.push(enriched);\n } else {\n // Overwrite oldest entry (circular buffer)\n this.breadcrumbs[this.breadcrumbIndex] = enriched;\n this.breadcrumbIndex = (this.breadcrumbIndex + 1) % MAX_BREADCRUMBS_STORED;\n }\n }\n\n /**\n * Get the most recent breadcrumbs in chronological order\n * @param count - Number of breadcrumbs to retrieve\n * @returns Array of recent breadcrumbs\n */\n private getRecentBreadcrumbs(count: number): Breadcrumb[] {\n const { length } = this.breadcrumbs;\n if (length === 0) return [];\n if (length <= count) return this.breadcrumbs.slice();\n\n // If buffer is not full yet, return last N items from end of array\n if (length < MAX_BREADCRUMBS_STORED) {\n return this.breadcrumbs.slice(length - count);\n }\n\n // Circular buffer logic:\n // - When the buffer is full, `this.breadcrumbIndex` points to the oldest entry (the next to be overwritten).\n // - The most recent breadcrumb is at index `(this.breadcrumbIndex - 1 + length) % length`.\n // - To get the last `count` breadcrumbs in chronological order, we start at\n // `(this.breadcrumbIndex - count + length) % length` and read `count` entries, wrapping around as needed.\n // - This ensures we always get the correct slice, even if the buffer has wrapped around.\n const result: Breadcrumb[] = [];\n const start = (this.breadcrumbIndex - count + length) % length;\n\n for (let i = 0; i < count; i++) {\n const index = (start + i) % length;\n const breadcrumb = this.breadcrumbs[index];\n if (breadcrumb) {\n result.push(breadcrumb);\n }\n }\n\n return result;\n }\n\n withScope(callback: (scope: any) => void): void {\n if (!this.enabled) return;\n\n try {\n // Simple scope implementation\n const scope = {\n setContext: (_key: string, _context: unknown) => {\n // Could store this for next log entry\n },\n setUser: (user: ObservabilityUser | null) => {\n this.setUser(user);\n },\n };\n callback(scope);\n } catch {\n // Gracefully handle scope errors\n }\n }\n\n async flush(_timeout?: number): Promise<boolean> {\n if (!this.enabled || !this.client) return true;\n\n try {\n await this.client.flush();\n return true;\n } catch (error) {\n logError('Better Stack flush error', { error });\n return false;\n }\n }\n}\n\n/**\n * Factory function to create a Better Stack plugin.\n *\n * Creates a configured BetterStackPlugin instance with optional configuration.\n * Auto-detects the appropriate @logtail package based on the environment.\n *\n * @param config - Optional Better Stack plugin configuration\n * @returns BetterStackPlugin instance\n *\n * @example\n * ```typescript\n * const betterstack = createBetterStackPlugin({\n * sourceToken: '...',\n * logLevel: 'info',\n * });\n * ```\n */\nexport const createBetterStackPlugin = <T extends LogtailClient = LogtailClient>(\n config?: BetterStackPluginConfig,\n): BetterStackPlugin<T> => {\n return new BetterStackPlugin<T>(config);\n};\n","/**\n * @fileoverview Shared observability utilities and types\n * Shared observability utilities and types\n */\n\nimport { logWarn } from '@od-oneapp/shared/logger';\n\n/**\n * Get runtime environment information.\n *\n * Detects the current runtime environment (browser, Node.js, edge, Bun) and returns\n * detailed information about the environment type, version, and capabilities.\n *\n * @returns Runtime information object with type, version, and environment-specific details\n *\n * @example\n * ```typescript\n * const runtime = getRuntimeInfo();\n * // Returns: { type: 'node', version: '22.0.0', major: 22, minor: 0, isNode22Plus: true, isNextJs: true }\n * // or: { type: 'browser', isNextJs: true }\n * // or: { type: 'edge', variant: 'vercel' }\n * ```\n */\nexport const getRuntimeInfo = () => {\n // Edge runtime detection (Vercel Edge, Cloudflare Workers)\n if (typeof globalThis !== 'undefined' && (globalThis as any).EdgeRuntime) {\n return { type: 'edge', variant: 'vercel' };\n }\n if (\n typeof globalThis !== 'undefined' &&\n (globalThis as any).caches &&\n typeof (globalThis as any).caches !== 'undefined'\n ) {\n return { type: 'edge', variant: 'cloudflare' };\n }\n\n // Bun detection\n if (typeof process !== 'undefined' && process.versions?.bun) {\n return { type: 'bun', version: process.versions.bun };\n }\n\n // Browser detection (more robust)\n if (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as any).window !== 'undefined' &&\n typeof (globalThis as any).window.document !== 'undefined' &&\n typeof (globalThis as any).window.navigator !== 'undefined'\n ) {\n return { type: 'browser', isNextJs: Boolean((globalThis as any).window.__NEXT_DATA__) };\n }\n\n // Node.js detection with version check\n if (typeof process !== 'undefined' && process.versions?.node) {\n const nodeVersion = parseInt(process.versions.node.split('.')[0] ?? '0');\n const nodeVersionMinor = parseInt(process.versions.node.split('.')[1] ?? '0');\n\n if (nodeVersion < 22) {\n // Note: Using logWarn here - observability system may not be initialized yet, but shared logger is always available\n logWarn(\n `[Observability] Node ${process.versions.node} detected. Node 22+ is required for optimal performance and latest features.`,\n );\n }\n\n return {\n type: 'node',\n version: process.versions.node,\n major: nodeVersion,\n minor: nodeVersionMinor,\n isNode22Plus: nodeVersion >= 22,\n isNextJs:\n Boolean(process.env.NEXT_RUNTIME) ||\n Boolean(process.env.__NEXT_RUNTIME) ||\n Boolean(process.env.NEXT_PUBLIC_VERCEL_ENV),\n };\n }\n\n // Fallback\n return { type: 'unknown' };\n};\n\n// Cache the runtime info\nconst runtimeInfo = getRuntimeInfo();\n\n/**\n * Get cached runtime environment information.\n *\n * Returns the runtime information that was detected at module load time.\n * This is cached to avoid repeated detection checks.\n *\n * @returns Cached runtime information object\n *\n * @example\n * ```typescript\n * const runtime = getRuntimeEnvironment();\n * console.log(runtime.type); // 'node', 'browser', 'edge', etc.\n * ```\n */\nexport const getRuntimeEnvironment = () => runtimeInfo;\n\n/**\n * Detect if code is running in a browser environment\n * Extracted to shared utility to avoid duplication\n * @returns true if running in browser, false otherwise\n */\nexport function isBrowser(): boolean {\n return (\n typeof globalThis !== 'undefined' &&\n 'window' in globalThis &&\n typeof (globalThis as any).window !== 'undefined' &&\n typeof (globalThis as any).window.document !== 'undefined' &&\n typeof (globalThis as any).window.navigator !== 'undefined'\n );\n}\n\n/**\n * Determine if console logging should be enabled based on environment\n * Centralized logic to avoid duplication across entry points\n * @param envNodeEnv - The NEXT_PUBLIC_NODE_ENV value\n * @param consoleEnabled - The NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED value (explicit control)\n * @param debugEnabled - The NEXT_PUBLIC_OBSERVABILITY_DEBUG value\n * @returns boolean indicating if console should be enabled\n */\nexport function shouldEnableConsole(\n envNodeEnv?: string,\n consoleEnabled?: boolean,\n debugEnabled?: boolean,\n): boolean {\n const isDevelopment = envNodeEnv === 'development' || process.env.NODE_ENV === 'development';\n\n // Priority: explicit control > development mode > debug mode\n if (consoleEnabled !== undefined) {\n return consoleEnabled;\n }\n if (isDevelopment) {\n return true;\n }\n return debugEnabled ?? false;\n}\n\n// Export types for convenience - removed for Rollup compatibility\n\n// Note: For direct access to observability instances, import from environment-specific modules:\n// - @repo/observability/client-next\n// - @repo/observability/server-next\n// - @repo/observability/server-edge\n// - @repo/observability/client\n// - @repo/observability/server\n","/**\n * @fileoverview Console plugin for observability\n * Console plugin for observability\n * Simple logging implementation for development\n */\n\nimport { isBrowser } from '../../shared';\n\nimport type {\n ObservabilityPlugin,\n ObservabilityServerPlugin,\n PluginFactory,\n} from '../../core/plugin';\nimport type {\n Breadcrumb,\n LogLevel,\n ObservabilityContext,\n ObservabilityUser,\n} from '../../core/types';\n\n/**\n * Console plugin configuration\n */\nexport interface ConsolePluginConfig {\n prefix?: string;\n logLevel?: LogLevel;\n enabled?: boolean;\n colors?: boolean;\n}\n\n/**\n * Console plugin implementation for browser environments\n */\n/**\n * Console plugin implementation for browser environments.\n *\n * Provides simple console logging with color support for development.\n * Supports both browser (CSS colors) and Node.js (ANSI colors) environments.\n */\nexport class ConsolePlugin implements ObservabilityPlugin<Console> {\n name = 'console';\n enabled: boolean;\n protected prefix: string;\n private colors: boolean;\n private isBrowser: boolean;\n\n /**\n * Create a new ConsolePlugin instance.\n *\n * @param config - Console plugin configuration\n */\n constructor(config: ConsolePluginConfig = {}) {\n this.enabled = config.enabled ?? true;\n this.prefix = config.prefix ?? '[Console]';\n // Note: config.logLevel is accepted but not yet used (reserved for future log level filtering)\n this.colors = config.colors ?? true;\n this.isBrowser = isBrowser();\n }\n\n async initialize(): Promise<void> {\n // Console doesn't need initialization\n }\n\n async shutdown(): Promise<void> {\n // Console doesn't need shutdown\n }\n\n getClient(): Console | undefined {\n return undefined; // Console has no client\n }\n\n captureException(error: Error | unknown, context?: ObservabilityContext): void {\n if (!this.enabled) return;\n\n try {\n const contextData = this.formatContext(context);\n\n if (this.colors && this.isBrowser) {\n // Browser: Use CSS colors\n console.error(\n `%c${this.prefix} Error:`,\n 'color: red; font-weight: bold',\n error,\n contextData,\n );\n } else if (this.colors) {\n // Node.js: Use ANSI codes\n console.error(`\\x1b[31m${this.prefix} Error:\\x1b[0m`, error, contextData);\n } else {\n // No colors\n console.error(`${this.prefix} Error:`, error, contextData);\n }\n } catch {\n // Gracefully handle console errors\n }\n }\n\n captureMessage(message: string, level: LogLevel = 'info', context?: ObservabilityContext): void {\n if (!this.enabled) return;\n\n try {\n const contextData = this.formatContext(context);\n const logMethod = this.getLogMethod(level);\n const levelLabel = this.getLevelLabel(level);\n\n if (this.colors && this.isBrowser) {\n // Browser: Use CSS colors\n const cssColor = this.getBrowserColorCSS(level);\n (console[logMethod] as (...args: any[]) => void)(\n `%c${this.prefix} ${levelLabel}:`,\n cssColor,\n message,\n contextData,\n );\n } else if (this.colors) {\n // Node.js: Use ANSI codes\n const ansiColor = this.getAnsiColorCode(level);\n (console[logMethod] as (...args: any[]) => void)(\n `${ansiColor}${this.prefix} ${levelLabel}:\\x1b[0m`,\n message,\n contextData,\n );\n } else {\n // No colors\n (console[logMethod] as (...args: any[]) => void)(\n `${this.prefix} ${levelLabel}:`,\n message,\n contextData,\n );\n }\n } catch {\n // Gracefully handle console errors\n }\n }\n\n setUser(user: ObservabilityUser | null): void {\n if (!this.enabled) return;\n\n try {\n if (user === null) {\n console.info(this.prefix, 'User cleared');\n } else {\n console.info(this.prefix, 'User set:', JSON.stringify(user));\n }\n } catch {\n // Gracefully handle console errors\n }\n }\n\n addBreadcrumb(breadcrumb: Breadcrumb): void {\n if (!this.enabled) return;\n\n try {\n const enrichedBreadcrumb = {\n ...breadcrumb,\n timestamp: breadcrumb.timestamp ?? Date.now() / 1000,\n };\n console.log(this.prefix, 'Breadcrumb:', JSON.stringify(enrichedBreadcrumb));\n } catch {\n // Gracefully handle console errors\n }\n }\n\n withScope(callback: (scope: any) => void): void {\n if (!this.enabled) return;\n\n try {\n const scope = {\n setContext: (key: string, context: unknown) => {\n console.log(this.prefix, 'Context set:', key, JSON.stringify(context));\n },\n setUser: (user: ObservabilityUser | null) => {\n this.setUser(user);\n },\n };\n callback(scope);\n } catch {\n // Gracefully handle scope errors\n }\n }\n\n async flush(): Promise<boolean> {\n // Console doesn't need flushing\n if (this.enabled) {\n console.log(this.prefix, 'Flushed');\n }\n return true;\n }\n\n private formatContext(context?: ObservabilityContext): any {\n if (!context) return {};\n\n // Handle new format with explicit extra/tags structure\n if (context.extra !== undefined || context.tags !== undefined) {\n return {\n context: context.extra,\n tags: context.tags,\n };\n }\n\n // Handle AI package format with operation/metadata structure\n if ('operation' in context || 'metadata' in context) {\n return {\n context: context.metadata ?? {},\n tags: { operation: context.operation },\n };\n }\n\n // Handle any other context format - use as-is for context\n return {\n context,\n tags: {},\n };\n }\n\n /**\n * Get CSS color style for browser console\n * @param level - Log level\n * @returns CSS style string\n */\n private getBrowserColorCSS(level: LogLevel): string {\n const colorMap: Record<LogLevel, string> = {\n debug: 'color: #00CED1; font-weight: bold', // Dark Cyan\n info: 'color: #32CD32; font-weight: bold', // Lime Green\n warning: 'color: #FFA500; font-weight: bold', // Orange\n error: 'color: #DC143C; font-weight: bold', // Crimson\n };\n return colorMap[level] ?? 'color: inherit';\n }\n\n /**\n * Get ANSI color code for Node.js terminal\n * @param level - Log level\n * @returns ANSI escape code\n */\n private getAnsiColorCode(level: LogLevel): string {\n const colorMap: Record<LogLevel, string> = {\n debug: '\\x1b[36m', // Cyan\n info: '\\x1b[32m', // Green\n warning: '\\x1b[33m', // Yellow\n error: '\\x1b[31m', // Red\n };\n return colorMap[level] ?? '';\n }\n\n /**\n * Get the console method name for a log level.\n *\n * @param level - Log level\n * @returns Console method name ('debug', 'info', 'warn', or 'error')\n */\n private getLogMethod(level: LogLevel): keyof Console {\n switch (level) {\n case 'debug':\n return 'debug';\n case 'info':\n return 'info';\n case 'warning':\n return 'warn';\n case 'error':\n return 'error';\n default:\n return 'info';\n }\n }\n\n /**\n * Get a human-readable label for a log level.\n *\n * @param level - Log level\n * @returns Capitalized level label ('Debug', 'Info', 'Warning', 'Error')\n */\n private getLevelLabel(level: LogLevel): string {\n switch (level) {\n case 'debug':\n return 'Debug';\n case 'info':\n return 'Info';\n case 'warning':\n return 'Warning';\n case 'error':\n return 'Error';\n default:\n return 'Info';\n }\n }\n}\n\n/**\n * Console plugin implementation for server environments\n * Inherits flush() from ConsolePlugin - no override needed\n */\nexport class ConsoleServerPlugin\n extends ConsolePlugin\n implements ObservabilityServerPlugin<Console> {}\n\n/**\n * Factory function to create a console plugin for browser environments.\n *\n * @param config - Console plugin configuration\n * @returns ConsolePlugin instance configured for browser\n */\nexport const createConsolePlugin: PluginFactory<ConsolePluginConfig, ConsolePlugin> = config => {\n return new ConsolePlugin(config);\n};\n\n/**\n * Factory function to create a console plugin for server environments.\n *\n * Creates a server-compatible console plugin that includes flush() capability.\n *\n * @param config - Console plugin configuration\n * @returns ConsoleServerPlugin instance configured for server\n */\nexport const createConsoleServerPlugin: PluginFactory<\n ConsolePluginConfig,\n ConsoleServerPlugin\n> = config => {\n return new ConsoleServerPlugin(config);\n};\n\n// Re-export types\nexport type { ObservabilityPlugin, ObservabilityServerPlugin } from '../../core/plugin';\n","/**\n * @fileoverview Sentry-specific environment configuration\n * Sentry-specific environment configuration\n * Apps can extend this configuration to inherit Sentry environment variables\n */\n\nimport { logWarn } from '@od-oneapp/shared/logger';\nimport { createEnv } from '@t3-oss/env-core';\nimport { z } from 'zod/v4';\n\n// Create validated env object\nexport const env = createEnv({\n server: {\n SENTRY_DSN: z.string().url().optional(),\n SENTRY_AUTH_TOKEN: z.string().optional(),\n SENTRY_ORG: z.string().optional(),\n SENTRY_PROJECT: z.string().optional(),\n SENTRY_ENVIRONMENT: z.enum(['development', 'preview', 'production']).optional(),\n SENTRY_RELEASE: z.string().optional(),\n SENTRY_TRACES_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),\n SENTRY_PROFILES_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),\n SENTRY_REPLAYS_SESSION_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),\n SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE: z.coerce.number().min(0).max(1).optional(),\n SENTRY_DEBUG: z\n .string()\n .optional()\n .transform(val => val === 'true')\n .default(false),\n },\n clientPrefix: 'NEXT_PUBLIC_',\n client: {\n NEXT_PUBLIC_SENTRY_DSN: z.string().url().optional(),\n NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.enum(['development', 'preview', 'production']).optional(),\n NEXT_PUBLIC_SENTRY_RELEASE: z.string().optional(),\n },\n runtimeEnv: process.env,\n emptyStringAsUndefined: true,\n onInvalidAccess: (variable: string) => {\n throw new Error(\n `❌ Attempted to access a server-side environment variable on the client: ${variable}`,\n );\n },\n onValidationError: error => {\n // Note: Using logWarn during env validation - shared logger is always available\n logWarn('Sentry environment validation failed', { error });\n // Don't throw in packages - use fallbacks\n return undefined as never;\n },\n});\n\n/**\n * Safe environment access for non-Next.js contexts.\n *\n * Provides fallback environment variable access for Node.js, workers, and test environments\n * where the validated env object may not be available. Returns fallback values with proper\n * type coercion and defaults.\n *\n * @returns Environment object with Sentry configuration values\n */\nexport function safeEnv() {\n if (env) return env;\n\n // Fallback values for resilience\n return {\n // Server\n SENTRY_DSN: process.env.SENTRY_DSN ?? '',\n SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN ?? '',\n SENTRY_ORG: process.env.SENTRY_ORG ?? '',\n SENTRY_PROJECT: process.env.SENTRY_PROJECT ?? '',\n SENTRY_ENVIRONMENT:\n (process.env.SENTRY_ENVIRONMENT as 'development' | 'preview' | 'production') ?? 'development',\n SENTRY_RELEASE: process.env.SENTRY_RELEASE ?? '',\n SENTRY_TRACES_SAMPLE_RATE:\n Number(process.env.SENTRY_TRACES_SAMPLE_RATE) ||\n (process.env.NODE_ENV === 'production' ? 0.1 : 1.0),\n SENTRY_PROFILES_SAMPLE_RATE: Number(process.env.SENTRY_PROFILES_SAMPLE_RATE) ?? 0,\n SENTRY_REPLAYS_SESSION_SAMPLE_RATE:\n Number(process.env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE) ||\n (process.env.NODE_ENV === 'production' ? 0.1 : 0),\n SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE:\n Number(process.env.SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE) || 1.0,\n SENTRY_DEBUG: process.env.SENTRY_DEBUG === 'true',\n // Client\n NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN ?? '',\n NEXT_PUBLIC_SENTRY_ENVIRONMENT:\n (process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT as 'development' | 'preview' | 'production') ??\n 'development',\n NEXT_PUBLIC_SENTRY_RELEASE: process.env.NEXT_PUBLIC_SENTRY_RELEASE ?? '',\n };\n}\n\n// Export type\nexport type Env = typeof env;\n","/**\n * @fileoverview Sentry plugin implementation\n * Sentry plugin implementation\n */\n\nimport { logDebug, logError, logWarn } from '@od-oneapp/shared/logger';\n\nimport { isBrowser } from '../../shared';\n\nimport { safeEnv } from './env';\n\nimport type { Hub, Scope, Span, SpanContext, Transaction, TransactionContext } from './types';\nimport type { ObservabilityServerPlugin } from '../../core/plugin';\nimport type {\n Breadcrumb,\n LogLevel,\n ObservabilityContext,\n ObservabilityUser,\n} from '../../core/types';\n\n/**\n * Default log filter function that filters out noisy development logs.\n * Filters out:\n * - Next.js Fast Refresh messages\n * - HMR (Hot Module Replacement) messages\n * - Prisma query logs (server-only)\n * - Prisma engine/info logs\n * - SQL queries matching Prisma's format\n *\n * Handles ANSI color codes, console formatting (%c, %s), and CSS styling.\n *\n * @param log - The log entry from Sentry\n * @param isServer - Whether this is running on the server (defaults to true)\n * @returns The log entry if it should be sent, or null to filter it out\n */\nexport function defaultBeforeSendLog(log: any, isServer = true): any | null {\n // Check both message and any formatted message fields\n const messageToCheck = log.message || log.formatted || '';\n if (!messageToCheck) {\n return log; // No message to filter, send as-is\n }\n\n const message = String(messageToCheck);\n\n // Remove ANSI color codes for comparison (e.g., \\u001b[34mprisma:query\\u001b[39m)\n // Also handle %c format codes used by console styling and %s placeholders\n const messageWithoutAnsi = message\n .replace(/\\u001b\\[[0-9;]*m/g, '') // Remove ANSI escape codes\n .replace(/%[csdfiO]/g, '') // Remove console format placeholders (%c, %s, %d, %f, %i, %o)\n .replace(/background:[^;]+;?/g, '') // Remove CSS background styles\n .replace(/color:[^;]+;?/g, '') // Remove CSS color styles\n .replace(/border-radius:[^;]+;?/g, '') // Remove CSS border-radius\n .replace(/light-dark\\([^)]+\\)/g, '') // Remove light-dark() CSS functions\n .replace(/rgba?\\([^)]+\\)/g, '') // Remove rgba/rgb color functions\n .replace(/#[0-9a-fA-F]{3,8}/g, '') // Remove hex colors\n .toLowerCase(); // Case-insensitive matching\n\n // Filter out Next.js Fast Refresh and HMR messages (both client and server)\n if (messageWithoutAnsi.includes('[fast refresh]') || messageWithoutAnsi.includes('[hmr]')) {\n return null; // Drop the log\n }\n\n // Filter out Prisma logs (server-only)\n if (isServer) {\n if (\n messageWithoutAnsi.includes('prisma:query') ||\n messageWithoutAnsi.includes('prisma:engine') ||\n messageWithoutAnsi.includes('prisma:info') ||\n // Also filter SQL queries that look like Prisma queries (SELECT ... FROM \"public\".)\n (messageWithoutAnsi.includes('select') &&\n messageWithoutAnsi.includes('from') &&\n (messageWithoutAnsi.includes('\"public\".') || messageWithoutAnsi.includes('public.')))\n ) {\n return null; // Drop the log\n }\n }\n\n return log; // Send the log\n}\n\n/**\n * Minimal Sentry interface for common methods across all Sentry packages\n */\ninterface SentryClient {\n init(options: any): void;\n captureException(error: any, captureContext?: any): string;\n captureMessage(message: string, captureContext?: any): string;\n setUser(user: any): void;\n addBreadcrumb(breadcrumb: any): void;\n withScope(callback: (scope: any) => void): void;\n getCurrentScope?(): any;\n getActiveTransaction?(): any;\n startTransaction?(context: TransactionContext, customSamplingContext?: any): any;\n startSpan?(context: SpanContext): any;\n configureScope?(callback: (scope: any) => void): void;\n getCurrentHub?(): any;\n flush?(timeout?: number): Promise<boolean>;\n close?(timeout?: number): Promise<boolean>;\n browserTracingIntegration?(): any;\n replayIntegration?(): any;\n profilesIntegration?(): any;\n consoleLoggingIntegration?(options?: { levels?: string[] }): any;\n logger?: {\n trace(message: string, attributes?: Record<string, unknown>): void;\n debug(message: string, attributes?: Record<string, unknown>): void;\n info(message: string, attributes?: Record<string, unknown>): void;\n warn(message: string, attributes?: Record<string, unknown>): void;\n error(message: string, attributes?: Record<string, unknown>): void;\n fatal(message: string, attributes?: Record<string, unknown>): void;\n fmt(strings: TemplateStringsArray, ...values: unknown[]): string;\n };\n}\n\n/**\n * Sentry plugin configuration\n */\nexport interface SentryPluginConfig {\n /**\n * The Sentry package to use (e.g., '@sentry/node', '@sentry/browser', '@sentry/nextjs')\n * If not provided, the plugin will try to detect based on environment\n */\n sentryPackage?: string;\n\n // Core Sentry options\n dsn?: string;\n environment?: string;\n release?: string;\n enabled?: boolean;\n debug?: boolean;\n\n // Sampling rates\n tracesSampleRate?: number;\n profilesSampleRate?: number;\n replaysSessionSampleRate?: number;\n replaysOnErrorSampleRate?: number;\n\n // Integrations and hooks\n integrations?: any[];\n beforeSend?: (event: any, hint: any) => any;\n beforeSendTransaction?: (event: any, hint: any) => any;\n beforeBreadcrumb?: (breadcrumb: any, hint?: any) => any;\n beforeSendLog?: (log: any) => any;\n\n // Logging options\n enableLogs?: boolean;\n consoleLoggingIntegration?: {\n levels?: ('log' | 'warn' | 'error' | 'debug' | 'info' | 'assert' | 'trace')[];\n };\n\n // Trace propagation\n tracePropagationTargets?: (string | RegExp)[];\n\n // Other options\n initialScope?: any;\n maxBreadcrumbs?: number;\n attachStacktrace?: boolean;\n autoSessionTracking?: boolean;\n sendDefaultPii?: boolean;\n}\n\n/**\n * Sentry plugin implementation\n */\n/**\n * Sentry plugin implementation.\n *\n * Integrates Sentry error tracking and performance monitoring into the observability system.\n * Auto-detects the appropriate Sentry package (@sentry/node, @sentry/browser, @sentry/nextjs)\n * based on the runtime environment.\n */\nexport class SentryPlugin<\n T extends SentryClient = SentryClient,\n> implements ObservabilityServerPlugin<T> {\n name = 'sentry';\n enabled: boolean;\n protected client: T | undefined;\n protected initialized = false;\n protected sentryPackage: string;\n protected config: SentryPluginConfig;\n\n /**\n * Create a new SentryPlugin instance.\n *\n * @param config - Sentry plugin configuration\n */\n constructor(config: SentryPluginConfig = {}) {\n this.config = config;\n const env = safeEnv();\n // Auto-enable if DSN is provided\n const hasDSN = config.dsn ?? env.SENTRY_DSN ?? env.NEXT_PUBLIC_SENTRY_DSN;\n this.enabled = config.enabled ?? Boolean(hasDSN);\n\n // Determine Sentry package to use\n this.sentryPackage = config.sentryPackage ?? this.detectSentryPackage();\n }\n\n /**\n * Detect which Sentry package to use based on the runtime environment.\n *\n * @returns Package name ('@sentry/node', '@sentry/browser', or '@sentry/nextjs')\n */\n private detectSentryPackage(): string {\n if (isBrowser()) {\n return '@sentry/browser';\n } else if (process.env.NEXT_RUNTIME === 'edge') {\n return '@sentry/nextjs'; // Next.js edge uses same package\n } else if (process.env.NEXT_RUNTIME) {\n return '@sentry/nextjs';\n } else {\n return '@sentry/node';\n }\n }\n\n getClient(): T | undefined {\n return this.client;\n }\n\n /**\n * Get safe environment access (for testing/mocking).\n *\n * @returns Environment configuration object\n */\n protected getSafeEnv() {\n return safeEnv();\n }\n\n async initialize(config?: SentryPluginConfig): Promise<void> {\n if (this.initialized || !this.enabled) return;\n\n const env = safeEnv();\n const mergedConfig = { ...this.config, ...config };\n\n // Check for DSN\n const dsn = mergedConfig.dsn ?? env.SENTRY_DSN ?? env.NEXT_PUBLIC_SENTRY_DSN;\n if (!dsn) {\n logWarn('Sentry plugin: No DSN provided, skipping initialization');\n this.enabled = false;\n return;\n }\n\n try {\n // Dynamic import of the specified Sentry package\n this.client = (await import(/* webpackIgnore: true */ this.sentryPackage)) as T;\n\n if (this.client && this.enabled) {\n // Build integrations array if not provided\n let { integrations } = mergedConfig;\n if (!integrations && this.client.browserTracingIntegration) {\n integrations = [];\n\n // Add browser tracing for performance monitoring\n if (\n mergedConfig.tracesSampleRate !== undefined ||\n env.SENTRY_TRACES_SAMPLE_RATE !== undefined\n ) {\n integrations.push(this.client.browserTracingIntegration());\n }\n\n // Add replay integration if configured\n if (\n this.client.replayIntegration &&\n (mergedConfig.replaysSessionSampleRate !== undefined ||\n env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE !== undefined)\n ) {\n integrations.push(this.client.replayIntegration());\n }\n\n // Add profiling if configured\n if (\n this.client.profilesIntegration &&\n (mergedConfig.profilesSampleRate !== undefined ||\n env.SENTRY_PROFILES_SAMPLE_RATE !== undefined)\n ) {\n integrations.push(this.client.profilesIntegration());\n }\n }\n\n // Add console logging integration if logs are enabled\n const enableLogs = mergedConfig.enableLogs ?? true;\n if (enableLogs && this.client.consoleLoggingIntegration) {\n const consoleLoggingConfig = mergedConfig.consoleLoggingIntegration || {\n levels: ['log', 'warn', 'error'],\n };\n if (!integrations) {\n integrations = [];\n }\n integrations.push(this.client.consoleLoggingIntegration(consoleLoggingConfig));\n }\n\n this.client.init({\n dsn,\n environment: mergedConfig.environment ?? env.SENTRY_ENVIRONMENT ?? process.env.NODE_ENV,\n release: mergedConfig.release ?? env.SENTRY_RELEASE,\n debug: mergedConfig.debug ?? env.SENTRY_DEBUG,\n\n // Enable logs to be sent to Sentry\n enableLogs,\n\n // Sampling rates\n tracesSampleRate: mergedConfig.tracesSampleRate ?? env.SENTRY_TRACES_SAMPLE_RATE,\n profilesSampleRate: mergedConfig.profilesSampleRate ?? env.SENTRY_PROFILES_SAMPLE_RATE,\n replaysSessionSampleRate:\n mergedConfig.replaysSessionSampleRate ?? env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE,\n replaysOnErrorSampleRate:\n mergedConfig.replaysOnErrorSampleRate ?? env.SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE,\n\n // Integrations and hooks\n integrations,\n beforeSend: mergedConfig.beforeSend,\n beforeSendTransaction: mergedConfig.beforeSendTransaction,\n // Use provided beforeSendLog, or default filter if logs are enabled and no custom filter provided\n beforeSendLog:\n mergedConfig.beforeSendLog ||\n (enableLogs ? (log: any) => defaultBeforeSendLog(log, !isBrowser()) : undefined),\n\n // Other options\n tracePropagationTargets: mergedConfig.tracePropagationTargets,\n initialScope: mergedConfig.initialScope,\n maxBreadcrumbs: mergedConfig.maxBreadcrumbs,\n attachStacktrace: mergedConfig.attachStacktrace,\n autoSessionTracking: mergedConfig.autoSessionTracking,\n });\n\n this.initialized = true;\n }\n } catch (error) {\n logError(`Failed to import Sentry package '${this.sentryPackage}'`, { error });\n this.enabled = false;\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.client && this.initialized) {\n // Use close if available, otherwise flush\n if (this.client.close) {\n await this.client.close();\n } else if (this.client.flush) {\n await this.client.flush();\n }\n this.initialized = false;\n }\n }\n\n /**\n * Clean up the plugin (alias for shutdown)\n */\n async cleanup(): Promise<void> {\n await this.shutdown();\n }\n\n captureException(error: Error | unknown, context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n // Additional build-time guard to prevent errors during static generation\n if (typeof this.client.captureException !== 'function') {\n // During build/static generation, Sentry client may not be properly initialized\n // Fall back to logging in development\n if (process.env.NODE_ENV === 'development') {\n logError('[Sentry Fallback] Exception', { error });\n }\n return;\n }\n\n try {\n this.client.captureException(error, context);\n } catch (captureError) {\n // Graceful fallback if Sentry fails during build\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to capture exception', { error: captureError });\n logError('[Sentry Fallback] Exception', { error });\n }\n }\n }\n\n captureMessage(message: string, level: LogLevel = 'info', context?: ObservabilityContext): void {\n if (!this.enabled || !this.client) return;\n\n // Prefer Sentry.logger if available (structured logs)\n if (this.client.logger) {\n try {\n const attributes: Record<string, unknown> | undefined = context\n ? ((context.extra as Record<string, unknown> | undefined) ??\n (context as Record<string, unknown>))\n : undefined;\n switch (level) {\n case 'debug':\n this.client.logger.debug(message, attributes);\n return;\n case 'info':\n this.client.logger.info(message, attributes);\n return;\n case 'warning':\n this.client.logger.warn(message, attributes);\n return;\n case 'error':\n this.client.logger.error(message, attributes);\n return;\n }\n } catch (error) {\n // Fall through to captureMessage if logger fails\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log via logger', { error });\n }\n }\n }\n\n // Fallback to captureMessage for compatibility\n // Additional build-time guard to prevent errors during static generation\n if (typeof this.client.captureMessage !== 'function') {\n // During build/static generation, Sentry client may not be properly initialized\n // Fall back to logging in development\n if (process.env.NODE_ENV === 'development') {\n if (level === 'error') {\n logError(`[Sentry Fallback] ${message}`);\n } else if (level === 'warning') {\n logWarn(`[Sentry Fallback] ${message}`);\n } else {\n logDebug(`[Sentry Fallback] ${message}`);\n }\n }\n return;\n }\n\n // Map our log levels to Sentry severity levels\n const sentryLevel =\n level === 'warning'\n ? 'warning'\n : level === 'error'\n ? 'error'\n : level === 'debug'\n ? 'debug'\n : 'info';\n\n try {\n // Build capture context from ObservabilityContext\n const captureContext = context\n ? {\n level: sentryLevel,\n extra: context.extra ?? context,\n tags: context.tags,\n }\n : sentryLevel;\n\n this.client.captureMessage(message, captureContext);\n } catch (error) {\n // Graceful fallback if Sentry fails during build\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to capture message', { error });\n if (level === 'error') {\n logError(`[Sentry Fallback] ${message}`);\n } else if (level === 'warning') {\n logWarn(`[Sentry Fallback] ${message}`);\n } else {\n logDebug(`[Sentry Fallback] ${message}`);\n }\n }\n }\n }\n\n setUser(user: ObservabilityUser | null): void {\n if (!this.enabled || !this.client) return;\n this.client.setUser(user);\n }\n\n addBreadcrumb(breadcrumb: Breadcrumb): void {\n if (!this.enabled || !this.client) return;\n this.client.addBreadcrumb({\n ...breadcrumb,\n timestamp: breadcrumb.timestamp ?? Date.now() / 1000,\n });\n }\n\n withScope(callback: (scope: any) => void): void {\n if (!this.enabled || !this.client) return;\n this.client.withScope(callback);\n }\n\n /**\n * Start a new transaction\n */\n startTransaction(\n context: TransactionContext,\n customSamplingContext?: any,\n ): Transaction | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.startTransaction) {\n return this.client.startTransaction(context, customSamplingContext);\n }\n\n // Fallback for older versions\n logWarn('startTransaction not available in this Sentry version');\n return undefined;\n }\n\n /**\n * Start a new span\n */\n startSpan(context: SpanContext): Span | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.startSpan) {\n return this.client.startSpan(context);\n }\n\n // Try to create span from active transaction\n const transaction = this.getActiveTransaction();\n if (transaction?.startChild) {\n return transaction.startChild(context);\n }\n\n return undefined;\n }\n\n /**\n * Get the currently active transaction\n */\n getActiveTransaction(): Transaction | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.getActiveTransaction) {\n return this.client.getActiveTransaction();\n }\n\n // Try to get from current scope\n if (this.client.getCurrentScope) {\n const scope = this.client.getCurrentScope();\n if (scope?.getTransaction) {\n return scope.getTransaction();\n }\n }\n\n return undefined;\n }\n\n /**\n * Configure the current scope\n */\n configureScope(callback: (scope: Scope) => void): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.configureScope) {\n this.client.configureScope(callback);\n } else if (this.client.withScope) {\n // Fallback using withScope\n this.client.withScope(callback);\n }\n }\n\n /**\n * Get the current hub instance\n */\n getCurrentHub(): Hub | undefined {\n if (!this.enabled || !this.client) return undefined;\n\n if (this.client.getCurrentHub) {\n return this.client.getCurrentHub();\n }\n\n return undefined;\n }\n\n /**\n * Set a measurement on the active transaction\n */\n setMeasurement(name: string, value: number, unit?: string): void {\n if (!this.enabled || !this.client) return;\n\n const transaction = this.getActiveTransaction();\n if (transaction?.setMeasurement) {\n transaction.setMeasurement(name, value, unit);\n }\n }\n\n /**\n * Add performance entries as breadcrumbs and measurements\n */\n addPerformanceEntries(\n entries: Array<{\n entryType: string;\n name: string;\n startTime: number;\n duration: number;\n [key: string]: unknown;\n }>,\n ): void {\n if (!this.enabled || !this.client) return;\n\n const transaction = this.getActiveTransaction();\n\n entries.forEach(entry => {\n // Add as breadcrumb for context\n this.addBreadcrumb({\n category: 'performance',\n message: `${entry.entryType}: ${entry.name}`,\n data: {\n name: entry.name,\n duration: entry.duration,\n startTime: entry.startTime,\n ...(entry.entryType === 'navigation' && {\n transferSize: (entry as { transferSize?: number }).transferSize,\n encodedBodySize: (entry as { encodedBodySize?: number }).encodedBodySize,\n decodedBodySize: (entry as { decodedBodySize?: number }).decodedBodySize,\n }),\n ...(entry.entryType === 'resource' && {\n initiatorType: (entry as { initiatorType?: string }).initiatorType,\n transferSize: (entry as { transferSize?: number }).transferSize,\n }),\n },\n });\n\n // Add measurements for key metrics\n if (transaction && entry.entryType === 'navigation') {\n const navEntry = entry as unknown as {\n responseStart?: number;\n fetchStart?: number;\n domInteractive?: number;\n domComplete?: number;\n loadEventEnd?: number;\n transferSize?: number;\n encodedBodySize?: number;\n decodedBodySize?: number;\n [key: string]: unknown;\n };\n\n // Core Web Vitals and other metrics\n const fetchStart = navEntry.fetchStart ?? 0;\n if (navEntry.responseStart !== undefined) {\n this.setMeasurement('fcp', navEntry.responseStart - fetchStart, 'millisecond');\n }\n if (navEntry.domInteractive !== undefined) {\n this.setMeasurement(\n 'dom_interactive',\n navEntry.domInteractive - fetchStart,\n 'millisecond',\n );\n }\n if (navEntry.domComplete !== undefined) {\n this.setMeasurement('dom_complete', navEntry.domComplete - fetchStart, 'millisecond');\n }\n if (navEntry.loadEventEnd !== undefined) {\n this.setMeasurement('load_event_end', navEntry.loadEventEnd - fetchStart, 'millisecond');\n }\n }\n });\n }\n\n /**\n * Record a Web Vital measurement\n */\n recordWebVital(\n name: 'FCP' | 'LCP' | 'FID' | 'CLS' | 'TTFB' | 'INP' | string,\n value: number,\n options?: {\n unit?: string;\n rating?: 'good' | 'needs-improvement' | 'poor';\n },\n ): void {\n if (!this.enabled || !this.client) return;\n\n const { unit = 'millisecond', rating } = options ?? {};\n const transaction = this.getActiveTransaction();\n\n if (transaction) {\n // Set the measurement\n transaction.setMeasurement(name.toLowerCase(), value, unit);\n\n // Add rating as tag if provided\n if (rating) {\n transaction.setTag(`webvital.${name.toLowerCase()}.rating`, rating);\n }\n\n // Also send as a standalone event for monitoring\n this.client.captureMessage(`Web Vital: ${name}`, {\n level: 'info',\n tags: {\n 'webvital.name': name,\n 'webvital.value': value,\n 'webvital.unit': unit,\n ...(rating && { 'webvital.rating': rating }),\n },\n contexts: {\n trace: {\n trace_id: transaction.traceId,\n span_id: transaction.spanId,\n },\n },\n });\n }\n }\n\n /**\n * Create a custom performance mark\n */\n mark(name: string, options?: { detail?: any }): void {\n if (!this.enabled) return;\n\n // Use Performance API if available\n if (typeof performance !== 'undefined' && performance.mark) {\n performance.mark(name, options);\n }\n\n // Also add as breadcrumb\n this.addBreadcrumb({\n category: 'performance.mark',\n message: name,\n data: options?.detail,\n timestamp: Date.now() / 1000,\n });\n }\n\n /**\n * Create a custom performance measure\n */\n measure(\n name: string,\n startMarkOrOptions?:\n | string\n | { start?: string; end?: string; duration?: number; detail?: unknown },\n endMark?: string,\n ): void {\n if (!this.enabled) return;\n\n // Use Performance API if available\n if (typeof performance !== 'undefined' && performance.measure) {\n if (typeof startMarkOrOptions === 'string') {\n performance.measure(name, startMarkOrOptions, endMark);\n } else if (startMarkOrOptions) {\n performance.measure(name, startMarkOrOptions);\n } else {\n // No options provided, create a simple measure\n performance.measure(name);\n }\n\n // Get the measure to record its duration\n const measures = performance.getEntriesByName(name, 'measure');\n const measure = measures[measures.length - 1];\n\n if (measure) {\n this.setMeasurement(name, measure.duration, 'millisecond');\n\n this.addBreadcrumb({\n category: 'performance.measure',\n message: name,\n data: {\n duration: measure.duration,\n startTime: measure.startTime,\n },\n timestamp: measure.startTime / 1000,\n });\n }\n }\n }\n\n /**\n * Log a trace message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Trace message to log\n * @param attributes - Optional attributes to include with the log\n */\n logTrace(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.trace) {\n try {\n this.client.logger.trace(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log trace', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'debug', attributes);\n }\n\n /**\n * Log a debug message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Debug message to log\n * @param attributes - Optional attributes to include with the log\n */\n logDebug(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.debug) {\n try {\n this.client.logger.debug(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log debug', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'debug', attributes);\n }\n\n /**\n * Log an info message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Info message to log\n * @param attributes - Optional attributes to include with the log\n */\n logInfo(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.info) {\n try {\n this.client.logger.info(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log info', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'info', attributes);\n }\n\n /**\n * Log a warning message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Warning message to log\n * @param attributes - Optional attributes to include with the log\n */\n logWarn(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.warn) {\n try {\n this.client.logger.warn(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log warn', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'warning', attributes);\n }\n\n /**\n * Log an error message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Error message to log\n * @param attributes - Optional attributes to include with the log\n */\n logError(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.error) {\n try {\n this.client.logger.error(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log error', { error });\n }\n }\n }\n\n // Fallback to captureMessage\n this.captureMessage(message, 'error', attributes);\n }\n\n /**\n * Log a fatal message using Sentry.logger (if available).\n * Falls back to captureMessage if logger is not available.\n *\n * @param message - Fatal message to log\n * @param attributes - Optional attributes to include with the log\n */\n logFatal(message: string, attributes?: Record<string, unknown>): void {\n if (!this.enabled || !this.client) return;\n\n if (this.client.logger?.fatal) {\n try {\n this.client.logger.fatal(message, attributes);\n return;\n } catch (error) {\n if (process.env.NODE_ENV === 'development') {\n logWarn('[Sentry Plugin] Failed to log fatal', { error });\n }\n }\n }\n\n // Fallback to captureMessage with error level\n this.captureMessage(message, 'error', attributes);\n }\n\n /**\n * Get the Sentry.logger instance if available.\n * This allows direct access to Sentry.logger APIs including fmt.\n *\n * @returns Sentry.logger instance or undefined if not available\n *\n * @example\n * ```typescript\n * const logger = sentryPlugin.getLogger();\n * if (logger) {\n * logger.info(logger.fmt`User ${user.id} logged in`);\n * }\n * ```\n */\n getLogger(): SentryClient['logger'] | undefined {\n if (!this.enabled || !this.client) return undefined;\n return this.client.logger;\n }\n\n async flush(timeout?: number): Promise<boolean> {\n if (!this.enabled || !this.client || !this.client.flush) return true;\n try {\n return await this.client.flush(timeout);\n } catch (_error) {\n return false;\n }\n }\n}\n\n/**\n * Factory function to create a Sentry plugin.\n *\n * Creates a configured SentryPlugin instance with optional configuration.\n * Auto-detects the appropriate Sentry package based on the environment.\n *\n * @param config - Optional Sentry plugin configuration\n * @returns SentryPlugin instance\n *\n * @example\n * ```typescript\n * const sentry = createSentryPlugin({\n * dsn: 'https://...',\n * environment: 'production',\n * tracesSampleRate: 0.1,\n * });\n * ```\n */\nexport const createSentryPlugin = <T extends SentryClient = SentryClient>(\n config?: SentryPluginConfig,\n): SentryPlugin<T> => {\n return new SentryPlugin<T>(config);\n};\n","/**\n * @fileoverview Next.js client-specific observability export\n * Next.js client-specific observability export\n */\n\nimport { env } from '../env';\n\nimport { ObservabilityBuilder } from './factory/builder';\nimport { createBetterStackPlugin } from './plugins/betterstack';\nimport { env as betterStackEnv } from './plugins/betterstack/env';\nimport { createConsolePlugin } from './plugins/console';\nimport { createSentryPlugin } from './plugins/sentry';\nimport { env as sentryEnv } from './plugins/sentry/env';\nimport { shouldEnableConsole } from './shared';\n\nimport type { ObservabilityManager } from './core/manager';\n\n/**\n * Create auto-configured observability for Next.js client\n */\nexport async function createClientObservability() {\n const builder = ObservabilityBuilder.create();\n\n // Console logging control using shared utility\n const enableConsole = shouldEnableConsole(\n env.NEXT_PUBLIC_NODE_ENV,\n env.NEXT_PUBLIC_OBSERVABILITY_CONSOLE_ENABLED,\n env.NEXT_PUBLIC_OBSERVABILITY_DEBUG,\n );\n\n // Always add console plugin, control via enabled flag\n builder.withPlugin(\n createConsolePlugin({\n prefix: '[Next.js Client]',\n enabled: enableConsole,\n }),\n );\n\n // Auto-activate Sentry if client DSN is provided\n if (sentryEnv.NEXT_PUBLIC_SENTRY_DSN) {\n builder.withPlugin(\n createSentryPlugin({\n dsn: sentryEnv.NEXT_PUBLIC_SENTRY_DSN,\n }),\n );\n }\n\n // Auto-activate Better Stack if client token is provided\n const clientBetterStackToken =\n betterStackEnv.NEXT_PUBLIC_BETTER_STACK_SOURCE_TOKEN ??\n betterStackEnv.NEXT_PUBLIC_BETTERSTACK_TOKEN ??\n betterStackEnv.NEXT_PUBLIC_LOGTAIL_TOKEN;\n\n if (clientBetterStackToken) {\n builder.withPlugin(\n createBetterStackPlugin({\n sourceToken: clientBetterStackToken,\n }),\n );\n }\n\n return builder.build();\n}\n\n// Lazy initialization for the observability instance using promise-based singleton\nlet initializationPromise: Promise<ObservabilityManager> | null = null;\n\n/**\n * Get or create the observability instance\n * Uses promise-based singleton pattern to prevent race conditions in concurrent scenarios\n * @returns Promise resolving to the ObservabilityManager instance\n */\nexport async function getObservability(): Promise<ObservabilityManager> {\n if (!initializationPromise) {\n initializationPromise = (async () => {\n try {\n return await createClientObservability();\n } catch (error) {\n // Reset cached promise on failure so callers can retry\n initializationPromise = null;\n throw error;\n }\n })();\n\n // Set promise for React 19 hooks (dynamic import to avoid circular dependency)\n void (async () => {\n try {\n const { setObservabilityPromise } = await import('./hooks/useObservability');\n const promise = initializationPromise;\n if (promise !== null) {\n setObservabilityPromise(promise);\n }\n } catch {\n // Hooks module not available or import failed - continue without hooks\n }\n })();\n }\n return initializationPromise;\n}\n\n// Export types and utilities\nexport * from './core/types';\nexport { createObservability } from './factory';\nexport { ObservabilityBuilder } from './factory/builder';\n\n// Re-export plugins for direct access (excluding conflicting exports)\nexport { BetterStackPlugin } from './plugins/betterstack';\nexport { ConsolePlugin } from './plugins/console';\nexport { SentryPlugin } from './plugins/sentry';\nexport { SentryMicroFrontendPlugin } from './plugins/sentry-microfrontend';\n\n// Re-export plugin-specific types with aliases to avoid conflicts\nexport type { Env as BetterStackEnv, BetterStackPluginConfig } from './plugins/betterstack';\nexport type { ConsolePluginConfig } from './plugins/console';\nexport type { Env as SentryEnv, SentryPluginConfig } from './plugins/sentry';\nexport type {\n BackstageAppConfig,\n MicroFrontendMode,\n SentryMicroFrontendConfig,\n} from './plugins/sentry-microfrontend';\n\n// Legacy function for backward compatibility (no-op)\n/**\n * @deprecated Configuration now happens through the observability system\n */\nexport const configureLogger = () => {\n // No-op: Configuration now happens through the observability system\n};\n\n// Re-export type\nexport type LogContext = Record<string, any>;\n","/**\n * @fileoverview Next.js Client Components for Analytics\n *\n * React components for integrating analytics into Next.js applications.\n * Provides provider components, tracked UI elements, and higher-order\n * components for automatic event tracking.\n *\n * **Components**:\n * - `AnalyticsProvider`: Provider component for App Router\n * - `TrackedButton`: Button component with automatic click tracking\n * - `TrackedLink`: Link component with automatic click tracking\n * - `withViewTracking`: HOC for tracking component views\n *\n * **Note**: This file uses Next.js hooks. For framework-agnostic components,\n * use the base components or accept navigation functions as parameters.\n *\n * @module @od-oneapp/analytics/client/next/components\n */\n\n'use client';\n\nimport { useCallback, useEffect, useRef } from 'react';\n\nimport type { Route } from 'next';\n\nimport { createClientObservability } from '@od-oneapp/observability/client/next';\nimport { useRouter } from 'next/navigation';\n\nimport { usePageTracking, useTrackEvent } from './hooks';\nimport { createNextJSClientAnalytics } from './manager';\nimport { getGlobalAnalytics, setGlobalAnalytics } from './state';\n\nimport type { AnalyticsConfig, Properties } from '../../shared/types/types';\nimport type { ObservabilityClient } from '@od-oneapp/observability/client/next';\n\n// Global logger instance (from @od-oneapp/observability)\n// Using minimal interface for optional fallback error logging\n\nlet logger: ObservabilityClient | null = null;\n\n/**\n * Analytics provider component for App Router.\n *\n * @remarks\n * Wraps your application and provides analytics context to all child components.\n * Automatically initializes analytics and optionally tracks page views.\n *\n * @param props - Component props\n * @param props.children - React children to wrap\n * @param props.config - Analytics configuration\n * @param props.autoPageTracking - Whether to automatically track page views (default: true)\n * @param props.pageTrackingOptions - Options for page tracking\n *\n * @example\n * ```tsx\n * export default function RootLayout({ children }) {\n * return (\n * <AnalyticsProvider\n * config={{\n * providers: {\n * http: { options: { endpoint: process.env.NEXT_PUBLIC_ANALYTICS_ENDPOINT! } }\n * }\n * }}\n * autoPageTracking={true}\n * >\n * {children}\n * </AnalyticsProvider>\n * );\n * }\n * ```\n */\nexport function AnalyticsProvider({\n autoPageTracking = true,\n children,\n config,\n pageTrackingOptions,\n}: {\n children: React.ReactNode;\n config: AnalyticsConfig;\n autoPageTracking?: boolean;\n pageTrackingOptions?: Parameters<typeof usePageTracking>[0];\n}) {\n // Initialize analytics\n useEffect(() => {\n if (!getGlobalAnalytics()) {\n const initAnalytics = async () => {\n try {\n // Initialize logger if not already initialized\n logger ??= await createClientObservability();\n\n const instance = await createNextJSClientAnalytics(config);\n setGlobalAnalytics(instance);\n } catch (error) {\n if (logger) {\n logger.captureException(error, {\n message: 'Failed to initialize analytics',\n });\n }\n }\n };\n void initAnalytics();\n }\n }, [config]);\n\n // Auto page tracking\n usePageTracking(autoPageTracking ? pageTrackingOptions : { skip: true });\n\n return children as React.ReactElement;\n}\n\n/**\n * Button component with automatic click tracking.\n *\n * @remarks\n * Wraps a standard button element and automatically tracks click events\n * when the button is clicked.\n *\n * @param props - Button props plus tracking props\n * @param props.eventName - Name of the event to track\n * @param props.properties - Additional properties to include in the event\n * @param props.onClick - Optional click handler (tracking happens before this)\n *\n * @example\n * ```tsx\n * <TrackedButton\n * eventName=\"Sign Up Clicked\"\n * properties={{ location: 'header', variant: 'primary' }}\n * onClick={() => router.push('/signup')}\n * >\n * Sign Up\n * </TrackedButton>\n * ```\n */\nexport function TrackedButton({\n children,\n eventName,\n onClick,\n properties,\n ...props\n}: React.ButtonHTMLAttributes<HTMLButtonElement> & {\n eventName: string;\n properties?: Properties;\n}) {\n const track = useTrackEvent();\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n track(eventName, properties);\n onClick?.(e);\n },\n [track, eventName, properties, onClick],\n );\n\n return (\n <button type=\"button\" {...props} onClick={handleClick}>\n {children}\n </button>\n );\n}\n\n/**\n * Link component with automatic click tracking.\n *\n * @remarks\n * Wraps a standard anchor element and automatically tracks click events\n * when the link is clicked. Also handles internal navigation for Next.js.\n *\n * @param props - Anchor props plus tracking props\n * @param props.eventName - Name of the event to track\n * @param props.properties - Additional properties to include in the event\n * @param props.href - Link URL\n * @param props.onClick - Optional click handler (tracking happens before this)\n *\n * @example\n * ```tsx\n * <TrackedLink\n * href=\"/products\"\n * eventName=\"Product Link Clicked\"\n * properties={{ linkText: 'View Products' }}\n * >\n * View Products\n * </TrackedLink>\n * ```\n */\nexport function TrackedLink({\n children,\n eventName,\n href,\n onClick,\n properties,\n ...props\n}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {\n eventName: string;\n properties?: Properties;\n}) {\n const track = useTrackEvent();\n const router = useRouter();\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n // Track the event\n const enhancedProperties = {\n ...properties,\n href,\n link_text: typeof children === 'string' ? children : undefined,\n };\n track(eventName, enhancedProperties);\n\n // Handle navigation\n if (onClick) {\n onClick(e);\n } else if (href && !props.target && href.startsWith('/')) {\n // Internal navigation\n e.preventDefault();\n router.push(href as Route);\n }\n },\n [track, eventName, properties, href, onClick, router, children, props.target],\n );\n\n return (\n <a {...props} href={href} onClick={handleClick}>\n {children}\n </a>\n );\n}\n\n/**\n * Higher-order component for tracking component views.\n *\n * @remarks\n * Wraps a component and automatically tracks a view event when the component\n * is first rendered. Useful for tracking page sections or feature usage.\n *\n * @param Component - The component to wrap\n * @param eventName - Name of the event to track\n * @param getProperties - Optional function to extract properties from component props\n * @returns Wrapped component with automatic view tracking\n *\n * @example\n * ```tsx\n * const TrackedDashboard = withViewTracking(\n * Dashboard,\n * 'Dashboard Viewed',\n * (props) => ({ userId: props.userId, plan: props.plan })\n * );\n * ```\n */\nexport function withViewTracking<P extends object>(\n Component: React.ComponentType<P>,\n eventName: string,\n getProperties?: (props: P) => Properties,\n) {\n return function TrackedComponent(props: P) {\n const track = useTrackEvent();\n const tracked = useRef(false);\n\n useEffect(() => {\n if (!tracked.current) {\n tracked.current = true;\n const properties = getProperties ? getProperties(props) : {};\n track(eventName, properties);\n }\n }, [track, props]);\n\n return <Component {...props} />;\n };\n}\n","/**\n * @fileoverview Next.js client exports\n *\n * This module provides Next.js-specific client-side analytics functionality.\n * It exports:\n *\n * - **Analytics Managers**: `createNextJSClientAnalytics()`, `createNextJSClientAnalyticsUninitialized()`\n * - **React Hooks**: `useAnalytics()`, `usePageTracking()`, `useTrackEvent()`, `useIdentifyUser()`\n * - **React Components**: `AnalyticsProvider`, `TrackedButton`, `TrackedLink`, `withViewTracking()`\n * - **Emitters**: Type-safe event tracking functions\n * - **Ecommerce Emitters**: Comprehensive ecommerce event tracking\n * - **AI Emitters**: AI product analytics tracking\n * - **Configuration**: Client-safe configuration utilities\n * - **PostHog Utilities**: Bootstrap data and cookie utilities\n *\n * **Usage**: Import from `@od-oneapp/analytics/client/next` for Next.js client components.\n *\n * @module @od-oneapp/analytics/client/next\n */\n\n'use client';\n\n// Export Next.js specific analytics manager\nexport {\n createNextJSClientAnalytics,\n createNextJSClientAnalyticsUninitialized,\n} from './client/next/manager';\n\n// Export Next.js hooks\nexport {\n resetAnalytics,\n useAnalytics,\n useIdentifyUser,\n usePageTracking,\n useTrackEvent,\n} from './client/next/hooks';\n\n// Export Next.js components\nexport {\n AnalyticsProvider,\n TrackedButton,\n TrackedLink,\n withViewTracking,\n} from './client/next/components';\n\n// Export all emitters - these are the preferred way to track events\nexport {\n // Emitter utilities\n ContextBuilder,\n EventBatch,\n PayloadBuilder,\n alias,\n createAnonymousSession,\n createUserSession,\n // Ecommerce emitters namespace\n ecommerce,\n group,\n // Core Segment.io spec emitters\n identify,\n isAliasPayload,\n isGroupPayload,\n isIdentifyPayload,\n isPagePayload,\n // Type guards\n isTrackPayload,\n page,\n screen,\n track,\n withMetadata,\n withUTM,\n} from './shared/emitters';\n\n// Export adapter utilities\nexport {\n createEmitterProcessor,\n // Emitter processing utilities\n processEmitterPayload,\n trackEcommerceEvent,\n} from './shared/utils/emitter-adapter';\n\n// Export client-safe configuration utilities\nexport {\n PROVIDER_REQUIREMENTS,\n createConfigBuilder,\n getAnalyticsConfig,\n validateConfig,\n} from './shared/utils/config-client';\n\n// Validation utilities removed - validation should happen on the server side only\n// This follows the four-file export pattern to avoid importing server-only dependencies\n\n// Export PostHog utilities\nexport {\n createBootstrapData,\n createMinimalBootstrapData,\n generateDistinctId,\n getDistinctIdFromCookies,\n} from './shared/utils/posthog-bootstrap';\n\n// Export types\nexport type * from './types';\n"],"mappings":"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"}
package/client.d.mts CHANGED
@@ -1,12 +1,12 @@
1
- import { C as EmitterPagePayload, D as EmitterTrackPayload, S as EmitterOptions, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, g as EmitterContext, i as AnalyticsProvider, n as AnalyticsContext, p as EmitterAliasPayload, r as AnalyticsManager, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload } from "./types-BxBnNQ0V.mjs";
2
- import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-DldkVSPp.mjs";
3
- import { a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, i as getDistinctIdFromCookies, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload } from "./posthog-bootstrap-DWxFrxlt.mjs";
4
- import { d as EcommerceEventSpec, m as OrderProperties, p as ExtendedProductProperties, r as CartProperties, t as BaseProductProperties } from "./types-CBvxUEaF.mjs";
5
- import { t as index_d_exports$1 } from "./index-jPzXRn52.mjs";
6
- import { t as index_d_exports } from "./index-BkIWe--N.mjs";
7
- import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-DPS6bSYo.mjs";
8
- import { a as ConsoleConfig, c as PostHogConfig, i as SegmentOptions, l as PostHogOptions, n as VercelOptions, o as ConsoleOptions, r as SegmentConfig, s as BootstrapData, t as VercelConfig } from "./vercel-types-lwakUfoI.mjs";
9
- import { n as createAnalyticsManager, t as AnalyticsManager$1 } from "./manager-DvRRjza6.mjs";
1
+ import { C as EmitterPagePayload, D as EmitterTrackPayload, S as EmitterOptions, b as EmitterIdentifyPayload, c as ProviderConfig, d as TrackingOptions, g as EmitterContext, i as AnalyticsProvider, n as AnalyticsContext, p as EmitterAliasPayload, r as AnalyticsManager, t as AnalyticsConfig, u as ProviderRegistry, v as EmitterGroupPayload, w as EmitterPayload } from "./types-cMMfHIpi.mjs";
2
+ import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BDSsleo_.mjs";
3
+ import { a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, i as getDistinctIdFromCookies, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload } from "./posthog-bootstrap-Bu1BfhVv.mjs";
4
+ import { d as EcommerceEventSpec, m as OrderProperties, p as ExtendedProductProperties, r as CartProperties, t as BaseProductProperties } from "./types-DEcTnnFe.mjs";
5
+ import { t as index_d_exports$1 } from "./index-BWhDEs8u.mjs";
6
+ import { t as index_d_exports } from "./index-Cp-N57Zb.mjs";
7
+ import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-Ciu7O6n1.mjs";
8
+ import { a as ConsoleConfig, c as PostHogConfig, i as SegmentOptions, l as PostHogOptions, n as VercelOptions, o as ConsoleOptions, r as SegmentConfig, s as BootstrapData, t as VercelConfig } from "./vercel-types-oM7Sn385.mjs";
9
+ import { n as createAnalyticsManager, t as AnalyticsManager$1 } from "./manager-OJpSKwqb.mjs";
10
10
 
11
11
  //#region src/client/manager.d.ts
12
12
  declare function createClientAnalytics(config: AnalyticsConfig): Promise<AnalyticsManager>;
package/client.mjs CHANGED
@@ -1,121 +1,13 @@
1
- import { t as ConsoleProvider } from "./console-8bND3mMU.mjs";
1
+ import { t as ConsoleProvider } from "./console-BpU88FNF.mjs";
2
2
  import { HttpClientProvider } from "./providers-http-client.mjs";
3
- import { _ as AnalyticsManager, a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, i as getDistinctIdFromCookies, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload, v as createAnalyticsManager } from "./posthog-bootstrap-CYfIy_WS.mjs";
4
- import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-6-nKo8i-.mjs";
5
- import { t as ecommerce_exports } from "./ecommerce-Cgu4wlux.mjs";
6
- import { t as ai_exports } from "./ai-YMnynb-t.mjs";
7
- import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-P6P5adJg.mjs";
3
+ import { _ as AnalyticsManager, a as ContextBuilder, c as createAnonymousSession, d as isGroupPayload, f as isIdentifyPayload, g as withUTM, h as withMetadata, i as getDistinctIdFromCookies, l as createUserSession, m as isTrackPayload, n as createMinimalBootstrapData, o as EventBatch, p as isPagePayload, r as generateDistinctId, s as PayloadBuilder, t as createBootstrapData, u as isAliasPayload, v as createAnalyticsManager } from "./posthog-bootstrap-DkPdn-hA.mjs";
4
+ import { a as screen, i as page, n as group, o as track, r as identify, t as alias } from "./emitters-BvEelkxS.mjs";
5
+ import { t as ecommerce_exports } from "./ecommerce-DGG1FbiH.mjs";
6
+ import { t as ai_exports } from "./ai-Co8hBoEj.mjs";
7
+ import { a as createEmitterProcessor, i as validateConfig, n as createConfigBuilder, o as processEmitterPayload, r as getAnalyticsConfig, s as trackEcommerceEvent, t as PROVIDER_REQUIREMENTS } from "./config-6Mwe7b2O.mjs";
8
+ import { SegmentClientProvider } from "@od-oneapp/integration-segment/analytics-provider/client";
9
+ import { VercelClientProvider } from "@od-oneapp/integration-vercel/analytics-provider/client";
8
10
 
9
- //#region ../../integrations/segment/src/analytics-provider/client.ts
10
- var SegmentClientProvider = class {
11
- name = "segment";
12
- analytics = null;
13
- config;
14
- isInitialized = false;
15
- constructor(config) {
16
- if (!config.writeKey) throw new Error("Segment writeKey is required");
17
- this.config = {
18
- options: config.options,
19
- writeKey: config.writeKey
20
- };
21
- }
22
- async initialize() {
23
- if (this.isInitialized) return;
24
- const { AnalyticsBrowser } = await import(
25
- /* webpackChunkName: "segment-analytics-browser" */
26
- "@segment/analytics-next"
27
- );
28
- this.analytics = AnalyticsBrowser.load({
29
- writeKey: this.config.writeKey,
30
- ...this.config.options
31
- });
32
- this.isInitialized = true;
33
- }
34
- async track(event, properties = {}, _context) {
35
- if (!this.analytics) return;
36
- await this.analytics.track(event, properties);
37
- }
38
- async identify(userId, traits = {}, _context) {
39
- if (!this.analytics) return;
40
- await this.analytics.identify(userId, traits);
41
- }
42
- async page(name, properties = {}, _context) {
43
- if (!this.analytics) return;
44
- await this.analytics.page(name, properties);
45
- }
46
- async group(groupId, traits = {}, _context) {
47
- if (!this.analytics) return;
48
- await this.analytics.group(groupId, traits);
49
- }
50
- async alias(userId, previousId, _context) {
51
- if (!this.analytics) return;
52
- await this.analytics.alias(userId, previousId);
53
- }
54
- };
55
-
56
- //#endregion
57
- //#region ../../integrations/vercel/src/analytics-provider/client.ts
58
- /**
59
- * Converts internal Properties type to Vercel Analytics format.
60
- * Vercel Analytics requires Record<string, string | number | boolean>.
61
- */
62
- function normalizePropertiesToVercel(properties) {
63
- if (!properties) return {};
64
- const normalized = {};
65
- for (const [key, value] of Object.entries(properties)) if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") normalized[key] = value;
66
- return normalized;
67
- }
68
- var VercelClientProvider = class {
69
- name = "vercel";
70
- config;
71
- isInitialized = false;
72
- constructor(config) {
73
- this.config = { options: config.options };
74
- }
75
- async initialize() {
76
- if (this.isInitialized) return;
77
- try {
78
- const { inject } = await import("@vercel/analytics");
79
- inject(this.config.options);
80
- this.isInitialized = true;
81
- } catch {
82
- throw new Error("Vercel Analytics not available. Install with: npm install @vercel/analytics");
83
- }
84
- }
85
- async track(event, properties = {}) {
86
- if (!this.isInitialized) return;
87
- try {
88
- const { track } = await import("@vercel/analytics");
89
- track(event, normalizePropertiesToVercel(properties));
90
- } catch {}
91
- }
92
- async identify(userId, traits = {}) {
93
- await this.track("User Identified", {
94
- userId,
95
- ...traits
96
- });
97
- }
98
- async page(name, properties = {}) {
99
- if (name || Object.keys(properties).length > 0) await this.track("Page View", {
100
- page: name,
101
- ...properties
102
- });
103
- }
104
- async group(groupId, traits = {}) {
105
- await this.track("Group Identified", {
106
- groupId,
107
- ...traits
108
- });
109
- }
110
- async alias(userId, previousId) {
111
- await this.track("User Aliased", {
112
- previousId,
113
- userId
114
- });
115
- }
116
- };
117
-
118
- //#endregion
119
11
  //#region src/client/manager.ts
120
12
  /**
121
13
  * @fileoverview Client Analytics Manager