@sonordev/site-kit 3.0.3 → 3.0.4
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.
- package/dist/AnalyticsProvider-MLT26JRP.mjs +6 -0
- package/dist/{AnalyticsProvider-UKF7ESSP.mjs.map → AnalyticsProvider-MLT26JRP.mjs.map} +1 -1
- package/dist/AnalyticsProvider-WTOGN7LV.js +27 -0
- package/dist/{AnalyticsProvider-N3RNQXTK.js.map → AnalyticsProvider-WTOGN7LV.js.map} +1 -1
- package/dist/analytics/index.d.mts +1 -0
- package/dist/analytics/index.d.ts +1 -0
- package/dist/analytics/index.js +18 -9
- package/dist/analytics/index.mjs +3 -2
- package/dist/chunk-3DPXOZAU.mjs +26 -0
- package/dist/chunk-3DPXOZAU.mjs.map +1 -0
- package/dist/{chunk-7DW4SXNG.js → chunk-3GCEFS73.js} +5 -5
- package/dist/{chunk-7DW4SXNG.js.map → chunk-3GCEFS73.js.map} +1 -1
- package/dist/{chunk-ZDLBI3XX.mjs → chunk-65SMJBHW.mjs} +7 -2
- package/dist/chunk-65SMJBHW.mjs.map +1 -0
- package/dist/{chunk-S34XAPW2.mjs → chunk-AN4ATCYQ.mjs} +8 -8
- package/dist/chunk-AN4ATCYQ.mjs.map +1 -0
- package/dist/{chunk-XIGNKCHQ.js → chunk-EBJ4S5DU.js} +8 -8
- package/dist/chunk-EBJ4S5DU.js.map +1 -0
- package/dist/chunk-HMFFAUCD.js +30 -0
- package/dist/chunk-HMFFAUCD.js.map +1 -0
- package/dist/{chunk-FLD5R2PT.js → chunk-IBDVZ6BF.js} +7 -2
- package/dist/{chunk-FLD5R2PT.js.map → chunk-IBDVZ6BF.js.map} +1 -1
- package/dist/{chunk-UZ63S7FE.mjs → chunk-KMZ527EM.mjs} +3 -3
- package/dist/{chunk-UZ63S7FE.mjs.map → chunk-KMZ527EM.mjs.map} +1 -1
- package/dist/{chunk-GBZHL2IT.js → chunk-NNZDHLXN.js} +3 -3
- package/dist/{chunk-GBZHL2IT.js.map → chunk-NNZDHLXN.js.map} +1 -1
- package/dist/{chunk-PAYGGILT.mjs → chunk-T4QBSRA4.mjs} +3 -3
- package/dist/{chunk-PAYGGILT.mjs.map → chunk-T4QBSRA4.mjs.map} +1 -1
- package/dist/client/index.d.mts +2 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +9 -0
- package/dist/client/index.mjs +1 -0
- package/dist/commerce/index.js +49 -48
- package/dist/commerce/index.mjs +4 -3
- package/dist/dispatch-Cto83LLT.d.mts +28 -0
- package/dist/dispatch-DRQGcM8K.d.ts +28 -0
- package/dist/index.js +29 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -3
- package/dist/index.mjs.map +1 -1
- package/dist/layout/client.js +2 -2
- package/dist/layout/client.mjs +1 -1
- package/dist/layout/index.js +2 -2
- package/dist/layout/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/AnalyticsProvider-N3RNQXTK.js +0 -26
- package/dist/AnalyticsProvider-UKF7ESSP.mjs +0 -5
- package/dist/chunk-S34XAPW2.mjs.map +0 -1
- package/dist/chunk-XIGNKCHQ.js.map +0 -1
- package/dist/chunk-ZDLBI3XX.mjs.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
import { registerAnalyticsDispatcher } from './chunk-3DPXOZAU.mjs';
|
|
2
3
|
import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-EE6SFAZP.mjs';
|
|
3
4
|
import { createContext, useRef, useEffect, useState, useCallback, useMemo, useContext } from 'react';
|
|
4
5
|
import { usePathname } from 'next/navigation';
|
|
@@ -992,6 +993,10 @@ function AnalyticsProvider({
|
|
|
992
993
|
};
|
|
993
994
|
doTrack();
|
|
994
995
|
}, [propApiUrl, propApiKey, pathname, debug]);
|
|
996
|
+
useEffect(() => {
|
|
997
|
+
registerAnalyticsDispatcher({ trackEvent, trackConversion });
|
|
998
|
+
return () => registerAnalyticsDispatcher(null);
|
|
999
|
+
}, [trackEvent, trackConversion]);
|
|
995
1000
|
const contextValue = useMemo(() => ({
|
|
996
1001
|
trackEvent,
|
|
997
1002
|
trackConversion,
|
|
@@ -1027,5 +1032,5 @@ function useTrackEvent() {
|
|
|
1027
1032
|
}
|
|
1028
1033
|
|
|
1029
1034
|
export { AnalyticsProvider, WebVitals, useAnalytics, useAnalyticsOptional, useTrackEvent };
|
|
1030
|
-
//# sourceMappingURL=chunk-
|
|
1031
|
-
//# sourceMappingURL=chunk-
|
|
1035
|
+
//# sourceMappingURL=chunk-65SMJBHW.mjs.map
|
|
1036
|
+
//# sourceMappingURL=chunk-65SMJBHW.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/analytics/WebVitals.tsx","../src/analytics/AnalyticsProvider.tsx"],"names":["propApiUrl","propApiKey","propSite","debug","wordCount","getApiConfig","usePathname","useEffect","useRef"],"mappings":"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","file":"chunk-65SMJBHW.mjs","sourcesContent":["/**\n * @sonordev/site-kit/analytics - Web Vitals Component\n * \n * Automatically reports Core Web Vitals via Portal API\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { usePathname } from 'next/navigation'\nimport type { Metric } from 'web-vitals'\n\ninterface WebVitalsProps {\n apiUrl?: string\n apiKey?: string\n /** Sub-site identifier (matches AnalyticsConfig.site). Tagged on every Web Vital event. */\n site?: string\n debug?: boolean\n}\n\nfunction getApiConfig() {\n const apiUrl = typeof window !== 'undefined' \n ? (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n : 'https://api.sonor.io'\n const apiKey = typeof window !== 'undefined' \n ? (window as any).__SITE_KIT_API_KEY__\n : undefined\n return { apiUrl, apiKey }\n}\n\nexport function WebVitals({ apiUrl: propApiUrl, apiKey: propApiKey, site: propSite, debug = false }: WebVitalsProps) {\n const pathname = usePathname()\n\n // Core Web Vitals are per-PAGELOAD, not per-route: LCP/TTFB/FCP finalize\n // once for the initial document and never re-fire on SPA navigations. The\n // observers are therefore registered exactly once (mount), and metrics are\n // attributed to the landing pathname. Re-registering per pathname (the old\n // behavior) leaked listeners on every navigation and re-reported the\n // landing page's LCP under later routes.\n const landingPathRef = useRef<string>(pathname || '/')\n const propsRef = useRef({ propApiUrl, propApiKey, propSite, debug })\n propsRef.current = { propApiUrl, propApiKey, propSite, debug }\n\n useEffect(() => {\n let cancelled = false\n let teardown: (() => void) | undefined\n\n // Dynamic import to avoid SSR issues; catch ChunkLoadError (e.g. Turbopack dev)\n import('web-vitals').then(({ onCLS, onLCP, onTTFB, onINP, onFCP }) => {\n if (cancelled) return\n const { propApiUrl, propApiKey, propSite, debug } = propsRef.current\n const vitals: Record<string, number> = {}\n let reported = false\n\n const reportVitals = async () => {\n if (reported) return\n if (Object.keys(vitals).length === 0) return\n \n reported = true\n \n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n const site =\n propSite ||\n (typeof window !== 'undefined'\n ? (window as { __SITE_KIT_SITE__?: string }).__SITE_KIT_SITE__ ||\n window.location.host\n : '')\n\n if (!apiKey) {\n if (debug) console.warn('[Analytics] No API key configured for Web Vitals')\n return\n }\n\n // Report each metric individually\n for (const [name, value] of Object.entries(vitals)) {\n const data = {\n site,\n pagePath: landingPathRef.current,\n metricName: name,\n metricValue: value,\n metricRating: getRating(name, value),\n }\n \n if (debug) {\n console.log('[Analytics] Web Vital:', data)\n }\n \n try {\n await fetch(`${apiUrl}/api/public/analytics/web-vitals`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(data),\n })\n } catch (error) {\n if (debug) console.error('[Analytics] Error reporting Web Vital:', error)\n }\n }\n }\n \n // Collect vitals\n onLCP((metric: Metric) => {\n vitals.LCP = metric.value\n if (debug) console.log('[Analytics] LCP:', metric.value)\n })\n \n onCLS((metric: Metric) => {\n vitals.CLS = metric.value\n if (debug) console.log('[Analytics] CLS:', metric.value)\n })\n \n onTTFB((metric: Metric) => {\n vitals.TTFB = metric.value\n if (debug) console.log('[Analytics] TTFB:', metric.value)\n })\n \n onINP((metric: Metric) => {\n vitals.INP = metric.value\n if (debug) console.log('[Analytics] INP:', metric.value)\n })\n \n onFCP((metric: Metric) => {\n vitals.FCP = metric.value\n if (debug) console.log('[Analytics] FCP:', metric.value)\n })\n \n // Report on page hide (user leaving)\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n reportVitals()\n }\n }\n\n document.addEventListener('visibilitychange', handleVisibilityChange)\n\n // Also report after a delay as fallback\n const timeout = setTimeout(reportVitals, 10000)\n\n // The old code returned this cleanup from the promise callback, where\n // React never saw it — listeners and observers piled up per navigation.\n teardown = () => {\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n clearTimeout(timeout)\n }\n }).catch((err) => {\n // ChunkLoadError in Turbopack/dev - Web Vitals are optional\n if (propsRef.current.debug) console.warn('[Analytics] Web Vitals import failed:', err)\n })\n\n return () => {\n cancelled = true\n teardown?.()\n }\n // Mount-once by design — see comment above. Props are read via propsRef.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n return null\n}\n\nfunction getRating(name: string, value: number): 'good' | 'needs-improvement' | 'poor' {\n const thresholds: Record<string, [number, number]> = {\n LCP: [2500, 4000],\n CLS: [0.1, 0.25],\n TTFB: [800, 1800],\n INP: [200, 500],\n FCP: [1800, 3000],\n }\n \n const [good, poor] = thresholds[name] || [0, 0]\n if (value <= good) return 'good'\n if (value <= poor) return 'needs-improvement'\n return 'poor'\n}\n","/**\n * @sonordev/site-kit/analytics - Analytics Provider\n * \n * Provides analytics context and automatic page view tracking.\n * All data goes through Portal API with API key auth - never Supabase directly.\n */\n\n'use client'\n\nimport React, { createContext, useContext, useEffect, useRef, useCallback, useMemo, useState } from 'react'\nimport { usePathname } from 'next/navigation'\nimport type { AnalyticsContextValue, TrackEventOptions, TrackConversionOptions } from './types'\nimport { registerAnalyticsDispatcher } from './dispatch'\nimport { WebVitals } from './WebVitals'\n// Single source of truth for visitor/session IDs (storage keys _sk_vid/_sk_sid)\n// — shared with SignalBridge and EngageWidget. Includes the crypto.randomUUID\n// fallback for older browsers; do NOT re-fork ID logic into this module.\nimport { getOrCreateVisitorId, getOrCreateSessionId } from '../shared/identity'\n\nconst AnalyticsContext = createContext<AnalyticsContextValue | null>(null)\n\n// ============================================\n// Utility Functions\n// ============================================\n\n/**\n * Schedule a callback to run during browser idle time.\n * Safari has no requestIdleCallback — use a short real delay there so the\n * work lands after the post-hydration burst instead of right inside it.\n */\nfunction scheduleIdleTask(callback: () => void, timeout = 2000): void {\n if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {\n ;(window as typeof window & { requestIdleCallback: (cb: () => void, opts?: { timeout: number }) => number }).requestIdleCallback(\n callback,\n { timeout }\n )\n } else {\n setTimeout(callback, 300)\n }\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\n \n const ua = navigator.userAgent\n if (/tablet|ipad|playbook|silk/i.test(ua)) return 'tablet'\n if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return 'mobile'\n return 'desktop'\n}\n\nfunction getBrowser(): string {\n if (typeof window === 'undefined') return 'unknown'\n \n const ua = navigator.userAgent\n if (ua.includes('Firefox')) return 'Firefox'\n if (ua.includes('Edg')) return 'Edge'\n if (ua.includes('Chrome')) return 'Chrome'\n if (ua.includes('Safari')) return 'Safari'\n if (ua.includes('Opera') || ua.includes('OPR')) return 'Opera'\n return 'Other'\n}\n\nfunction getOS(): string {\n if (typeof window === 'undefined') return 'unknown'\n \n const ua = navigator.userAgent\n if (ua.includes('Windows')) return 'Windows'\n if (ua.includes('Mac OS X') || ua.includes('Macintosh')) return 'macOS'\n if (ua.includes('iPhone') || ua.includes('iPad')) return 'iOS'\n if (ua.includes('Android')) return 'Android'\n if (ua.includes('Linux')) return 'Linux'\n if (ua.includes('CrOS')) return 'ChromeOS'\n return 'Other'\n}\n\nfunction getUserAgent(): string {\n if (typeof window === 'undefined') return ''\n return navigator.userAgent\n}\n\nfunction getUTMParams(): Record<string, string> {\n if (typeof window === 'undefined') return {}\n \n const params = new URLSearchParams(window.location.search)\n const utmParams: Record<string, string> = {}\n \n for (const key of ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']) {\n const value = params.get(key)\n if (value) utmParams[key] = value\n }\n \n return utmParams\n}\n\n/**\n * Promise wrapper around scheduleIdleTask so the metadata scrape can yield\n * back to the main thread between slices.\n */\nfunction nextIdleSlice(timeout = 1500): Promise<void> {\n return new Promise(resolve => scheduleIdleTask(resolve, timeout))\n}\n\n/**\n * Extract SEO metadata from the current page.\n * This enriches seo_pages with live data from the actual page.\n *\n * Split into three slices so no single idle callback runs the whole scrape as\n * one long task on throttled mobile CPUs (full-tree clones + textContent reads\n * are the expensive part):\n * 1. getLightPageMetadata — meta tags, canonical, H1 (cheap queries)\n * 2. getLinkPageMetadata — word count + link graph (whole-tree text + anchors)\n * 3. getHeavyPageMetadata — images w/ context, content clone, sections, FAQs\n * Callers yield via nextIdleSlice() between them and merge the results; the\n * merged payload shape is identical to the old monolithic getPageMetadata().\n */\nfunction getLightPageMetadata(): Record<string, any> {\n if (typeof document === 'undefined') return {}\n\n const getMeta = (name: string): string | null => {\n const el = document.querySelector(`meta[name=\"${name}\"], meta[property=\"${name}\"]`)\n return el?.getAttribute('content') || null\n }\n \n const getCanonical = (): string | null => {\n const el = document.querySelector('link[rel=\"canonical\"]')\n return el?.getAttribute('href') || null\n }\n \n const getRobots = (): string | null => {\n return getMeta('robots')\n }\n \n const getH1 = (): string | null => {\n const h1 = document.querySelector('h1')\n return h1?.textContent?.trim() || null\n }\n \n const getH1Count = (): number => {\n return document.querySelectorAll('h1').length\n }\n \n return {\n metaDescription: getMeta('description'),\n canonical: getCanonical(),\n robots: getRobots(),\n ogTitle: getMeta('og:title'),\n ogDescription: getMeta('og:description'),\n ogImage: getMeta('og:image'),\n h1: getH1(),\n h1Count: getH1Count(),\n }\n}\n\n/** Slice 2: image inventory — per-image ancestor walks + surrounding text. */\nfunction getMediaPageMetadata(): Record<string, any> {\n if (typeof document === 'undefined') return {}\n\n interface PageImageReport {\n src: string\n alt: string | null\n elementType: 'img' | 'Image' | 'ManagedImage' | 'picture' | 'background'\n slotId?: string\n position: 'hero' | 'content' | 'sidebar' | 'footer' | 'header' | 'unknown'\n width?: number\n height?: number\n surroundingText?: string\n }\n\n // Helper to determine element position in page\n const getElementPosition = (el: Element): PageImageReport['position'] => {\n let current: Element | null = el\n while (current) {\n const tag = current.tagName?.toLowerCase()\n const role = current.getAttribute('role')\n const className = current.className?.toString?.() || ''\n \n // Check for hero sections\n if (className.includes('hero') || current.id?.includes('hero')) return 'hero'\n if (tag === 'header' || role === 'banner') return 'header'\n if (tag === 'nav' || role === 'navigation') return 'header'\n if (tag === 'footer' || role === 'contentinfo') return 'footer'\n if (tag === 'aside' || role === 'complementary') return 'sidebar'\n if (tag === 'main' || tag === 'article' || role === 'main') return 'content'\n \n current = current.parentElement\n }\n return 'unknown'\n }\n\n // Get surrounding text context for an image\n const getSurroundingText = (el: Element): string => {\n // Find closest paragraph, figcaption, or container\n const container = el.closest('figure, p, div, section, article')\n if (!container) return ''\n \n // Get text excluding script/style content\n const text = container.textContent?.replace(/\\s+/g, ' ').trim() || ''\n return text.slice(0, 300) // Limit to 300 chars\n }\n\n const getImageDetails = (): PageImageReport[] => {\n const images = document.querySelectorAll('img, [data-managed-image]')\n const seen = new Set<string>()\n const results: PageImageReport[] = []\n \n images.forEach(el => {\n const img = el as HTMLImageElement\n const src = img.getAttribute('src') || img.getAttribute('data-src') || ''\n \n // Skip duplicates, data URIs, and empty src\n if (!src || src.startsWith('data:') || seen.has(src)) return\n seen.add(src)\n \n // Detect if it's a ManagedImage\n const slotId = img.getAttribute('data-slot-id') || undefined\n const isManagedImage = img.hasAttribute('data-managed-image') || !!slotId\n \n results.push({\n src,\n alt: img.alt || null,\n elementType: isManagedImage ? 'ManagedImage' : 'img',\n slotId,\n position: getElementPosition(img),\n width: img.naturalWidth || parseInt(img.getAttribute('width') || '0') || undefined,\n height: img.naturalHeight || parseInt(img.getAttribute('height') || '0') || undefined,\n surroundingText: getSurroundingText(img),\n })\n })\n \n return results\n }\n\n const getImageStats = (): { count: number; withoutAlt: number; images: PageImageReport[] } => {\n const images = getImageDetails()\n let withoutAlt = 0\n images.forEach(img => {\n if (!img.alt || img.alt.trim() === '') withoutAlt++\n })\n return { count: images.length, withoutAlt, images }\n }\n\n const imageStats = getImageStats()\n return {\n imagesCount: imageStats.count,\n imagesWithoutAlt: imageStats.withoutAlt,\n images: imageStats.images, // Full image details for SEO optimization\n }\n}\n\n/** Slice 3: word count, link graph, and content extraction for Signal AI. */\nfunction getContentPageMetadata(): Record<string, any> {\n if (typeof document === 'undefined') return {}\n\n const getWordCount = (): number => {\n // Get main content, fallback to body\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n const text = main.textContent || ''\n return text.split(/\\s+/).filter(w => w.length > 0).length\n }\n\n interface InternalLink {\n targetPath: string\n anchorText: string\n position: 'header' | 'nav' | 'content' | 'footer' | 'sidebar' | 'unknown'\n isNofollow: boolean\n }\n \n const getLinkStats = (): { \n internal: number\n external: number\n internalLinks: InternalLink[]\n } => {\n const links = document.querySelectorAll('a[href]')\n const currentHost = window.location.host\n let internal = 0\n let external = 0\n const internalLinks: InternalLink[] = []\n \n // Helper to determine link position in page\n const getLinkPosition = (el: Element): InternalLink['position'] => {\n let current: Element | null = el\n while (current) {\n const tag = current.tagName?.toLowerCase()\n const role = current.getAttribute('role')\n \n if (tag === 'header' || role === 'banner') return 'header'\n if (tag === 'nav' || role === 'navigation') return 'nav'\n if (tag === 'footer' || role === 'contentinfo') return 'footer'\n if (tag === 'aside' || role === 'complementary') return 'sidebar'\n if (tag === 'main' || tag === 'article' || role === 'main') return 'content'\n \n current = current.parentElement\n }\n return 'unknown'\n }\n \n links.forEach(link => {\n const href = link.getAttribute('href') || ''\n const rel = link.getAttribute('rel') || ''\n const isNofollow = rel.includes('nofollow')\n \n let isInternal = false\n let targetPath = ''\n \n if (href.startsWith('/') && !href.startsWith('//')) {\n isInternal = true\n targetPath = href.split('?')[0].split('#')[0] // Remove query/hash\n } else if (href.startsWith('#')) {\n // Same page anchor - skip\n internal++\n return\n } else if (href.startsWith('http')) {\n try {\n const url = new URL(href)\n if (url.host === currentHost) {\n isInternal = true\n targetPath = url.pathname\n } else {\n external++\n }\n } catch {\n // Invalid URL\n }\n }\n \n if (isInternal && targetPath) {\n internal++\n // Normalize path\n if (!targetPath.startsWith('/')) targetPath = '/' + targetPath\n if (targetPath !== '/' && targetPath.endsWith('/')) {\n targetPath = targetPath.slice(0, -1)\n }\n \n internalLinks.push({\n targetPath,\n anchorText: (link.textContent || '').trim().slice(0, 200),\n position: getLinkPosition(link),\n isNofollow,\n })\n }\n })\n \n return { internal, external, internalLinks }\n }\n\n // ============================================\n // Content Extraction for Signal AI Analysis\n // ============================================\n \n interface HeadingInfo {\n level: number\n text: string\n id?: string\n }\n\n interface ContentSection {\n heading?: string\n headingLevel?: number\n text: string\n wordCount: number\n }\n\n interface FAQItem {\n question: string\n answer: string\n }\n\n const getHeadingStructure = (): HeadingInfo[] => {\n const headings: HeadingInfo[] = []\n const elements = document.querySelectorAll('h1, h2, h3, h4, h5, h6')\n \n elements.forEach(el => {\n const level = parseInt(el.tagName[1])\n const text = el.textContent?.trim() || ''\n if (text) {\n headings.push({\n level,\n text: text.slice(0, 200), // Limit length\n id: el.id || undefined\n })\n }\n })\n \n return headings\n }\n\n const getContentText = (): { text: string; hash: string } => {\n // Get main content area\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n \n // Clone to avoid modifying the page\n const clone = main.cloneNode(true) as Element\n \n // Remove script, style, nav, header, footer from clone\n clone.querySelectorAll('script, style, nav, header, footer, [role=\"navigation\"], [role=\"banner\"], [role=\"contentinfo\"]').forEach(el => el.remove())\n \n // Get clean text\n let text = clone.textContent || ''\n text = text.replace(/\\s+/g, ' ').trim()\n \n // Limit to 10KB for storage\n text = text.slice(0, 10000)\n \n // Simple hash for change detection\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n const chr = text.charCodeAt(i)\n hash = ((hash << 5) - hash) + chr\n hash |= 0\n }\n \n return { text, hash: hash.toString(16) }\n }\n\n const getContentSections = (): ContentSection[] => {\n const sections: ContentSection[] = []\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n \n // Find all heading + content pairs\n const headings = main.querySelectorAll('h1, h2, h3')\n \n headings.forEach((heading, idx) => {\n const headingText = heading.textContent?.trim() || ''\n const level = parseInt(heading.tagName[1])\n \n // Get content between this heading and the next\n let content = ''\n let sibling = heading.nextElementSibling\n \n while (sibling && !['H1', 'H2', 'H3'].includes(sibling.tagName)) {\n if (sibling.tagName === 'P' || sibling.tagName === 'UL' || sibling.tagName === 'OL' || sibling.tagName === 'DIV') {\n content += (sibling.textContent || '') + ' '\n }\n sibling = sibling.nextElementSibling\n }\n \n content = content.replace(/\\s+/g, ' ').trim().slice(0, 1000)\n const wordCount = content.split(/\\s+/).filter(w => w.length > 0).length\n \n if (content && wordCount > 10) {\n sections.push({\n heading: headingText.slice(0, 200),\n headingLevel: level,\n text: content,\n wordCount\n })\n }\n })\n \n return sections.slice(0, 20) // Limit to 20 sections\n }\n\n const detectFAQContent = (): FAQItem[] => {\n const faqs: FAQItem[] = []\n \n // Look for FAQ schema\n const scripts = document.querySelectorAll('script[type=\"application/ld+json\"]')\n scripts.forEach(script => {\n try {\n const data = JSON.parse(script.textContent || '')\n if (data['@type'] === 'FAQPage' && data.mainEntity) {\n data.mainEntity.forEach((item: any) => {\n if (item['@type'] === 'Question') {\n faqs.push({\n question: item.name?.slice(0, 200) || '',\n answer: (item.acceptedAnswer?.text || '').slice(0, 500)\n })\n }\n })\n }\n } catch { /* ignore parse errors */ }\n })\n \n // Look for common FAQ patterns in HTML\n if (faqs.length === 0) {\n // details/summary pattern\n const details = document.querySelectorAll('details')\n details.forEach(detail => {\n const summary = detail.querySelector('summary')\n if (summary) {\n const question = summary.textContent?.trim() || ''\n const answer = detail.textContent?.replace(question, '').trim().slice(0, 500) || ''\n if (question && answer) {\n faqs.push({ question: question.slice(0, 200), answer })\n }\n }\n })\n \n // Accordion pattern (common class names)\n const accordionItems = document.querySelectorAll('[class*=\"accordion\"], [class*=\"faq\"], [data-faq]')\n accordionItems.forEach(item => {\n const questionEl = item.querySelector('[class*=\"question\"], [class*=\"title\"], button, h3, h4')\n const answerEl = item.querySelector('[class*=\"answer\"], [class*=\"content\"], [class*=\"panel\"], p')\n if (questionEl && answerEl) {\n const question = questionEl.textContent?.trim() || ''\n const answer = answerEl.textContent?.trim().slice(0, 500) || ''\n if (question && answer && question.includes('?')) {\n faqs.push({ question: question.slice(0, 200), answer })\n }\n }\n })\n }\n \n return faqs.slice(0, 20) // Limit to 20 FAQs\n }\n\n const detectLists = (): { type: 'ul' | 'ol'; items: string[] }[] => {\n const lists: { type: 'ul' | 'ol'; items: string[] }[] = []\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n \n main.querySelectorAll('ul, ol').forEach(list => {\n const type = list.tagName.toLowerCase() as 'ul' | 'ol'\n const items: string[] = []\n \n list.querySelectorAll(':scope > li').forEach(li => {\n const text = li.textContent?.trim().slice(0, 200) || ''\n if (text) items.push(text)\n })\n \n // Only include substantial lists (3+ items)\n if (items.length >= 3) {\n lists.push({ type, items: items.slice(0, 10) })\n }\n })\n \n return lists.slice(0, 10) // Limit to 10 lists\n }\n\n const estimateReadingTime = (wordCount: number): number => {\n // Average reading speed: 200-250 words per minute\n return Math.ceil(wordCount / 225)\n }\n \n const linkStats = getLinkStats()\n const headingStructure = getHeadingStructure()\n const contentData = getContentText()\n const contentSections = getContentSections()\n const faqContent = detectFAQContent()\n const listContent = detectLists()\n const wordCount = getWordCount()\n\n return {\n wordCount,\n internalLinks: linkStats.internal,\n internalLinkTargets: linkStats.internalLinks, // Full link graph data\n externalLinks: linkStats.external,\n // Content analysis data\n content: {\n text: contentData.text,\n hash: contentData.hash,\n headings: headingStructure,\n sections: contentSections,\n faqs: faqContent.length > 0 ? faqContent : undefined,\n lists: listContent.length > 0 ? listContent : undefined,\n readingTime: estimateReadingTime(wordCount),\n },\n }\n}\n\n/**\n * Collect full page metadata across three idle slices so the scrape never\n * runs as one long main-thread task. `isStale` is checked between slices —\n * if the user SPA-navigates mid-scrape, later slices would read the NEW\n * page's DOM under the old path, so we stop and return only the slices\n * scraped while the page was still current (partial metadata beats corrupt\n * metadata, and the page view itself is still recorded).\n */\nasync function collectPageMetadata(isStale: () => boolean): Promise<Record<string, any>> {\n const light = getLightPageMetadata()\n await nextIdleSlice()\n if (isStale()) return light\n const media = getMediaPageMetadata()\n await nextIdleSlice()\n if (isStale()) return { ...light, ...media }\n const content = getContentPageMetadata()\n return { ...light, ...media, ...content }\n}\n\nfunction getApiConfig() {\n const apiUrl = typeof window !== 'undefined' \n ? (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n : 'https://api.sonor.io'\n const apiKey = typeof window !== 'undefined' \n ? (window as any).__SITE_KIT_API_KEY__\n : undefined\n return { apiUrl, apiKey }\n}\n\n// ============================================\n// Provider Component\n// ============================================\n\ninterface AnalyticsProviderProps {\n /**\n * Optional. AnalyticsProvider is normally mounted as a CHILDLESS sibling of\n * page content (see SiteKitClientProviders) — it tracks via effects and a\n * metadata ref, it does not need to enclose the page. When rendered\n * childless, the AnalyticsContext simply has no consumers; components that\n * need it should use `useAnalyticsOptional()`.\n */\n children?: React.ReactNode\n apiUrl?: string\n apiKey?: string\n trackPageViews?: boolean\n trackWebVitals?: boolean\n trackScrollDepth?: boolean\n trackClicks?: boolean\n trackJourneys?: boolean // NEW: Track user journey paths\n sessionTimeout?: number\n excludePaths?: string[]\n validateAgainstSitemap?: boolean // Log debug warnings for paths not in sitemap (informational only, never blocks tracking)\n debug?: boolean\n /** External visitor ID from shared identity (used by SiteKitLayout) */\n externalVisitorId?: string\n /** External session ID from shared identity (used by SiteKitLayout) */\n externalSessionId?: string\n /** Callback invoked with page metadata after each page view (used by Signal bridge) */\n onPageMetadata?: (metadata: Record<string, unknown>) => void\n /**\n * Sub-site identifier (e.g. `ohiopowerstudies.com`). Every event tagged with\n * this string so a single Sonor project can host many sites and the\n * dashboard can filter / roll up per site. Normally passed in by\n * SiteKitClientProviders; if omitted, falls back to\n * `window.__SITE_KIT_SITE__` then `window.location.host`.\n */\n site?: string\n}\n\nexport function AnalyticsProvider({\n children,\n apiUrl: propApiUrl,\n apiKey: propApiKey,\n trackPageViews = true,\n trackWebVitals = true,\n trackScrollDepth = true,\n trackClicks = true,\n trackJourneys = true, // NEW: Enable journey tracking by default\n sessionTimeout = 30,\n excludePaths = [],\n validateAgainstSitemap = false,\n debug = false,\n externalVisitorId,\n externalSessionId,\n onPageMetadata,\n site: propSite,\n}: AnalyticsProviderProps) {\n const pathname = usePathname()\n // Use state to track query string changes instead of useSearchParams (avoids Suspense requirement)\n const [queryString, setQueryString] = useState('')\n\n // Sub-site identifier — every event body below carries this so a single\n // Sonor project can host many sites and the dashboard can filter / roll up\n // per site. Resolution: prop > window global (set by SiteKitClientProviders)\n // > window.location.host. Empty string is acceptable (older clients).\n const site =\n propSite ||\n (typeof window !== 'undefined'\n ? (window as { __SITE_KIT_SITE__?: string }).__SITE_KIT_SITE__ ||\n window.location.host\n : '')\n \n // Listen for URL changes including query string\n useEffect(() => {\n if (typeof window === 'undefined') return\n \n // Set initial query string\n setQueryString(window.location.search)\n \n // Listen for popstate (back/forward navigation)\n const handlePopState = () => {\n setQueryString(window.location.search)\n }\n \n window.addEventListener('popstate', handlePopState)\n return () => window.removeEventListener('popstate', handlePopState)\n }, [pathname]) // Re-check when pathname changes\n \n const visitorIdRef = useRef<string>('')\n const sessionIdRef = useRef<string>('')\n const lastPathRef = useRef<string>('')\n const validPathsRef = useRef<Set<string> | null>(null)\n const sitemapLoadedRef = useRef<boolean>(false)\n \n // Journey tracking state\n const journeyStartTimeRef = useRef<number>(0)\n const pageEnterTimeRef = useRef<number>(0)\n const currentScrollDepthRef = useRef<number>(0)\n \n // Initialize IDs — use external (shared) IDs when provided by SiteKitLayout\n useEffect(() => {\n visitorIdRef.current = externalVisitorId || getOrCreateVisitorId()\n sessionIdRef.current = externalSessionId || getOrCreateSessionId(sessionTimeout)\n }, [sessionTimeout, externalVisitorId, externalSessionId])\n \n // Fetch valid pages from seo_pages (populated by SitemapSync from SEO module)\n useEffect(() => {\n if (!validateAgainstSitemap) {\n if (debug) console.log('[Analytics] Page validation disabled')\n return\n }\n \n const fetchValidPages = async () => {\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Analytics] No API key for page validation')\n return\n }\n \n try {\n // Fetch seo_pages which is the canonical source of truth\n // (populated by SitemapSync component from the SEO module)\n const response = await fetch(`${apiUrl}/api/public/seo/pages`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n })\n \n if (response.ok) {\n const data = await response.json()\n const pages = data?.pages || []\n validPathsRef.current = new Set(\n pages.map((p: any) => p.path).filter(Boolean)\n )\n sitemapLoadedRef.current = true\n\n if (debug) {\n console.log('[Analytics] Loaded', validPathsRef.current.size, 'valid pages from seo_pages')\n }\n } else {\n sitemapLoadedRef.current = true // Mark as loaded even on failure so we don't block\n if (debug) {\n console.error('[Analytics] Pages fetch failed:', response.statusText)\n }\n }\n } catch (error) {\n sitemapLoadedRef.current = true // Mark as loaded even on error so we don't block\n if (debug) console.error('[Analytics] Error fetching valid pages:', error)\n }\n }\n \n fetchValidPages()\n }, [propApiUrl, propApiKey, validateAgainstSitemap, debug])\n \n // Track page views\n useEffect(() => {\n if (!trackPageViews) return\n if (!pathname) return\n\n // Normalize path: strip trailing slashes (except root)\n const normalizedPath = pathname === '/' ? '/' : pathname.replace(/\\/+$/, '')\n\n if (excludePaths.some(p => normalizedPath.startsWith(p))) return\n if (normalizedPath === lastPathRef.current) return\n\n lastPathRef.current = normalizedPath\n \n const trackPageView = async () => {\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Analytics] No API key configured')\n return\n }\n \n const utmParams = getUTMParams()\n // Captured before the sliced scrape yields — the title must belong to\n // THIS page even if the user navigates while slices are pending.\n const pageTitle = document.title\n // Sliced scrape: yields to the main thread between phases; on SPA\n // navigation mid-scrape it returns only the slices read from this\n // page's DOM (the page view still records, with partial metadata).\n const pageMetadata = await collectPageMetadata(\n () => lastPathRef.current !== normalizedPath,\n )\n\n // Share page metadata with Signal bridge via callback\n if (onPageMetadata) {\n onPageMetadata(pageMetadata)\n }\n\n const pageView = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n pagePath: normalizedPath,\n pageTitle,\n referrer: document.referrer || null,\n deviceType: getDeviceType(),\n browser: getBrowser(),\n os: getOS(),\n userAgent: getUserAgent(),\n utmSource: utmParams.utm_source,\n utmMedium: utmParams.utm_medium,\n utmCampaign: utmParams.utm_campaign,\n utmTerm: utmParams.utm_term,\n utmContent: utmParams.utm_content,\n // SEO enrichment data - updates seo_pages\n seo: pageMetadata,\n }\n\n if (debug) {\n console.log('[Analytics] Page view:', pageView)\n }\n\n try {\n const response = await fetch(`${apiUrl}/api/public/analytics/page-view`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(pageView),\n })\n\n if (debug) {\n console.log('[Analytics] Page view response:', response.status, response.statusText, 'url:', `${apiUrl}/api/public/analytics/page-view`)\n }\n if (!response.ok && debug) {\n const text = await response.text().catch(() => '')\n console.error('[Analytics] Error tracking page view:', response.status, response.statusText, text)\n }\n } catch (error) {\n if (debug) console.error('[Analytics] Error tracking page view (fetch failed):', error)\n }\n\n // Informational sitemap validation (never blocks tracking)\n if (validateAgainstSitemap && debug) {\n if (sitemapLoadedRef.current && validPathsRef.current && validPathsRef.current.size > 0) {\n if (!validPathsRef.current.has(normalizedPath)) {\n console.log('[Analytics] Note: path not found in sitemap (tracked anyway):', normalizedPath)\n }\n } else if (!sitemapLoadedRef.current) {\n console.log('[Analytics] Sitemap not yet loaded, tracked anyway:', normalizedPath)\n }\n }\n }\n \n // Use requestIdleCallback to defer tracking until browser is idle\n scheduleIdleTask(() => trackPageView())\n }, [pathname, queryString, propApiUrl, propApiKey, trackPageViews, excludePaths, debug, validateAgainstSitemap])\n\n // ============================================\n // Journey Path Tracking\n // ============================================\n useEffect(() => {\n if (!trackJourneys) return\n if (!pathname) return\n if (typeof window === 'undefined') return\n\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) return\n \n const now = Date.now()\n const previousPath = lastPathRef.current\n const previousDuration = pageEnterTimeRef.current > 0 \n ? Math.round((now - pageEnterTimeRef.current) / 1000) \n : 0\n const previousScrollDepth = currentScrollDepthRef.current\n\n // Update tracking refs for next navigation\n pageEnterTimeRef.current = now\n currentScrollDepthRef.current = 0\n\n // Determine if this is a new session or continuation\n const isNewSession = !previousPath || journeyStartTimeRef.current === 0\n \n if (isNewSession) {\n journeyStartTimeRef.current = now\n }\n\n const trackJourneyStep = async () => {\n const sessionData: Record<string, any> = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n action: isNewSession ? 'start' : 'update',\n lastPage: pathname,\n userAgent: getUserAgent(),\n // Journey step data\n journeyStep: {\n page: pathname,\n timestamp: new Date().toISOString(),\n },\n }\n\n // Include previous page duration when navigating\n if (!isNewSession && previousDuration > 0) {\n sessionData.previousPageDuration = previousDuration\n sessionData.previousPageScrollDepth = previousScrollDepth\n }\n\n // Include first page for new sessions\n if (isNewSession) {\n sessionData.firstPage = pathname\n const utmParams = getUTMParams()\n sessionData.referrer = document.referrer || null\n sessionData.utmSource = utmParams.utm_source\n sessionData.utmMedium = utmParams.utm_medium\n sessionData.utmCampaign = utmParams.utm_campaign\n sessionData.utmTerm = utmParams.utm_term\n sessionData.utmContent = utmParams.utm_content\n sessionData.screenWidth = window.screen.width\n sessionData.screenHeight = window.screen.height\n }\n\n if (debug) {\n console.log('[Analytics] Journey step:', sessionData)\n }\n\n try {\n await fetch(`${apiUrl}/api/public/analytics/session`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(sessionData),\n })\n } catch (error) {\n if (debug) console.error('[Analytics] Error tracking journey:', error)\n }\n }\n\n scheduleIdleTask(() => trackJourneyStep())\n\n // Track session end when the page is being hidden/unloaded. `pagehide`\n // (not `beforeunload`): beforeunload never fires on iOS Safari and makes\n // pages ineligible for the back/forward cache in Firefox.\n const handleUnload = () => {\n const duration = Math.round((Date.now() - journeyStartTimeRef.current) / 1000)\n const payload = JSON.stringify({\n sessionId: sessionIdRef.current,\n site,\n action: 'end',\n duration,\n lastPage: pathname,\n previousPageDuration: Math.round((Date.now() - pageEnterTimeRef.current) / 1000),\n previousPageScrollDepth: currentScrollDepthRef.current,\n })\n\n // Use sendBeacon for reliability\n if (navigator.sendBeacon) {\n const blob = new Blob([payload], { type: 'application/json' })\n navigator.sendBeacon(\n `${apiUrl}/api/public/analytics/session?key=${encodeURIComponent(apiKey)}`,\n blob\n )\n }\n }\n\n window.addEventListener('pagehide', handleUnload)\n\n return () => {\n window.removeEventListener('pagehide', handleUnload)\n }\n }, [pathname, propApiUrl, propApiKey, trackJourneys, debug])\n\n // ============================================\n // Scroll Depth Tracking\n // ============================================\n useEffect(() => {\n if (typeof window === 'undefined') return\n \n if (debug) console.log('[Analytics] Scroll tracking setup:', { trackScrollDepth, hasApiKey: !!propApiKey })\n \n if (!trackScrollDepth) return\n\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Analytics] Scroll tracking disabled - no API key')\n return\n }\n \n if (debug) console.log('[Analytics] Scroll tracking enabled for:', pathname)\n\n let maxDepth = 0\n let startTime = Date.now()\n let milestone25: number | null = null\n let milestone50: number | null = null\n let milestone75: number | null = null\n let milestone100: number | null = null\n let hasTracked = false\n\n const calculateScrollDepth = () => {\n const scrollTop = window.scrollY\n const docHeight = document.documentElement.scrollHeight\n const winHeight = window.innerHeight\n const scrollableHeight = docHeight - winHeight\n \n if (scrollableHeight <= 0) return 100\n return Math.min(100, Math.round((scrollTop / scrollableHeight) * 100))\n }\n\n const handleScroll = () => {\n const depth = calculateScrollDepth()\n const elapsed = (Date.now() - startTime) / 1000\n\n if (depth > maxDepth) {\n maxDepth = depth\n currentScrollDepthRef.current = depth // Update ref for journey tracking\n if (debug && depth % 25 === 0) console.log('[Analytics] Scroll milestone:', depth + '%')\n \n if (depth >= 25 && milestone25 === null) milestone25 = elapsed\n if (depth >= 50 && milestone50 === null) milestone50 = elapsed\n if (depth >= 75 && milestone75 === null) milestone75 = elapsed\n if (depth >= 100 && milestone100 === null) milestone100 = elapsed\n }\n }\n\n const sendScrollData = async (useBeacon = false) => {\n if (hasTracked || maxDepth === 0) return\n hasTracked = true\n\n const totalTime = (Date.now() - startTime) / 1000\n \n const payload = JSON.stringify({\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n pagePath: pathname,\n maxDepthPercent: maxDepth,\n timeTo25: milestone25,\n timeTo50: milestone50,\n timeTo75: milestone75,\n timeTo100: milestone100,\n totalTimeSeconds: totalTime,\n deviceType: getDeviceType(),\n })\n\n // Use sendBeacon for page unload (more reliable) or fetch for regular sends\n if (useBeacon && navigator.sendBeacon) {\n const blob = new Blob([payload], { type: 'application/json' })\n const headers = new Headers({ 'x-api-key': apiKey })\n // sendBeacon doesn't support custom headers, so we need to include key in URL\n navigator.sendBeacon(\n `${apiUrl}/api/public/analytics/scroll-depth?key=${encodeURIComponent(apiKey)}`,\n blob\n )\n if (debug) console.log('[Analytics] Scroll depth (beacon):', { maxDepth, totalTime })\n } else {\n try {\n await fetch(`${apiUrl}/api/public/analytics/scroll-depth`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: payload,\n keepalive: true, // Allows request to outlive the page\n })\n \n if (debug) console.log('[Analytics] Scroll depth:', { maxDepth, totalTime })\n } catch (error) {\n if (debug) console.error('[Analytics] Error tracking scroll depth:', error)\n }\n }\n }\n\n // Reset on page change\n maxDepth = 0\n startTime = Date.now()\n milestone25 = null\n milestone50 = null\n milestone75 = null\n milestone100 = null\n hasTracked = false\n\n window.addEventListener('scroll', handleScroll, { passive: true })\n\n // Capture the current position immediately — the provider mounts deferred\n // (idle/first-interaction), so the user may have already scrolled.\n handleScroll()\n\n // Send on page hide/unload - use beacon for reliability. `pagehide` (not\n // `beforeunload`) — it fires on iOS Safari and is bfcache-safe.\n const handlePageHide = () => sendScrollData(true)\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'hidden') sendScrollData(true)\n }\n\n window.addEventListener('pagehide', handlePageHide)\n document.addEventListener('visibilitychange', handleVisibilityChange)\n\n return () => {\n window.removeEventListener('scroll', handleScroll)\n window.removeEventListener('pagehide', handlePageHide)\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n sendScrollData(false) // Send when component unmounts (navigation) - can use fetch here\n }\n }, [pathname, propApiUrl, propApiKey, trackScrollDepth, debug])\n\n // ============================================\n // Click/Heatmap Tracking\n // ============================================\n useEffect(() => {\n if (!trackClicks) return\n if (typeof window === 'undefined') return\n\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n if (!apiKey) return\n\n const handleClick = async (e: MouseEvent) => {\n const target = e.target as HTMLElement\n if (!target) return\n\n const docHeight = document.documentElement.scrollHeight\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n // Calculate click position as percentage\n const xPercent = Math.round((e.pageX / viewportWidth) * 100)\n const yPercent = Math.round(((e.pageY) / docHeight) * 100)\n\n // Get element info\n const elementTag = target.tagName.toLowerCase()\n const elementId = target.id || null\n const elementClass = target.className && typeof target.className === 'string' \n ? target.className.split(' ').slice(0, 3).join(' ') \n : null\n const elementText = target.textContent?.slice(0, 50) || null\n\n const clickData = {\n sessionId: sessionIdRef.current,\n site,\n pagePath: pathname,\n xPercent,\n yPercent,\n xAbsolute: e.pageX,\n yAbsolute: e.pageY,\n viewportWidth,\n viewportHeight,\n pageHeight: docHeight,\n elementTag,\n elementId,\n elementClass,\n elementText,\n }\n\n if (debug) console.log('[Analytics] Click:', clickData)\n\n scheduleIdleTask(async () => {\n try {\n await fetch(`${apiUrl}/api/public/analytics/heatmap-click`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(clickData),\n })\n } catch (error) {\n if (debug) console.error('[Analytics] Error tracking click:', error)\n }\n }, 500)\n }\n\n document.addEventListener('click', handleClick, { passive: true })\n\n return () => {\n document.removeEventListener('click', handleClick)\n }\n }, [pathname, propApiUrl, propApiKey, trackClicks, debug])\n \n // Track event function - uses idle callback for non-critical events\n const trackEvent = useCallback((options: TrackEventOptions) => {\n const doTrack = async () => {\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Analytics] No API key configured')\n return\n }\n \n const event = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n eventName: options.name,\n eventCategory: options.category,\n eventLabel: options.label,\n eventValue: options.value,\n properties: options.properties,\n pagePath: pathname,\n }\n \n if (debug) {\n console.log('[Analytics] Event:', event)\n }\n \n try {\n const response = await fetch(`${apiUrl}/api/public/analytics/event`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(event),\n })\n \n if (!response.ok && debug) {\n console.error('[Analytics] Error tracking event:', response.statusText)\n }\n } catch (error) {\n if (debug) console.error('[Analytics] Error tracking event:', error)\n }\n }\n \n // Defer event tracking to idle time\n scheduleIdleTask(doTrack, 1000)\n }, [propApiUrl, propApiKey, pathname, debug])\n \n // Track conversion function - runs immediately (conversions are high priority)\n const trackConversion = useCallback((options: TrackConversionOptions) => {\n const doTrack = async () => {\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Analytics] No API key configured')\n return\n }\n \n const conversion = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n conversionType: options.type,\n value: options.value,\n currency: options.currency,\n metadata: options.metadata,\n pagePath: pathname,\n referrer: document.referrer || null,\n deviceType: getDeviceType(),\n }\n \n if (debug) {\n console.log('[Analytics] Conversion:', conversion)\n }\n \n try {\n const response = await fetch(`${apiUrl}/api/public/analytics/conversion`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(conversion),\n })\n \n if (!response.ok && debug) {\n console.error('[Analytics] Error tracking conversion:', response.statusText)\n }\n } catch (error) {\n if (debug) console.error('[Analytics] Error tracking conversion:', error)\n }\n }\n \n // Conversions run immediately (not deferred) since they're high-value events\n doTrack()\n }, [propApiUrl, propApiKey, pathname, debug])\n \n // Bridge for code outside this provider's tree (the childless-sibling\n // mount pattern leaves the whole page un-provided): register the REAL\n // track functions with the standalone dispatch module, which queues any\n // calls made before this (idle-deferred) provider mounted.\n useEffect(() => {\n registerAnalyticsDispatcher({ trackEvent, trackConversion })\n return () => registerAnalyticsDispatcher(null)\n }, [trackEvent, trackConversion])\n\n const contextValue = useMemo<AnalyticsContextValue>(() => ({\n trackEvent,\n trackConversion,\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n }), [trackEvent, trackConversion])\n \n return (\n <AnalyticsContext.Provider value={contextValue}>\n {trackWebVitals && (\n <WebVitals\n apiUrl={propApiUrl}\n apiKey={propApiKey}\n site={site}\n debug={debug}\n />\n )}\n {children}\n </AnalyticsContext.Provider>\n )\n}\n\n// ============================================\n// Hooks\n// ============================================\n\nexport function useAnalytics(): AnalyticsContextValue {\n const context = useContext(AnalyticsContext)\n if (!context) {\n throw new Error('useAnalytics must be used within an AnalyticsProvider')\n }\n return context\n}\n\n/**\n * Safe version of useAnalytics that returns null when used outside of AnalyticsProvider.\n * Use this in components that may be rendered without an AnalyticsProvider in the tree.\n */\nexport function useAnalyticsOptional(): AnalyticsContextValue | null {\n return useContext(AnalyticsContext)\n}\n\nexport function useTrackEvent() {\n const { trackEvent, trackConversion } = useAnalytics()\n return { trackEvent, trackConversion }\n}\n"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAnalytics } from './chunk-
|
|
2
|
+
import { useAnalytics } from './chunk-65SMJBHW.mjs';
|
|
3
3
|
import { useCallback, useEffect } from 'react';
|
|
4
4
|
|
|
5
5
|
function useContactTracking(options = {}) {
|
|
6
6
|
const { autoTrack = true, debug = false } = options;
|
|
7
|
-
const { trackConversion } = useAnalytics();
|
|
7
|
+
const { trackConversion: trackConversion2 } = useAnalytics();
|
|
8
8
|
const trackPhoneClick = useCallback((phoneNumber, metadata) => {
|
|
9
9
|
if (debug) console.log("[Analytics] Phone click:", phoneNumber);
|
|
10
|
-
|
|
10
|
+
trackConversion2({
|
|
11
11
|
type: "phone_call",
|
|
12
12
|
metadata: {
|
|
13
13
|
phoneNumber: phoneNumber.replace(/\D/g, ""),
|
|
@@ -16,17 +16,17 @@ function useContactTracking(options = {}) {
|
|
|
16
16
|
...metadata
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
|
-
}, [
|
|
19
|
+
}, [trackConversion2, debug]);
|
|
20
20
|
const trackEmailClick = useCallback((email, metadata) => {
|
|
21
21
|
if (debug) console.log("[Analytics] Email click:", email);
|
|
22
|
-
|
|
22
|
+
trackConversion2({
|
|
23
23
|
type: "email_click",
|
|
24
24
|
metadata: {
|
|
25
25
|
email,
|
|
26
26
|
...metadata
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
-
}, [
|
|
29
|
+
}, [trackConversion2, debug]);
|
|
30
30
|
useEffect(() => {
|
|
31
31
|
if (!autoTrack || typeof document === "undefined") return;
|
|
32
32
|
const handleClick = (e) => {
|
|
@@ -65,5 +65,5 @@ function ContactTracking({ debug = false }) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export { ContactTracking, useContactTracking };
|
|
68
|
-
//# sourceMappingURL=chunk-
|
|
69
|
-
//# sourceMappingURL=chunk-
|
|
68
|
+
//# sourceMappingURL=chunk-AN4ATCYQ.mjs.map
|
|
69
|
+
//# sourceMappingURL=chunk-AN4ATCYQ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["trackConversion"],"mappings":"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","file":"chunk-AN4ATCYQ.mjs","sourcesContent":["/**\n * @sonordev/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkIBDVZ6BF_js = require('./chunk-IBDVZ6BF.js');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
|
|
7
7
|
function useContactTracking(options = {}) {
|
|
8
8
|
const { autoTrack = true, debug = false } = options;
|
|
9
|
-
const { trackConversion } =
|
|
9
|
+
const { trackConversion: trackConversion2 } = chunkIBDVZ6BF_js.useAnalytics();
|
|
10
10
|
const trackPhoneClick = react.useCallback((phoneNumber, metadata) => {
|
|
11
11
|
if (debug) console.log("[Analytics] Phone click:", phoneNumber);
|
|
12
|
-
|
|
12
|
+
trackConversion2({
|
|
13
13
|
type: "phone_call",
|
|
14
14
|
metadata: {
|
|
15
15
|
phoneNumber: phoneNumber.replace(/\D/g, ""),
|
|
@@ -18,17 +18,17 @@ function useContactTracking(options = {}) {
|
|
|
18
18
|
...metadata
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
|
-
}, [
|
|
21
|
+
}, [trackConversion2, debug]);
|
|
22
22
|
const trackEmailClick = react.useCallback((email, metadata) => {
|
|
23
23
|
if (debug) console.log("[Analytics] Email click:", email);
|
|
24
|
-
|
|
24
|
+
trackConversion2({
|
|
25
25
|
type: "email_click",
|
|
26
26
|
metadata: {
|
|
27
27
|
email,
|
|
28
28
|
...metadata
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
-
}, [
|
|
31
|
+
}, [trackConversion2, debug]);
|
|
32
32
|
react.useEffect(() => {
|
|
33
33
|
if (!autoTrack || typeof document === "undefined") return;
|
|
34
34
|
const handleClick = (e) => {
|
|
@@ -68,5 +68,5 @@ function ContactTracking({ debug = false }) {
|
|
|
68
68
|
|
|
69
69
|
exports.ContactTracking = ContactTracking;
|
|
70
70
|
exports.useContactTracking = useContactTracking;
|
|
71
|
-
//# sourceMappingURL=chunk-
|
|
72
|
-
//# sourceMappingURL=chunk-
|
|
71
|
+
//# sourceMappingURL=chunk-EBJ4S5DU.js.map
|
|
72
|
+
//# sourceMappingURL=chunk-EBJ4S5DU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["trackConversion","useAnalytics","useCallback","useEffect"],"mappings":"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","file":"chunk-EBJ4S5DU.js","sourcesContent":["/**\n * @sonordev/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/analytics/dispatch.ts
|
|
4
|
+
var MAX_QUEUE = 50;
|
|
5
|
+
var dispatcher = null;
|
|
6
|
+
var queue = [];
|
|
7
|
+
function registerAnalyticsDispatcher(next) {
|
|
8
|
+
dispatcher = next;
|
|
9
|
+
if (!next) return;
|
|
10
|
+
const pending = queue;
|
|
11
|
+
queue = [];
|
|
12
|
+
for (const call of pending) {
|
|
13
|
+
if (call.kind === "event") next.trackEvent(call.options);
|
|
14
|
+
else next.trackConversion(call.options);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function trackEvent(options) {
|
|
18
|
+
if (dispatcher) dispatcher.trackEvent(options);
|
|
19
|
+
else if (queue.length < MAX_QUEUE) queue.push({ kind: "event", options });
|
|
20
|
+
}
|
|
21
|
+
function trackConversion(options) {
|
|
22
|
+
if (dispatcher) dispatcher.trackConversion(options);
|
|
23
|
+
else if (queue.length < MAX_QUEUE) queue.push({ kind: "conversion", options });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.registerAnalyticsDispatcher = registerAnalyticsDispatcher;
|
|
27
|
+
exports.trackConversion = trackConversion;
|
|
28
|
+
exports.trackEvent = trackEvent;
|
|
29
|
+
//# sourceMappingURL=chunk-HMFFAUCD.js.map
|
|
30
|
+
//# sourceMappingURL=chunk-HMFFAUCD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/analytics/dispatch.ts"],"names":[],"mappings":";;;AA4BA,IAAM,SAAA,GAAY,EAAA;AAElB,IAAI,UAAA,GAAyC,IAAA;AAC7C,IAAI,QAAsB,EAAC;AAMpB,SAAS,4BAA4B,IAAA,EAAwC;AAClF,EAAA,UAAA,GAAa,IAAA;AACb,EAAA,IAAI,CAAC,IAAA,EAAM;AACX,EAAA,MAAM,OAAA,GAAU,KAAA;AAChB,EAAA,KAAA,GAAQ,EAAC;AACT,EAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,IAAA,IAAI,KAAK,IAAA,KAAS,OAAA,EAAS,IAAA,CAAK,UAAA,CAAW,KAAK,OAAO,CAAA;AAAA,SAClD,IAAA,CAAK,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAA;AAAA,EACxC;AACF;AAOO,SAAS,WAAW,OAAA,EAAkC;AAC3D,EAAA,IAAI,UAAA,EAAY,UAAA,CAAW,UAAA,CAAW,OAAO,CAAA;AAAA,OAAA,IACpC,KAAA,CAAM,SAAS,SAAA,EAAW,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,CAAA;AAC1E;AAGO,SAAS,gBAAgB,OAAA,EAAuC;AACrE,EAAA,IAAI,UAAA,EAAY,UAAA,CAAW,eAAA,CAAgB,OAAO,CAAA;AAAA,OAAA,IACzC,KAAA,CAAM,SAAS,SAAA,EAAW,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,CAAA;AAC/E","file":"chunk-HMFFAUCD.js","sourcesContent":["/**\n * @sonordev/site-kit — standalone analytics dispatch bridge\n *\n * The analytics API is hook-based (useAnalytics), which requires living\n * inside <AnalyticsProvider>. But the house perf pattern mounts the provider\n * as a childless deferred SIBLING of the page tree (see DeferredAnalytics on\n * reference sites), so page components — and sibling packages like\n * @sonordev/agency-site-kit — can never reach the context.\n *\n * This module is the bridge: AnalyticsProvider registers its trackEvent /\n * trackConversion here on mount (single source of payload construction — do\n * NOT re-implement the POST anywhere else), and the standalone functions\n * below queue until it does. If the provider never mounts, calls no-op after\n * the queue cap — tracking must never break a page.\n */\n\nimport type { TrackEventOptions, TrackConversionOptions } from './types'\n\ninterface AnalyticsDispatcher {\n trackEvent: (options: TrackEventOptions) => void\n trackConversion: (options: TrackConversionOptions) => void\n}\n\ntype QueuedCall =\n | { kind: 'event'; options: TrackEventOptions }\n | { kind: 'conversion'; options: TrackConversionOptions }\n\n/** Pre-mount buffer — bounded so a page without analytics can't grow it forever. */\nconst MAX_QUEUE = 50\n\nlet dispatcher: AnalyticsDispatcher | null = null\nlet queue: QueuedCall[] = []\n\n/**\n * Called by AnalyticsProvider on mount/unmount. Flushes anything queued\n * before the (idle-deferred) provider arrived.\n */\nexport function registerAnalyticsDispatcher(next: AnalyticsDispatcher | null): void {\n dispatcher = next\n if (!next) return\n const pending = queue\n queue = []\n for (const call of pending) {\n if (call.kind === 'event') next.trackEvent(call.options)\n else next.trackConversion(call.options)\n }\n}\n\n/**\n * Track a custom analytics event from anywhere client-side — no provider\n * context needed. Queues until AnalyticsProvider mounts; no-ops (bounded)\n * if it never does.\n */\nexport function trackEvent(options: TrackEventOptions): void {\n if (dispatcher) dispatcher.trackEvent(options)\n else if (queue.length < MAX_QUEUE) queue.push({ kind: 'event', options })\n}\n\n/** Conversion twin of {@link trackEvent}. */\nexport function trackConversion(options: TrackConversionOptions): void {\n if (dispatcher) dispatcher.trackConversion(options)\n else if (queue.length < MAX_QUEUE) queue.push({ kind: 'conversion', options })\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunkHMFFAUCD_js = require('./chunk-HMFFAUCD.js');
|
|
4
5
|
var chunk3BNFUMLL_js = require('./chunk-3BNFUMLL.js');
|
|
5
6
|
var react = require('react');
|
|
6
7
|
var navigation = require('next/navigation');
|
|
@@ -994,6 +995,10 @@ function AnalyticsProvider({
|
|
|
994
995
|
};
|
|
995
996
|
doTrack();
|
|
996
997
|
}, [propApiUrl, propApiKey, pathname, debug]);
|
|
998
|
+
react.useEffect(() => {
|
|
999
|
+
chunkHMFFAUCD_js.registerAnalyticsDispatcher({ trackEvent, trackConversion });
|
|
1000
|
+
return () => chunkHMFFAUCD_js.registerAnalyticsDispatcher(null);
|
|
1001
|
+
}, [trackEvent, trackConversion]);
|
|
997
1002
|
const contextValue = react.useMemo(() => ({
|
|
998
1003
|
trackEvent,
|
|
999
1004
|
trackConversion,
|
|
@@ -1033,5 +1038,5 @@ exports.WebVitals = WebVitals;
|
|
|
1033
1038
|
exports.useAnalytics = useAnalytics;
|
|
1034
1039
|
exports.useAnalyticsOptional = useAnalyticsOptional;
|
|
1035
1040
|
exports.useTrackEvent = useTrackEvent;
|
|
1036
|
-
//# sourceMappingURL=chunk-
|
|
1037
|
-
//# sourceMappingURL=chunk-
|
|
1041
|
+
//# sourceMappingURL=chunk-IBDVZ6BF.js.map
|
|
1042
|
+
//# sourceMappingURL=chunk-IBDVZ6BF.js.map
|