@heartbeep/beeper
Version:
Modern JavaScript SDK for Heartbeep event tracking - beep beep!
1 lines • 10.7 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/react.tsx"],"names":["Heartbeep","config","apiUrl","item","data","payload","error","event","name","metadata","HeartbeepContext","createContext","HeartbeepProvider","children","siteId","debug","heartbeepRef","useRef","useEffect","contextValue","React","useHeartbeep","context","useContext","AutoPageview","pageview","handleRouteChange"],"mappings":"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","file":"react.mjs","sourcesContent":["import type {\n HeartbeepConfig,\n EventType,\n TrackEventData,\n TrackEventPayload,\n} from \"./types\";\n\nexport * from \"./types\";\n\nexport class Heartbeep {\n private config: HeartbeepConfig;\n private queue: Array<{ event: EventType; payload?: TrackEventPayload }> = [];\n private isReady = false;\n\n constructor(config: HeartbeepConfig) {\n if (!config.siteId) {\n throw new Error(\"[Heartbeep] siteId is required\");\n }\n\n // Build the API URL\n let apiUrl = config.apiUrl || 'https://heartbeep.live/api/beep/website';\n // Remove trailing slash\n apiUrl = apiUrl.replace(/\\/$/, '');\n // Append siteId if not already included\n if (!apiUrl.includes(config.siteId)) {\n apiUrl = `${apiUrl}/${config.siteId}`;\n }\n\n this.config = {\n ...config,\n apiUrl,\n debug: config.debug || false,\n };\n\n // Initialize when DOM is ready\n if (typeof window !== \"undefined\") {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => this.init());\n } else {\n this.init();\n }\n }\n }\n\n private init(): void {\n this.isReady = true;\n this.processQueue();\n\n if (this.config.debug) {\n console.log(\"[Heartbeep] Initialized with siteId:\", this.config.siteId);\n }\n }\n\n private processQueue(): void {\n while (this.queue.length > 0) {\n const item = this.queue.shift();\n if (item) {\n this.track(item.event, item.payload);\n }\n }\n }\n\n private async send(data: TrackEventData): Promise<void> {\n if (this.config.debug) {\n console.log(\"[Heartbeep] Tracking event:\", data);\n }\n\n try {\n const payload = JSON.stringify(data);\n\n // Try sendBeacon first for reliability\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n const sent = navigator.sendBeacon(this.config.apiUrl!, payload);\n if (sent) return;\n }\n\n // Fallback to fetch\n if (typeof fetch !== \"undefined\") {\n await fetch(this.config.apiUrl!, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: payload,\n keepalive: true,\n });\n }\n } catch (error) {\n if (this.config.debug) {\n console.error(\"[Heartbeep] Error tracking event:\", error);\n }\n }\n }\n\n track(event: EventType, payload?: TrackEventPayload): void {\n // Queue events if not ready\n if (!this.isReady) {\n this.queue.push({ event, payload });\n return;\n }\n\n // Skip tracking if running on server\n if (typeof window === \"undefined\") {\n return;\n }\n\n const data: TrackEventData = {\n event,\n name: payload?.name || document.title,\n url: window.location.href,\n timestamp: Date.now(),\n metadata: payload?.metadata,\n };\n\n this.send(data);\n }\n\n // Convenience method for pageview tracking\n pageview(name?: string): void {\n this.track(\"pageview\", { name });\n }\n\n // Convenience method for click tracking\n click(name: string, metadata?: Record<string, any>): void {\n this.track(\"click\", { name, metadata });\n }\n\n // Convenience method for purchase tracking\n purchase(name: string, metadata?: Record<string, any>): void {\n this.track(\"purchase\", { name, metadata });\n }\n}\n\n// Convenience beep function for quick tracking\nexport function beep(event: EventType, name?: string): void {\n console.log(`[Beeper] 🔔 ${event}: ${name || \"unnamed event\"}`);\n}\n","import React, { createContext, useContext, useEffect, useRef } from \"react\";\nimport { Heartbeep } from \"./index\";\nimport type { HeartbeepConfig, EventType, TrackEventPayload } from \"./types\";\n\ninterface HeartbeepContextValue {\n heartbeep: Heartbeep | null;\n track: (event: EventType, payload?: TrackEventPayload) => void;\n pageview: (name?: string) => void;\n click: (name: string, metadata?: Record<string, any>) => void;\n purchase: (name: string, metadata?: Record<string, any>) => void;\n}\n\nconst HeartbeepContext = createContext<HeartbeepContextValue | null>(null);\n\nexport interface HeartbeepProviderProps {\n children: React.ReactNode;\n siteId: string;\n apiUrl?: string;\n debug?: boolean;\n}\n\nexport function HeartbeepProvider({\n children,\n siteId,\n apiUrl,\n debug,\n}: HeartbeepProviderProps) {\n const heartbeepRef = useRef<Heartbeep | null>(null);\n\n useEffect(() => {\n if (typeof window !== \"undefined\" && !heartbeepRef.current) {\n const config: HeartbeepConfig = {\n siteId,\n apiUrl,\n debug,\n };\n heartbeepRef.current = new Heartbeep(config);\n }\n }, [siteId, apiUrl, debug]);\n\n const contextValue: HeartbeepContextValue = {\n heartbeep: heartbeepRef.current,\n track: (event, payload) => {\n heartbeepRef.current?.track(event, payload);\n },\n pageview: name => {\n heartbeepRef.current?.pageview(name);\n },\n click: (name, metadata) => {\n heartbeepRef.current?.click(name, metadata);\n },\n purchase: (name, metadata) => {\n heartbeepRef.current?.purchase(name, metadata);\n },\n };\n\n return (\n <HeartbeepContext.Provider value={contextValue}>\n {children}\n </HeartbeepContext.Provider>\n );\n}\n\nexport function useHeartbeep() {\n const context = useContext(HeartbeepContext);\n if (!context) {\n throw new Error(\"useHeartbeep must be used within a HeartbeepProvider\");\n }\n return context;\n}\n\n// Auto-track page views on route change\nexport function AutoPageview({ children }: { children?: React.ReactNode }) {\n const { pageview } = useHeartbeep();\n\n useEffect(() => {\n pageview();\n\n // Listen for route changes (works with Next.js and React Router)\n const handleRouteChange = () => pageview();\n\n window.addEventListener(\"popstate\", handleRouteChange);\n return () => window.removeEventListener(\"popstate\", handleRouteChange);\n }, [pageview]);\n\n return <>{children}</>;\n}\n"]}