@sonordev/site-kit 2.7.2 → 2.7.3

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 (45) hide show
  1. package/dist/AnalyticsProvider-GWZR3ID7.mjs +4 -0
  2. package/dist/{AnalyticsProvider-VAAWDXH3.mjs.map → AnalyticsProvider-GWZR3ID7.mjs.map} +1 -1
  3. package/dist/AnalyticsProvider-NBKOHK5M.js +25 -0
  4. package/dist/{AnalyticsProvider-MY64KGIH.js.map → AnalyticsProvider-NBKOHK5M.js.map} +1 -1
  5. package/dist/analytics/index.d.mts +12 -2
  6. package/dist/analytics/index.d.ts +12 -2
  7. package/dist/analytics/index.js +9 -9
  8. package/dist/analytics/index.mjs +2 -2
  9. package/dist/{chunk-5OX347TD.js → chunk-4LC4KETS.js} +5 -5
  10. package/dist/{chunk-5OX347TD.js.map → chunk-4LC4KETS.js.map} +1 -1
  11. package/dist/{chunk-QBNA75GS.js → chunk-7NC3UQEE.js} +19 -4
  12. package/dist/chunk-7NC3UQEE.js.map +1 -0
  13. package/dist/{chunk-W5QMQMUS.mjs → chunk-FO5EUANA.mjs} +3 -3
  14. package/dist/{chunk-W5QMQMUS.mjs.map → chunk-FO5EUANA.mjs.map} +1 -1
  15. package/dist/{chunk-6EEXEVSE.mjs → chunk-IM57FXP7.mjs} +17 -5
  16. package/dist/chunk-IM57FXP7.mjs.map +1 -0
  17. package/dist/{chunk-LWJDQ2BT.js → chunk-LPSWITNZ.js} +4 -4
  18. package/dist/{chunk-LWJDQ2BT.js.map → chunk-LPSWITNZ.js.map} +1 -1
  19. package/dist/{chunk-UOB7WK3K.mjs → chunk-PMVEDBWP.mjs} +19 -4
  20. package/dist/chunk-PMVEDBWP.mjs.map +1 -0
  21. package/dist/{chunk-XCQ7BEZG.mjs → chunk-RSUNHEBH.mjs} +3 -3
  22. package/dist/{chunk-XCQ7BEZG.mjs.map → chunk-RSUNHEBH.mjs.map} +1 -1
  23. package/dist/{chunk-EJXWFTKA.js → chunk-SYNJOJTP.js} +17 -5
  24. package/dist/chunk-SYNJOJTP.js.map +1 -0
  25. package/dist/commerce/index.js +48 -48
  26. package/dist/commerce/index.mjs +3 -3
  27. package/dist/index.js +28 -28
  28. package/dist/index.mjs +3 -3
  29. package/dist/layout/client.d.mts +1 -1
  30. package/dist/layout/client.d.ts +1 -1
  31. package/dist/layout/client.js +2 -2
  32. package/dist/layout/client.mjs +1 -1
  33. package/dist/layout/index.d.mts +1 -1
  34. package/dist/layout/index.d.ts +1 -1
  35. package/dist/layout/index.js +2 -2
  36. package/dist/layout/index.mjs +1 -1
  37. package/dist/{types-5RCOK10v.d.ts → types-YXQAZGpe.d.mts} +9 -0
  38. package/dist/{types-5RCOK10v.d.mts → types-YXQAZGpe.d.ts} +9 -0
  39. package/package.json +1 -1
  40. package/dist/AnalyticsProvider-MY64KGIH.js +0 -25
  41. package/dist/AnalyticsProvider-VAAWDXH3.mjs +0 -4
  42. package/dist/chunk-6EEXEVSE.mjs.map +0 -1
  43. package/dist/chunk-EJXWFTKA.js.map +0 -1
  44. package/dist/chunk-QBNA75GS.js.map +0 -1
  45. package/dist/chunk-UOB7WK3K.mjs.map +0 -1
@@ -57,7 +57,7 @@ function SiteKitIdentityProvider({
57
57
  return /* @__PURE__ */ jsxRuntime.jsx(SiteKitIdentityContext.Provider, { value, children });
58
58
  }
59
59
  var LazyAnalyticsProvider = dynamic__default.default(
60
- () => import('./AnalyticsProvider-MY64KGIH.js').then((m) => ({ default: m.AnalyticsProvider })),
60
+ () => import('./AnalyticsProvider-NBKOHK5M.js').then((m) => ({ default: m.AnalyticsProvider })),
61
61
  { ssr: false }
62
62
  );
63
63
  var LazyEngageWidget = dynamic__default.default(
@@ -83,10 +83,25 @@ function SiteKitClientProviders({
83
83
  sitemapSync = true,
84
84
  debug = false
85
85
  }) {
86
+ const analyticsConfig = typeof analytics === "object" ? analytics : {};
87
+ const explicitSite = analyticsConfig.site;
88
+ const envSiteUrl = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_SITE_URL : void 0;
89
+ let resolvedSite = explicitSite ?? "";
90
+ if (!resolvedSite && envSiteUrl) {
91
+ try {
92
+ resolvedSite = new URL(envSiteUrl).host;
93
+ } catch {
94
+ }
95
+ }
96
+ if (!resolvedSite && typeof window !== "undefined") {
97
+ resolvedSite = window.location.host;
98
+ }
99
+ const site = resolvedSite;
86
100
  if (typeof window !== "undefined") {
87
101
  window.__SITE_KIT_API_URL__ = apiUrl;
88
102
  window.__SITE_KIT_API_KEY__ = apiKey;
89
103
  window.__SITE_KIT_DEBUG__ = debug;
104
+ window.__SITE_KIT_SITE__ = site;
90
105
  }
91
106
  const [visitorId] = react.useState(() => getOrCreateVisitorId());
92
107
  const [sessionId] = react.useState(() => getOrCreateSessionId());
@@ -112,7 +127,6 @@ function SiteKitClientProviders({
112
127
  );
113
128
  }
114
129
  if (analytics) {
115
- const analyticsConfig = typeof analytics === "object" ? analytics : {};
116
130
  content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
117
131
  content,
118
132
  /* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -120,6 +134,7 @@ function SiteKitClientProviders({
120
134
  {
121
135
  apiUrl,
122
136
  apiKey,
137
+ site,
123
138
  trackPageViews: analyticsConfig.trackPageViews !== false,
124
139
  trackWebVitals: analyticsConfig.trackWebVitals !== false,
125
140
  trackScrollDepth: analyticsConfig.trackScrollDepth !== false,
@@ -158,5 +173,5 @@ function SiteKitClientProviders({
158
173
  }
159
174
 
160
175
  exports.SiteKitClientProviders = SiteKitClientProviders;
161
- //# sourceMappingURL=chunk-QBNA75GS.js.map
162
- //# sourceMappingURL=chunk-QBNA75GS.js.map
176
+ //# sourceMappingURL=chunk-7NC3UQEE.js.map
177
+ //# sourceMappingURL=chunk-7NC3UQEE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/identity.tsx","../src/layout/SiteKitClientProviders.tsx"],"names":["createContext","useMemo","jsx","dynamic","useState","useRef","useCallback","Fragment","jsxs","Suspense"],"mappings":"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","file":"chunk-7NC3UQEE.js","sourcesContent":["/**\n * @sonordev/site-kit/shared — Unified Identity Management\n *\n * Single source of truth for visitor and session IDs across\n * Analytics, Signal, and Engage modules.\n *\n * Storage keys:\n * localStorage: _sk_vid (visitor ID, persists ~forever)\n * sessionStorage: _sk_sid (session ID, per-tab)\n * sessionStorage: _sk_stime (last activity timestamp for timeout)\n *\n * Storage keys are prefixed with `_sk_*`.\n */\n\n'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\n// ============================================\n// ID Generation\n// ============================================\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * Get or create a persistent visitor ID.\n * Stored in localStorage under `_sk_vid`.\n */\nexport function getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n let visitorId = localStorage.getItem('_sk_vid')\n\n if (!visitorId) {\n visitorId = generateId()\n }\n\n localStorage.setItem('_sk_vid', visitorId)\n return visitorId\n}\n\n/**\n * Get or create a session ID with inactivity timeout.\n * Stored in sessionStorage under `_sk_sid`.\n * Session expires after `timeoutMinutes` of inactivity (default 30).\n */\nexport function getOrCreateSessionId(timeoutMinutes = 30): string {\n if (typeof window === 'undefined') return ''\n\n const now = Date.now()\n const timeoutMs = timeoutMinutes * 60 * 1000\n\n const existingSession = sessionStorage.getItem('_sk_sid')\n const lastActivity = sessionStorage.getItem('_sk_stime')\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n // Session still active — refresh timestamp\n sessionStorage.setItem('_sk_stime', now.toString())\n sessionStorage.setItem('_sk_sid', existingSession)\n return existingSession\n }\n }\n\n // New session (first visit or timeout expired)\n const newSession = generateId()\n sessionStorage.setItem('_sk_sid', newSession)\n sessionStorage.setItem('_sk_stime', now.toString())\n return newSession\n}\n\n// ============================================\n// React Context\n// ============================================\n\nexport interface SiteKitIdentity {\n visitorId: string\n sessionId: string\n}\n\nconst SiteKitIdentityContext = createContext<SiteKitIdentity | null>(null)\n\nexport interface SiteKitIdentityProviderProps {\n visitorId: string\n sessionId: string\n children: React.ReactNode\n}\n\nexport function SiteKitIdentityProvider({\n visitorId,\n sessionId,\n children,\n}: SiteKitIdentityProviderProps) {\n const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId])\n\n return (\n <SiteKitIdentityContext.Provider value={value}>\n {children}\n </SiteKitIdentityContext.Provider>\n )\n}\n\n/**\n * Access the shared visitor/session identity.\n * Falls back to generating IDs directly if used outside of SiteKitIdentityProvider.\n */\nexport function useSiteKitIdentity(): SiteKitIdentity {\n const context = useContext(SiteKitIdentityContext)\n if (context) return context\n\n // Fallback for standalone usage outside SiteKitLayout\n return {\n visitorId: getOrCreateVisitorId(),\n sessionId: getOrCreateSessionId(),\n }\n}\n","'use client'\n\n/**\n * SiteKitClientProviders — Client Island\n *\n * This is the 'use client' boundary for SiteKitLayout.\n * It composes the client-only providers (Analytics, Engage, Signal, SitemapSync)\n * that require React context or browser APIs.\n *\n * All modules are lazy-loaded via next/dynamic so their JS is only downloaded\n * when the feature is enabled — keeping the initial bundle lightweight.\n *\n * All modules share a unified identity (visitor ID + session ID) via\n * SiteKitIdentityProvider, ensuring consistent tracking across Analytics,\n * Signal, and Engage.\n *\n * Props are passed down from the server-side SiteKitLayout component,\n * which reads env vars at render time.\n */\n\nimport React, { Suspense, useCallback, useRef, useState, type ReactNode } from 'react'\nimport dynamic from 'next/dynamic'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\n// Lazy-load feature modules — JS only downloaded when feature is enabled\nconst LazyAnalyticsProvider = dynamic(\n () => import('../analytics/AnalyticsProvider').then(m => ({ default: m.AnalyticsProvider })),\n { ssr: false },\n)\nconst LazyEngageWidget = dynamic(\n () => import('../engage/EngageWidget').then(m => ({ default: m.EngageWidget })),\n { ssr: false },\n)\nconst LazySignalBridge = dynamic(\n () => import('../signal/SignalBridge').then(m => ({ default: m.SignalBridge })),\n { ssr: false },\n)\nconst LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n\nexport interface SiteKitClientProvidersProps {\n children: ReactNode\n apiKey: string\n apiUrl: string\n projectId?: string\n analytics?: boolean | AnalyticsConfig\n engage?: boolean | EngageConfig\n signal?: boolean | SignalConfig\n sitemapSync?: boolean\n debug?: boolean\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // Hoist analytics config so the `site` dimension is resolvable up here.\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n\n // Resolve the sub-site identifier — the dimension that lets one Sonor project\n // host many sites (e.g. truepowersystems.com + ohiopowerstudies.com under one\n // TPS project). Precedence: explicit `analytics.site` > NEXT_PUBLIC_SITE_URL\n // host > window.location.host. Always a string (possibly empty).\n const explicitSite = analyticsConfig.site\n const envSiteUrl =\n typeof process !== 'undefined'\n ? process.env.NEXT_PUBLIC_SITE_URL\n : undefined\n let resolvedSite = explicitSite ?? ''\n if (!resolvedSite && envSiteUrl) {\n try {\n resolvedSite = new URL(envSiteUrl).host\n } catch {\n /* malformed URL — fall through to client-side host */\n }\n }\n if (!resolvedSite && typeof window !== 'undefined') {\n resolvedSite = window.location.host\n }\n const site = resolvedSite\n\n // Set window globals for modules that still read from them.\n if (typeof window !== 'undefined') {\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = apiKey\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n ;(window as any).__SITE_KIT_SITE__ = site\n }\n\n // Unified identity — single source of truth for all modules\n const [visitorId] = useState(() => getOrCreateVisitorId())\n const [sessionId] = useState(() => getOrCreateSessionId())\n\n // Page metadata bridge: Analytics writes, Signal reads\n const pageMetadataRef = useRef<Record<string, unknown> | null>(null)\n const onPageMetadata = useCallback((metadata: Record<string, unknown>) => {\n pageMetadataRef.current = metadata\n }, [])\n\n let content = <>{children}</>\n\n // Wrap with SignalBridge if enabled.\n // NOTE: SignalBridge still wraps {content} and is dynamic(ssr:false) — the\n // same SSR-de-opt caveat as Analytics applies. It is left wrapping because\n // A/B experiment variant swapping may depend on enclosing page content; if a\n // site enables `signal` and SSR breaks, convert this to a sibling too.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <LazySignalBridge\n enabled\n realtime={signalConfig.realtime !== false}\n experiments={signalConfig.experiments !== false}\n behaviorTracking={signalConfig.behaviorTracking !== false}\n visitorId={visitorId}\n sessionId={sessionId}\n pageMetadataRef={pageMetadataRef}\n >\n {content}\n </LazySignalBridge>\n )\n }\n\n // Add Analytics if enabled (renders alongside, doesn't wrap).\n //\n // CRITICAL: LazyAnalyticsProvider is dynamic(..., { ssr: false }). Wrapping\n // {content} inside an ssr:false component makes the entire page tree skip\n // server rendering — the route de-opts to 100% client rendering and the\n // hero / LCP element only paints after hydration (mobile LCP ~4s, Lighthouse\n // ~85). Analytics tracks via effects + a metadata ref, so it never needs to\n // wrap page content — mount it as a childless sibling, exactly like Engage.\n if (analytics) {\n content = (\n <>\n {content}\n <Suspense fallback={null}>\n <LazyAnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n </>\n )\n }\n\n // Add Engage widget if enabled (renders alongside, doesn't wrap)\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n content = (\n <>\n {content}\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n <LazySitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { useAnalytics } from './chunk-6EEXEVSE.mjs';
2
+ import { useAnalytics } from './chunk-IM57FXP7.mjs';
3
3
  import { useCallback, useEffect } from 'react';
4
4
 
5
5
  function useContactTracking(options = {}) {
@@ -65,5 +65,5 @@ function ContactTracking({ debug = false }) {
65
65
  }
66
66
 
67
67
  export { ContactTracking, useContactTracking };
68
- //# sourceMappingURL=chunk-W5QMQMUS.mjs.map
69
- //# sourceMappingURL=chunk-W5QMQMUS.mjs.map
68
+ //# sourceMappingURL=chunk-FO5EUANA.mjs.map
69
+ //# sourceMappingURL=chunk-FO5EUANA.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":[],"mappings":"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","file":"chunk-W5QMQMUS.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
+ {"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":[],"mappings":"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","file":"chunk-FO5EUANA.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"]}
@@ -9,7 +9,7 @@ function getApiConfig() {
9
9
  const apiKey = typeof window !== "undefined" ? window.__SITE_KIT_API_KEY__ : void 0;
10
10
  return { apiUrl, apiKey };
11
11
  }
12
- function WebVitals({ apiUrl: propApiUrl, apiKey: propApiKey, debug = false }) {
12
+ function WebVitals({ apiUrl: propApiUrl, apiKey: propApiKey, site: propSite, debug = false }) {
13
13
  const pathname = usePathname();
14
14
  useEffect(() => {
15
15
  import('./web-vitals-KPICZIEF.mjs').then(({ onCLS, onLCP, onTTFB, onINP, onFCP }) => {
@@ -22,12 +22,14 @@ function WebVitals({ apiUrl: propApiUrl, apiKey: propApiKey, debug = false }) {
22
22
  const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig();
23
23
  const apiUrl = propApiUrl || globalApiUrl;
24
24
  const apiKey = propApiKey || globalApiKey;
25
+ const site = propSite || (typeof window !== "undefined" ? window.__SITE_KIT_SITE__ || window.location.host : "");
25
26
  if (!apiKey) {
26
27
  if (debug) console.warn("[Analytics] No API key configured for Web Vitals");
27
28
  return;
28
29
  }
29
30
  for (const [name, value] of Object.entries(vitals)) {
30
31
  const data = {
32
+ site,
31
33
  pagePath: pathname,
32
34
  metricName: name,
33
35
  metricValue: value,
@@ -84,7 +86,7 @@ function WebVitals({ apiUrl: propApiUrl, apiKey: propApiKey, debug = false }) {
84
86
  }).catch((err) => {
85
87
  if (debug) console.warn("[Analytics] Web Vitals import failed:", err);
86
88
  });
87
- }, [pathname, propApiUrl, propApiKey, debug]);
89
+ }, [pathname, propApiUrl, propApiKey, propSite, debug]);
88
90
  return null;
89
91
  }
90
92
  function getRating(name, value) {
@@ -507,10 +509,12 @@ function AnalyticsProvider({
507
509
  debug = false,
508
510
  externalVisitorId,
509
511
  externalSessionId,
510
- onPageMetadata
512
+ onPageMetadata,
513
+ site: propSite
511
514
  }) {
512
515
  const pathname = usePathname();
513
516
  const [queryString, setQueryString] = useState("");
517
+ const site = propSite || (typeof window !== "undefined" ? window.__SITE_KIT_SITE__ || window.location.host : "");
514
518
  useEffect(() => {
515
519
  if (typeof window === "undefined") return;
516
520
  setQueryString(window.location.search);
@@ -599,6 +603,7 @@ function AnalyticsProvider({
599
603
  const pageView = {
600
604
  sessionId: sessionIdRef.current,
601
605
  visitorId: visitorIdRef.current,
606
+ site,
602
607
  pagePath: normalizedPath,
603
608
  pageTitle: document.title,
604
609
  referrer: document.referrer || null,
@@ -670,6 +675,7 @@ function AnalyticsProvider({
670
675
  const sessionData = {
671
676
  sessionId: sessionIdRef.current,
672
677
  visitorId: visitorIdRef.current,
678
+ site,
673
679
  action: isNewSession ? "start" : "update",
674
680
  lastPage: pathname,
675
681
  userAgent: getUserAgent(),
@@ -716,6 +722,7 @@ function AnalyticsProvider({
716
722
  const duration = Math.round((Date.now() - journeyStartTimeRef.current) / 1e3);
717
723
  const payload = JSON.stringify({
718
724
  sessionId: sessionIdRef.current,
725
+ site,
719
726
  action: "end",
720
727
  duration,
721
728
  lastPage: pathname,
@@ -782,6 +789,7 @@ function AnalyticsProvider({
782
789
  const payload = JSON.stringify({
783
790
  sessionId: sessionIdRef.current,
784
791
  visitorId: visitorIdRef.current,
792
+ site,
785
793
  pagePath: pathname,
786
794
  maxDepthPercent: maxDepth,
787
795
  timeTo25: milestone25,
@@ -859,6 +867,7 @@ function AnalyticsProvider({
859
867
  const elementText = target.textContent?.slice(0, 50) || null;
860
868
  const clickData = {
861
869
  sessionId: sessionIdRef.current,
870
+ site,
862
871
  pagePath: pathname,
863
872
  xPercent,
864
873
  yPercent,
@@ -905,6 +914,7 @@ function AnalyticsProvider({
905
914
  const event = {
906
915
  sessionId: sessionIdRef.current,
907
916
  visitorId: visitorIdRef.current,
917
+ site,
908
918
  eventName: options.name,
909
919
  eventCategory: options.category,
910
920
  eventLabel: options.label,
@@ -945,6 +955,7 @@ function AnalyticsProvider({
945
955
  const conversion = {
946
956
  sessionId: sessionIdRef.current,
947
957
  visitorId: visitorIdRef.current,
958
+ site,
948
959
  conversionType: options.type,
949
960
  value: options.value,
950
961
  currency: options.currency,
@@ -986,6 +997,7 @@ function AnalyticsProvider({
986
997
  {
987
998
  apiUrl: propApiUrl,
988
999
  apiKey: propApiKey,
1000
+ site,
989
1001
  debug
990
1002
  }
991
1003
  ),
@@ -1008,5 +1020,5 @@ function useTrackEvent() {
1008
1020
  }
1009
1021
 
1010
1022
  export { AnalyticsProvider, WebVitals, useAnalytics, useAnalyticsOptional, useTrackEvent };
1011
- //# sourceMappingURL=chunk-6EEXEVSE.mjs.map
1012
- //# sourceMappingURL=chunk-6EEXEVSE.mjs.map
1023
+ //# sourceMappingURL=chunk-IM57FXP7.mjs.map
1024
+ //# sourceMappingURL=chunk-IM57FXP7.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/analytics/WebVitals.tsx","../src/analytics/AnalyticsProvider.tsx"],"names":["wordCount","getApiConfig","usePathname","useEffect"],"mappings":"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","file":"chunk-IM57FXP7.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 } 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 useEffect(() => {\n // Dynamic import to avoid SSR issues; catch ChunkLoadError (e.g. Turbopack dev)\n import('web-vitals').then(({ onCLS, onLCP, onTTFB, onINP, onFCP }) => {\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: pathname,\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 return () => {\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n clearTimeout(timeout)\n }\n }).catch((err) => {\n // ChunkLoadError in Turbopack/dev - Web Vitals are optional\n if (debug) console.warn('[Analytics] Web Vitals import failed:', err)\n })\n }, [pathname, propApiUrl, propApiKey, propSite, debug])\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 { WebVitals } from './WebVitals'\n\nconst AnalyticsContext = createContext<AnalyticsContextValue | null>(null)\n\n// ============================================\n// Utility Functions\n// ============================================\n\nfunction generateId(): string {\n return crypto.randomUUID()\n}\n\n/**\n * Schedule a callback to run during browser idle time\n * Falls back to setTimeout(0) for Safari\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, 0)\n }\n}\n\nfunction getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n let visitorId = localStorage.getItem('_sk_vid')\n\n if (!visitorId) {\n visitorId = generateId()\n }\n\n localStorage.setItem('_sk_vid', visitorId)\n return visitorId\n}\n\nfunction getSessionId(timeout: number): string {\n if (typeof window === 'undefined') return ''\n\n const now = Date.now()\n const timeoutMs = timeout * 60 * 1000\n\n const existingSession = sessionStorage.getItem('_sk_sid')\n const lastActivity = sessionStorage.getItem('_sk_stime')\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n sessionStorage.setItem('_sk_sid', existingSession)\n sessionStorage.setItem('_sk_stime', now.toString())\n return existingSession\n }\n }\n\n // New session\n const newSession = generateId()\n sessionStorage.setItem('_sk_sid', newSession)\n sessionStorage.setItem('_sk_stime', now.toString())\n return newSession\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 * Extract SEO metadata from the current page\n * This enriches seo_pages with live data from the actual page\n */\nfunction getPageMetadata(): 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 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 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 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 imageStats = getImageStats()\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 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 wordCount,\n imagesCount: imageStats.count,\n imagesWithoutAlt: imageStats.withoutAlt,\n images: imageStats.images, // Full image details for SEO optimization\n internalLinks: linkStats.internal,\n internalLinkTargets: linkStats.internalLinks, // Full link graph data\n externalLinks: linkStats.external,\n // NEW: 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\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 || getSessionId(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 const pageMetadata = getPageMetadata()\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: document.title,\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 on page unload\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('beforeunload', handleUnload)\n\n return () => {\n window.removeEventListener('beforeunload', 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 // Send on page unload or visibility change - use beacon for reliability\n const handleBeforeUnload = () => sendScrollData(true)\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'hidden') sendScrollData(true)\n }\n\n window.addEventListener('beforeunload', handleBeforeUnload)\n document.addEventListener('visibilitychange', handleVisibilityChange)\n\n return () => {\n window.removeEventListener('scroll', handleScroll)\n window.removeEventListener('beforeunload', handleBeforeUnload)\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 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,12 +1,12 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkEJXWFTKA_js = require('./chunk-EJXWFTKA.js');
4
+ var chunkSYNJOJTP_js = require('./chunk-SYNJOJTP.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 } = chunkEJXWFTKA_js.useAnalytics();
9
+ const { trackConversion } = chunkSYNJOJTP_js.useAnalytics();
10
10
  const trackPhoneClick = react.useCallback((phoneNumber, metadata) => {
11
11
  if (debug) console.log("[Analytics] Phone click:", phoneNumber);
12
12
  trackConversion({
@@ -68,5 +68,5 @@ function ContactTracking({ debug = false }) {
68
68
 
69
69
  exports.ContactTracking = ContactTracking;
70
70
  exports.useContactTracking = useContactTracking;
71
- //# sourceMappingURL=chunk-LWJDQ2BT.js.map
72
- //# sourceMappingURL=chunk-LWJDQ2BT.js.map
71
+ //# sourceMappingURL=chunk-LPSWITNZ.js.map
72
+ //# sourceMappingURL=chunk-LPSWITNZ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["useAnalytics","useCallback","useEffect"],"mappings":"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","file":"chunk-LWJDQ2BT.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"]}
1
+ {"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["useAnalytics","useCallback","useEffect"],"mappings":"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","file":"chunk-LPSWITNZ.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"]}
@@ -51,7 +51,7 @@ function SiteKitIdentityProvider({
51
51
  return /* @__PURE__ */ jsx(SiteKitIdentityContext.Provider, { value, children });
52
52
  }
53
53
  var LazyAnalyticsProvider = dynamic(
54
- () => import('./AnalyticsProvider-VAAWDXH3.mjs').then((m) => ({ default: m.AnalyticsProvider })),
54
+ () => import('./AnalyticsProvider-GWZR3ID7.mjs').then((m) => ({ default: m.AnalyticsProvider })),
55
55
  { ssr: false }
56
56
  );
57
57
  var LazyEngageWidget = dynamic(
@@ -77,10 +77,25 @@ function SiteKitClientProviders({
77
77
  sitemapSync = true,
78
78
  debug = false
79
79
  }) {
80
+ const analyticsConfig = typeof analytics === "object" ? analytics : {};
81
+ const explicitSite = analyticsConfig.site;
82
+ const envSiteUrl = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_SITE_URL : void 0;
83
+ let resolvedSite = explicitSite ?? "";
84
+ if (!resolvedSite && envSiteUrl) {
85
+ try {
86
+ resolvedSite = new URL(envSiteUrl).host;
87
+ } catch {
88
+ }
89
+ }
90
+ if (!resolvedSite && typeof window !== "undefined") {
91
+ resolvedSite = window.location.host;
92
+ }
93
+ const site = resolvedSite;
80
94
  if (typeof window !== "undefined") {
81
95
  window.__SITE_KIT_API_URL__ = apiUrl;
82
96
  window.__SITE_KIT_API_KEY__ = apiKey;
83
97
  window.__SITE_KIT_DEBUG__ = debug;
98
+ window.__SITE_KIT_SITE__ = site;
84
99
  }
85
100
  const [visitorId] = useState(() => getOrCreateVisitorId());
86
101
  const [sessionId] = useState(() => getOrCreateSessionId());
@@ -106,7 +121,6 @@ function SiteKitClientProviders({
106
121
  );
107
122
  }
108
123
  if (analytics) {
109
- const analyticsConfig = typeof analytics === "object" ? analytics : {};
110
124
  content = /* @__PURE__ */ jsxs(Fragment, { children: [
111
125
  content,
112
126
  /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
@@ -114,6 +128,7 @@ function SiteKitClientProviders({
114
128
  {
115
129
  apiUrl,
116
130
  apiKey,
131
+ site,
117
132
  trackPageViews: analyticsConfig.trackPageViews !== false,
118
133
  trackWebVitals: analyticsConfig.trackWebVitals !== false,
119
134
  trackScrollDepth: analyticsConfig.trackScrollDepth !== false,
@@ -152,5 +167,5 @@ function SiteKitClientProviders({
152
167
  }
153
168
 
154
169
  export { SiteKitClientProviders };
155
- //# sourceMappingURL=chunk-UOB7WK3K.mjs.map
156
- //# sourceMappingURL=chunk-UOB7WK3K.mjs.map
170
+ //# sourceMappingURL=chunk-PMVEDBWP.mjs.map
171
+ //# sourceMappingURL=chunk-PMVEDBWP.mjs.map