UNPKG

cosmic-analytics

Version:

Lightweight analytics for Cosmic projects

1 lines 24.2 kB
{"version":3,"sources":["../src/client/useCosmicAnalytics.ts","../src/lib/utils.ts","../src/lib/analytics.ts","../src/client/CosmicAnalyticsProvider.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\nimport { usePathname } from 'next/navigation';\nimport type { AnalyticsConfig } from '../types';\nimport { CosmicAnalytics } from '../lib/analytics';\n\nlet analyticsInstance: CosmicAnalytics | null = null;\n\n/**\n * Initialize the analytics instance\n */\nexport function initAnalytics(config?: AnalyticsConfig): CosmicAnalytics {\n if (!analyticsInstance) {\n analyticsInstance = new CosmicAnalytics(config);\n }\n return analyticsInstance;\n}\n\n/**\n * Get the current analytics instance\n */\nexport function getAnalytics(): CosmicAnalytics | null {\n return analyticsInstance;\n}\n\n/**\n * React hook for Cosmic Analytics with Next.js App Router\n */\nexport function useCosmicAnalytics(config?: AnalyticsConfig) {\n const pathname = usePathname();\n const initializedRef = useRef(false);\n const prevUrlRef = useRef<string | null>(null);\n\n useEffect(() => {\n // Initialize analytics on first render\n if (!initializedRef.current) {\n initAnalytics(config);\n initializedRef.current = true;\n }\n\n const analytics = getAnalytics();\n if (!analytics) return;\n\n // Track page view when URL changes\n // We use window.location.href to get the full URL including search params\n // This avoids needing useSearchParams which requires Suspense\n const currentUrl = typeof window !== 'undefined' ? window.location.href : pathname;\n \n if (prevUrlRef.current !== currentUrl) {\n analytics.trackPageView();\n prevUrlRef.current = currentUrl;\n }\n\n // Cleanup function to track page exit\n return () => {\n analytics.trackPageExit();\n };\n }, [pathname, config]);\n} ","import type { DeviceInfo } from '../types';\n\n/**\n * Generate a unique session ID\n */\nexport function generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\n/**\n * Check if running in browser environment\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if Do Not Track is enabled\n */\nexport function isDoNotTrackEnabled(): boolean {\n if (!isBrowser()) return false;\n \n const { doNotTrack, navigator } = window as any;\n const dnt = doNotTrack || navigator.doNotTrack || navigator.msDoNotTrack;\n \n return dnt === '1' || dnt === 'yes';\n}\n\n/**\n * Parse user agent to extract device information\n */\nexport function parseUserAgent(userAgent: string): DeviceInfo {\n const ua = userAgent.toLowerCase();\n \n // Detect device type\n let type: 'desktop' | 'mobile' | 'tablet' = 'desktop';\n if (/tablet|ipad|playbook|silk/i.test(ua)) {\n type = 'tablet';\n } else if (/mobile|iphone|ipod|android|blackberry|opera|mini|windows\\sce|palm|smartphone|iemobile/i.test(ua)) {\n type = 'mobile';\n }\n \n // Detect OS\n let os = 'Unknown';\n if (/windows nt 10/i.test(ua)) os = 'Windows 10';\n else if (/windows nt 6.3/i.test(ua)) os = 'Windows 8.1';\n else if (/windows nt 6.2/i.test(ua)) os = 'Windows 8';\n else if (/windows nt 6.1/i.test(ua)) os = 'Windows 7';\n else if (/windows/i.test(ua)) os = 'Windows';\n else if (/android/i.test(ua)) os = 'Android';\n else if (/iphone|ipad|ipod/i.test(ua)) os = 'iOS';\n else if (/mac os x/i.test(ua)) os = 'macOS';\n else if (/linux/i.test(ua)) os = 'Linux';\n else if (/chromeos/i.test(ua)) os = 'Chrome OS';\n \n // Detect browser\n let browser = 'Unknown';\n let browserVersion = '';\n \n if (/edg\\//i.test(ua)) {\n browser = 'Edge';\n const match = ua.match(/edg\\/(\\d+(\\.\\d+)*)/);\n if (match) browserVersion = match[1];\n } else if (/chrome|crios/i.test(ua) && !/edg/i.test(ua)) {\n browser = 'Chrome';\n const match = ua.match(/chrome\\/(\\d+(\\.\\d+)*)/);\n if (match) browserVersion = match[1];\n } else if (/firefox|fxios/i.test(ua)) {\n browser = 'Firefox';\n const match = ua.match(/firefox\\/(\\d+(\\.\\d+)*)/);\n if (match) browserVersion = match[1];\n } else if (/safari/i.test(ua) && !/chrome|crios/i.test(ua)) {\n browser = 'Safari';\n const match = ua.match(/version\\/(\\d+(\\.\\d+)*)/);\n if (match) browserVersion = match[1];\n } else if (/opera|opr/i.test(ua)) {\n browser = 'Opera';\n const match = ua.match(/(?:opera|opr)\\/(\\d+(\\.\\d+)*)/);\n if (match) browserVersion = match[1];\n }\n \n return { type, os, browser, browserVersion };\n}\n\n/**\n * Get viewport dimensions\n */\nexport function getViewport(): string {\n if (!isBrowser()) return '';\n return `${window.innerWidth}x${window.innerHeight}`;\n}\n\n/**\n * Get screen resolution\n */\nexport function getScreenResolution(): string {\n if (!isBrowser()) return '';\n return `${window.screen.width}x${window.screen.height}`;\n}\n\n/**\n * Get referrer source\n */\nexport function getReferrerSource(referrer: string): string {\n if (!referrer || referrer === '') return 'direct';\n \n try {\n const url = new URL(referrer);\n const hostname = url.hostname.replace('www.', '');\n \n // Common social media platforms\n if (hostname.includes('facebook.com') || hostname.includes('fb.com')) return 'facebook';\n if (hostname.includes('twitter.com') || hostname.includes('t.co')) return 'twitter';\n if (hostname.includes('linkedin.com')) return 'linkedin';\n if (hostname.includes('instagram.com')) return 'instagram';\n if (hostname.includes('youtube.com')) return 'youtube';\n if (hostname.includes('reddit.com')) return 'reddit';\n \n // Search engines\n if (hostname.includes('google.')) return 'google';\n if (hostname.includes('bing.com')) return 'bing';\n if (hostname.includes('yahoo.')) return 'yahoo';\n if (hostname.includes('duckduckgo.com')) return 'duckduckgo';\n if (hostname.includes('baidu.com')) return 'baidu';\n \n return hostname;\n } catch {\n return 'invalid';\n }\n}\n\n/**\n * Debounce function\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n \n return function (...args: Parameters<T>) {\n if (timeout) clearTimeout(timeout);\n timeout = setTimeout(() => func(...args), wait);\n };\n}\n\n/**\n * Safe JSON parse\n */\nexport function safeJsonParse<T>(json: string, fallback: T): T {\n try {\n return JSON.parse(json);\n } catch {\n return fallback;\n }\n} ","import type { AnalyticsConfig, AnalyticsEvent, PageViewEvent, SessionData } from '../types';\nimport {\n generateSessionId,\n isBrowser,\n isDoNotTrackEnabled,\n getViewport,\n getScreenResolution,\n safeJsonParse,\n} from './utils';\n\nconst SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes\nconst SESSION_STORAGE_KEY = 'cosmic_analytics_session';\n\nexport class CosmicAnalytics {\n private projectId: string;\n private apiEndpoint: string;\n private config: AnalyticsConfig;\n private session: SessionData | null = null;\n private pageViewStart: number = 0;\n private isEnabled: boolean = true;\n private queue: AnalyticsEvent[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(config?: AnalyticsConfig) {\n // Merge default config with user config first\n this.config = {\n apiEndpoint: 'https://api.cosmic.new/analytics',\n debug: false,\n enabled: true,\n respectDoNotTrack: true,\n sendInDevelopment: false,\n ...config,\n };\n \n // Get project ID from config or environment variable\n this.projectId = this.config.projectId || this.getProjectId();\n \n this.apiEndpoint = this.config.apiEndpoint!;\n \n // Check if analytics should be enabled\n this.isEnabled = this.shouldEnableAnalytics();\n \n if (this.isEnabled && isBrowser()) {\n this.initializeSession();\n this.setupEventListeners();\n this.startFlushTimer();\n }\n }\n\n private getProjectId(): string {\n // Simply return empty string as fallback\n // The projectId should be provided via config from the React component\n return '';\n }\n\n private isDevelopmentMode(): boolean {\n // First check if isDevelopment is explicitly set in config\n if (typeof this.config.isDevelopment === 'boolean') {\n return this.config.isDevelopment;\n }\n \n // Check for Node.js environment (Next.js server-side)\n if (typeof (globalThis as any).process !== 'undefined') {\n return (globalThis as any).process.env?.NODE_ENV === 'development';\n }\n \n // Check for browser environment\n if (isBrowser()) {\n // Check Next.js runtime config\n if ((window as any).__NEXT_DATA__?.buildId === 'development') {\n return true;\n }\n \n // Fallback to checking hostname\n const hostname = window.location.hostname;\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname.includes('.local');\n }\n \n return false;\n }\n\n private shouldEnableAnalytics(): boolean {\n if (!this.config.enabled) return false;\n if (!this.projectId) {\n if (this.config.debug) {\n console.warn('Cosmic Analytics: NEXT_PUBLIC_CLIENT_ID not found');\n }\n return false;\n }\n \n // Check if we're in development mode and if sendInDevelopment is false (default)\n if (this.isDevelopmentMode() && !this.config.sendInDevelopment) {\n if (this.config.debug) {\n console.log('Cosmic Analytics: Disabled in development mode. Set sendInDevelopment: true to enable.');\n }\n return false;\n }\n \n // Respect Do Not Track if configured\n if (this.config.respectDoNotTrack && isDoNotTrackEnabled()) {\n if (this.config.debug) {\n console.log('Cosmic Analytics: Respecting Do Not Track preference');\n }\n return false;\n }\n \n return true;\n }\n\n private initializeSession(): void {\n const storedSession = this.getStoredSession();\n \n if (storedSession && this.isSessionValid(storedSession)) {\n this.session = storedSession;\n this.session.lastActivity = Date.now();\n } else {\n this.session = {\n id: generateSessionId(),\n startTime: Date.now(),\n pageViews: 0,\n lastActivity: Date.now(),\n };\n }\n \n this.saveSession();\n }\n\n private getStoredSession(): SessionData | null {\n if (!isBrowser()) return null;\n \n try {\n const stored = sessionStorage.getItem(SESSION_STORAGE_KEY);\n if (!stored) return null;\n \n return safeJsonParse<SessionData | null>(stored, null);\n } catch {\n return null;\n }\n }\n\n private isSessionValid(session: SessionData): boolean {\n const now = Date.now();\n return now - session.lastActivity < SESSION_TIMEOUT;\n }\n\n private saveSession(): void {\n if (!isBrowser() || !this.session) return;\n \n try {\n sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(this.session));\n } catch (error) {\n if (this.config.debug) {\n console.error('Cosmic Analytics: Failed to save session', error);\n }\n }\n }\n\n private setupEventListeners(): void {\n if (!isBrowser()) return;\n \n // Page visibility change\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n this.trackPageExit();\n this.flush(true);\n } else if (document.visibilityState === 'visible') {\n // Track a new page view when returning to the tab\n this.trackPageView();\n }\n });\n \n // Before unload\n window.addEventListener('beforeunload', () => {\n this.trackPageExit();\n this.flush(true);\n });\n }\n\n private startFlushTimer(): void {\n this.flushTimer = setInterval(() => {\n this.flush();\n }, 5000); // Flush every 5 seconds\n }\n\n private stopFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n private addToQueue(event: AnalyticsEvent): void {\n this.queue.push(event);\n \n // Flush immediately if queue is getting large\n if (this.queue.length >= 10) {\n this.flush();\n }\n }\n\n private async flush(forceSendNow = false): Promise<void> {\n if (this.queue.length === 0) return;\n \n const events = [...this.queue];\n this.queue = [];\n \n try {\n const response = await fetch(`${this.apiEndpoint}/track`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n keepalive: forceSendNow,\n });\n \n if (!response.ok && this.config.debug) {\n console.error('Cosmic Analytics: Failed to send events', response.status);\n // Re-add events to queue for retry\n this.queue.unshift(...events);\n }\n } catch (error) {\n if (this.config.debug) {\n console.error('Cosmic Analytics: Error sending events', error);\n }\n // Re-add events to queue for retry\n this.queue.unshift(...events);\n }\n }\n\n public trackPageView(overrides?: Partial<PageViewEvent>): void {\n if (!this.isEnabled || !isBrowser() || !this.session) return;\n \n this.pageViewStart = Date.now();\n this.session.pageViews++;\n this.session.lastActivity = Date.now();\n this.saveSession();\n \n const event: PageViewEvent = {\n event: 'pageview',\n projectId: this.projectId,\n sessionId: this.session.id,\n url: window.location.href,\n title: document.title,\n referrer: document.referrer || 'direct',\n timestamp: Date.now(),\n screenResolution: getScreenResolution(),\n viewport: getViewport(),\n language: navigator.language,\n userAgent: navigator.userAgent,\n ...overrides,\n };\n \n if (this.config.debug) {\n console.log('Cosmic Analytics: Page view', event);\n }\n \n this.addToQueue(event);\n }\n\n public trackPageExit(): void {\n if (!this.isEnabled || !isBrowser() || !this.session || !this.pageViewStart) return;\n \n const duration = Date.now() - this.pageViewStart;\n \n const event = {\n event: 'pageexit' as const,\n projectId: this.projectId,\n sessionId: this.session.id,\n url: window.location.href,\n duration,\n timestamp: Date.now(),\n };\n \n if (this.config.debug) {\n console.log('Cosmic Analytics: Page exit', event);\n }\n \n this.addToQueue(event);\n }\n\n public reset(): void {\n if (!isBrowser()) return;\n \n // Clear session\n this.session = null;\n sessionStorage.removeItem(SESSION_STORAGE_KEY);\n \n // Re-initialize with new session\n if (this.isEnabled) {\n this.initializeSession();\n }\n }\n\n public disable(): void {\n this.isEnabled = false;\n this.stopFlushTimer();\n this.queue = [];\n }\n\n public enable(): void {\n this.isEnabled = this.shouldEnableAnalytics();\n if (this.isEnabled && isBrowser()) {\n this.initializeSession();\n this.startFlushTimer();\n }\n }\n} ","'use client';\n\nimport React from 'react';\nimport type { AnalyticsConfig } from '../types';\nimport { useCosmicAnalytics } from './useCosmicAnalytics';\n\ninterface CosmicAnalyticsProviderProps {\n children: React.ReactNode;\n config?: AnalyticsConfig;\n}\n\n/**\n * Provider component for easy integration with Next.js layouts\n */\nexport function CosmicAnalyticsProvider({ \n children, \n config \n}: CosmicAnalyticsProviderProps) {\n // Read the environment variable here where Next.js can replace it\n const projectId = process.env.NEXT_PUBLIC_CLIENT_ID;\n const isDevelopment = process.env.NODE_ENV === 'development';\n \n // Merge the projectId with the provided config\n const mergedConfig: AnalyticsConfig = {\n projectId,\n isDevelopment,\n ...config,\n };\n \n useCosmicAnalytics(mergedConfig);\n \n return <>{children}</>;\n} "],"mappings":"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","names":["navigator"]}