@sonordev/site-kit 3.2.1 → 3.3.0
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/agent-manifest.json +1 -1
- package/dist/AnalyticsProvider-26VS3CQR.js +29 -0
- package/dist/{AnalyticsProvider-A3STXJ65.js.map → AnalyticsProvider-26VS3CQR.js.map} +1 -1
- package/dist/{AnalyticsProvider-LEXGFM2K.mjs → AnalyticsProvider-AMHG4DIE.mjs} +5 -5
- package/dist/{AnalyticsProvider-LEXGFM2K.mjs.map → AnalyticsProvider-AMHG4DIE.mjs.map} +1 -1
- package/dist/ChatWidget-NIYNSMLU.js +17 -0
- package/dist/{ChatWidget-U3K2VHVN.js.map → ChatWidget-NIYNSMLU.js.map} +1 -1
- package/dist/ChatWidget-UKPEQEHB.mjs +8 -0
- package/dist/{ChatWidget-4QR2ZDRE.mjs.map → ChatWidget-UKPEQEHB.mjs.map} +1 -1
- package/dist/EngageWidget-33QCFWQW.js +16 -0
- package/dist/{EngageWidget-TOGMQ2G6.js.map → EngageWidget-33QCFWQW.js.map} +1 -1
- package/dist/EngageWidget-S76ZMDEF.mjs +7 -0
- package/dist/{EngageWidget-2FMKYJJT.mjs.map → EngageWidget-S76ZMDEF.mjs.map} +1 -1
- package/dist/{SignalCore-5QJG3IJB.mjs → SignalCore-2AUGAOQT.mjs} +4 -4
- package/dist/{SignalCore-5QJG3IJB.mjs.map → SignalCore-2AUGAOQT.mjs.map} +1 -1
- package/dist/{SignalCore-JB3VHHTG.js → SignalCore-2UXXM4FF.js} +8 -8
- package/dist/{SignalCore-JB3VHHTG.js.map → SignalCore-2UXXM4FF.js.map} +1 -1
- package/dist/SitemapSync-RBHXPQAQ.mjs +6 -0
- package/dist/{SitemapSync-T6PIDW64.mjs.map → SitemapSync-RBHXPQAQ.mjs.map} +1 -1
- package/dist/SitemapSync-WQJMHJNY.js +15 -0
- package/dist/{SitemapSync-BJWSTERT.js.map → SitemapSync-WQJMHJNY.js.map} +1 -1
- package/dist/analytics/index.js +11 -11
- package/dist/analytics/index.mjs +4 -4
- package/dist/{chunk-5ZNKNNJ4.mjs → chunk-2RLG4KBJ.mjs} +4 -4
- package/dist/{chunk-5ZNKNNJ4.mjs.map → chunk-2RLG4KBJ.mjs.map} +1 -1
- package/dist/{chunk-DYCEEU67.mjs → chunk-5KVT66R6.mjs} +3 -3
- package/dist/{chunk-DYCEEU67.mjs.map → chunk-5KVT66R6.mjs.map} +1 -1
- package/dist/{chunk-7OK6BI3A.mjs → chunk-6BDXN4X3.mjs} +3 -3
- package/dist/{chunk-7OK6BI3A.mjs.map → chunk-6BDXN4X3.mjs.map} +1 -1
- package/dist/{chunk-52VXHSVT.js → chunk-6UK5JIKE.js} +3 -3
- package/dist/{chunk-52VXHSVT.js.map → chunk-6UK5JIKE.js.map} +1 -1
- package/dist/{chunk-VTHCUHMK.mjs → chunk-AXFM4MFK.mjs} +8 -8
- package/dist/{chunk-VTHCUHMK.mjs.map → chunk-AXFM4MFK.mjs.map} +1 -1
- package/dist/{chunk-BNBCSHTK.js → chunk-BOTWTNHW.js} +12 -12
- package/dist/{chunk-BNBCSHTK.js.map → chunk-BOTWTNHW.js.map} +1 -1
- package/dist/{chunk-5RX4CUR2.js → chunk-BPKDRTEA.js} +97 -22
- package/dist/chunk-BPKDRTEA.js.map +1 -0
- package/dist/{chunk-NDROQRDB.js → chunk-EL6ZMYD2.js} +6 -6
- package/dist/{chunk-NDROQRDB.js.map → chunk-EL6ZMYD2.js.map} +1 -1
- package/dist/{chunk-SGPIGHMN.js → chunk-EM4DFSC5.js} +4 -4
- package/dist/{chunk-SGPIGHMN.js.map → chunk-EM4DFSC5.js.map} +1 -1
- package/dist/chunk-EOENN46G.js +8 -0
- package/dist/{chunk-WAAFJPNR.js.map → chunk-EOENN46G.js.map} +1 -1
- package/dist/{chunk-SBT4J733.mjs → chunk-FO6Y27AH.mjs} +3 -3
- package/dist/{chunk-SBT4J733.mjs.map → chunk-FO6Y27AH.mjs.map} +1 -1
- package/dist/{chunk-B5YNHSRA.js → chunk-FX3VR4BF.js} +7 -7
- package/dist/{chunk-B5YNHSRA.js.map → chunk-FX3VR4BF.js.map} +1 -1
- package/dist/{chunk-DCZUMCEC.js → chunk-G4FJJK6J.js} +14 -14
- package/dist/{chunk-DCZUMCEC.js.map → chunk-G4FJJK6J.js.map} +1 -1
- package/dist/{chunk-MYAXI33P.js → chunk-I2M533CW.js} +8 -8
- package/dist/{chunk-MYAXI33P.js.map → chunk-I2M533CW.js.map} +1 -1
- package/dist/{chunk-AMBTOIYM.mjs → chunk-ILLOVVVP.mjs} +91 -16
- package/dist/chunk-ILLOVVVP.mjs.map +1 -0
- package/dist/{chunk-LF3ID6WN.js → chunk-K2P7KPEQ.js} +20 -12
- package/dist/chunk-K2P7KPEQ.js.map +1 -0
- package/dist/{chunk-GMSPDTEV.js → chunk-M2EGCGIT.js} +7 -7
- package/dist/{chunk-GMSPDTEV.js.map → chunk-M2EGCGIT.js.map} +1 -1
- package/dist/{chunk-GMO6POZ2.mjs → chunk-M4HLDK62.mjs} +3 -3
- package/dist/{chunk-GMO6POZ2.mjs.map → chunk-M4HLDK62.mjs.map} +1 -1
- package/dist/{chunk-IR5UC236.mjs → chunk-NNPF4KRZ.mjs} +3 -3
- package/dist/{chunk-IR5UC236.mjs.map → chunk-NNPF4KRZ.mjs.map} +1 -1
- package/dist/{chunk-E7M5MDGC.js → chunk-P3QZRG2Z.js} +15 -15
- package/dist/{chunk-E7M5MDGC.js.map → chunk-P3QZRG2Z.js.map} +1 -1
- package/dist/{chunk-XHEXIYKY.mjs → chunk-PLQ4CUNI.mjs} +4 -4
- package/dist/{chunk-XHEXIYKY.mjs.map → chunk-PLQ4CUNI.mjs.map} +1 -1
- package/dist/{chunk-BUCF5FUY.mjs → chunk-PUGRSMAV.mjs} +3 -3
- package/dist/{chunk-BUCF5FUY.mjs.map → chunk-PUGRSMAV.mjs.map} +1 -1
- package/dist/{chunk-NJIHMZPC.js → chunk-QOFC3BYG.js} +5 -5
- package/dist/{chunk-NJIHMZPC.js.map → chunk-QOFC3BYG.js.map} +1 -1
- package/dist/chunk-S4FJIG6Y.mjs +6 -0
- package/dist/{chunk-QLM7RNQI.mjs.map → chunk-S4FJIG6Y.mjs.map} +1 -1
- package/dist/{chunk-NQ2P7AB3.mjs → chunk-SLOZWRWU.mjs} +4 -4
- package/dist/{chunk-NQ2P7AB3.mjs.map → chunk-SLOZWRWU.mjs.map} +1 -1
- package/dist/{chunk-XM67L4HL.js → chunk-WAYG3LS2.js} +14 -14
- package/dist/{chunk-XM67L4HL.js.map → chunk-WAYG3LS2.js.map} +1 -1
- package/dist/{chunk-7R7SGJG3.mjs → chunk-WEHJRE3H.mjs} +13 -5
- package/dist/chunk-WEHJRE3H.mjs.map +1 -0
- package/dist/{chunk-E4TWVVSW.mjs → chunk-X72PFC4X.mjs} +4 -4
- package/dist/{chunk-E4TWVVSW.mjs.map → chunk-X72PFC4X.mjs.map} +1 -1
- package/dist/{chunk-MX6DK246.js → chunk-XOCQANYF.js} +13 -13
- package/dist/{chunk-MX6DK246.js.map → chunk-XOCQANYF.js.map} +1 -1
- package/dist/{chunk-MKZHVSKL.mjs → chunk-ZCZEKWFW.mjs} +3 -3
- package/dist/{chunk-MKZHVSKL.mjs.map → chunk-ZCZEKWFW.mjs.map} +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.mjs +1 -1
- package/dist/commerce/index.js +50 -50
- package/dist/commerce/index.mjs +5 -5
- package/dist/engage/index.js +8 -8
- package/dist/engage/index.mjs +5 -5
- package/dist/fleet/index.js +7 -7
- package/dist/fleet/index.mjs +3 -3
- package/dist/forms/index.js +12 -12
- package/dist/forms/index.mjs +4 -4
- package/dist/images/index.js +10 -10
- package/dist/images/index.mjs +3 -3
- package/dist/index.js +63 -63
- package/dist/index.mjs +9 -9
- package/dist/layout/client.js +6 -6
- package/dist/layout/client.mjs +5 -5
- package/dist/layout/index.js +7 -7
- package/dist/layout/index.mjs +5 -5
- package/dist/maps/index.js +4 -4
- package/dist/maps/index.mjs +2 -2
- package/dist/seo/client.js +4 -4
- package/dist/seo/client.mjs +3 -3
- package/dist/seo/index.js +4 -4
- package/dist/seo/index.mjs +3 -3
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sync/index.d.mts +10 -1
- package/dist/sync/index.d.ts +10 -1
- package/dist/sync/index.js +15 -15
- package/dist/sync/index.mjs +3 -3
- package/package.json +1 -1
- package/dist/AnalyticsProvider-A3STXJ65.js +0 -29
- package/dist/ChatWidget-4QR2ZDRE.mjs +0 -8
- package/dist/ChatWidget-U3K2VHVN.js +0 -17
- package/dist/EngageWidget-2FMKYJJT.mjs +0 -7
- package/dist/EngageWidget-TOGMQ2G6.js +0 -16
- package/dist/SitemapSync-BJWSTERT.js +0 -15
- package/dist/SitemapSync-T6PIDW64.mjs +0 -6
- package/dist/chunk-5RX4CUR2.js.map +0 -1
- package/dist/chunk-7R7SGJG3.mjs.map +0 -1
- package/dist/chunk-AMBTOIYM.mjs.map +0 -1
- package/dist/chunk-LF3ID6WN.js.map +0 -1
- package/dist/chunk-QLM7RNQI.mjs +0 -6
- package/dist/chunk-WAAFJPNR.js +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/signal/SignalBridge.tsx"],"names":["dynamic","createContext","useContext","useState","useRef","useCallback","useMemo","jsxs","jsx"],"mappings":"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","file":"chunk-52VXHSVT.js","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalBridge\n *\n * Central coordination layer for Signal AI integration.\n *\n * Architecture (2026-07 perf release): SignalBridge is a tiny SSR-SAFE context shell. It\n * renders {children} immediately — children server-render and hydrate\n * normally, no ssr:false wrapper — and lazy-loads the heavy machinery\n * (SignalCore: config fetch, SSE streaming, experiment assignment, event\n * queue, behavior tracking) as a CHILDLESS sibling. The core registers its\n * imperative API into the shell on mount; `trackEvent`/`trackOutcome` calls\n * made before the core is ready are buffered and drained on registration.\n *\n * This removes the old failure mode where enabling `signal` de-opted the\n * whole route to client rendering (the same SSR bailout the analytics\n * sibling-mount fixed) — the #1 recommendation of the 2026-07 perf audit.\n *\n * The core is NOT idle-deferred: experiment variants must apply as early as\n * possible, so it starts loading on hydration.\n */\n\n'use client'\n\nimport React, { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react'\nimport dynamic from 'next/dynamic'\nimport type { SignalCoreApi, SignalCoreState } from './SignalCore'\nimport type {\n SignalConfig,\n SignalContextValue,\n SignalBridgeProps,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// Heavy machinery — loaded client-side only, never wraps content.\nconst LazySignalCore = dynamic(\n () => import('./SignalCore').then(m => ({ default: m.SignalCore })),\n { ssr: false },\n)\n\n// ============================================\n// Context\n// ============================================\n\nconst SignalContext = createContext<SignalContextValue | null>(null)\n\nexport function useSignal(): SignalContextValue {\n const context = useContext(SignalContext)\n if (!context) {\n throw new Error('useSignal must be used within a SignalBridge')\n }\n return context\n}\n\n// ============================================\n// SignalBridge Component (shell)\n// ============================================\n\nexport function SignalBridge({\n enabled = true,\n realtime = true,\n experiments = true,\n behaviorTracking = true,\n visitorId: externalVisitorId,\n sessionId: externalSessionId,\n pageMetadataRef,\n children,\n}: SignalBridgeProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const coreRef = useRef<SignalCoreApi | null>(null)\n // Calls made before the core chunk loads are buffered here and drained on\n // registration — consumers can call trackEvent/trackOutcome from first render.\n const pendingEventsRef = useRef<Partial<SignalEvent>[]>([])\n const pendingOutcomesRef = useRef<SignalOutcome[]>([])\n\n const handleState = useCallback((state: SignalCoreState) => {\n setConfig(state.config)\n setLoading(state.loading)\n setError(state.error)\n }, [])\n\n const handleRegister = useCallback((api: SignalCoreApi | null) => {\n coreRef.current = api\n if (api) {\n pendingEventsRef.current.splice(0).forEach(event => api.trackEvent(event))\n pendingOutcomesRef.current.splice(0).forEach(outcome => api.trackOutcome(outcome))\n }\n }, [])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (coreRef.current) {\n coreRef.current.trackEvent(event)\n } else {\n pendingEventsRef.current.push(event)\n }\n }, [])\n\n const trackOutcome = useCallback((outcome: SignalOutcome) => {\n if (coreRef.current) {\n coreRef.current.trackOutcome(outcome)\n } else {\n pendingOutcomesRef.current.push(outcome)\n }\n }, [])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n // null before the core loads — identical to the pre-config-fetch behavior\n // consumers already handle via `loading`.\n return coreRef.current?.getExperiment(experimentId) ?? null\n }, [])\n\n const refreshConfig = useCallback(async () => {\n await coreRef.current?.refreshConfig()\n }, [])\n\n const contextValue = useMemo<SignalContextValue>(() => ({\n config,\n loading,\n error,\n trackEvent,\n trackOutcome,\n getExperiment,\n refreshConfig,\n }), [config, loading, error, trackEvent, trackOutcome, getExperiment, refreshConfig])\n\n return (\n <SignalContext.Provider value={contextValue}>\n {children}\n {enabled && (\n <LazySignalCore\n enabled={enabled}\n realtime={realtime}\n experiments={experiments}\n behaviorTracking={behaviorTracking}\n externalVisitorId={externalVisitorId}\n externalSessionId={externalSessionId}\n pageMetadataRef={pageMetadataRef}\n onRegister={handleRegister}\n onState={handleState}\n />\n )}\n </SignalContext.Provider>\n )\n}\n\n// ============================================\n// Convenience Hooks\n// ============================================\n\n/**\n * Hook to access Signal config\n */\nexport function useSignalConfig(): SignalConfig | null {\n const { config } = useSignal()\n return config\n}\n\n/**\n * Hook for tracking events\n */\nexport function useSignalEvent() {\n const { trackEvent } = useSignal()\n return trackEvent\n}\n\n/**\n * Hook for tracking outcomes/conversions\n */\nexport function useSignalOutcome() {\n const { trackOutcome } = useSignal()\n return { trackOutcome }\n}\n\n/**\n * Hook for experiment assignment\n */\nexport function useSignalExperiment(experimentId: string): {\n assignment: ExperimentAssignment | null\n variant: string | null\n isControl: boolean\n} {\n const { getExperiment, config } = useSignal()\n const assignment = getExperiment(experimentId)\n\n // Check if experiment is running\n const experiment = config?.experiments?.find(e => e.id === experimentId)\n const isRunning = experiment?.status === 'running'\n\n return {\n assignment: isRunning ? assignment : null,\n variant: isRunning && assignment ? assignment.variant_key : null,\n isControl: !assignment || assignment.variant_key === 'control',\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/signal/SignalBridge.tsx"],"names":["dynamic","createContext","useContext","useState","useRef","useCallback","useMemo","jsxs","jsx"],"mappings":"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","file":"chunk-6UK5JIKE.js","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalBridge\n *\n * Central coordination layer for Signal AI integration.\n *\n * Architecture (2026-07 perf release): SignalBridge is a tiny SSR-SAFE context shell. It\n * renders {children} immediately — children server-render and hydrate\n * normally, no ssr:false wrapper — and lazy-loads the heavy machinery\n * (SignalCore: config fetch, SSE streaming, experiment assignment, event\n * queue, behavior tracking) as a CHILDLESS sibling. The core registers its\n * imperative API into the shell on mount; `trackEvent`/`trackOutcome` calls\n * made before the core is ready are buffered and drained on registration.\n *\n * This removes the old failure mode where enabling `signal` de-opted the\n * whole route to client rendering (the same SSR bailout the analytics\n * sibling-mount fixed) — the #1 recommendation of the 2026-07 perf audit.\n *\n * The core is NOT idle-deferred: experiment variants must apply as early as\n * possible, so it starts loading on hydration.\n */\n\n'use client'\n\nimport React, { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react'\nimport dynamic from 'next/dynamic'\nimport type { SignalCoreApi, SignalCoreState } from './SignalCore'\nimport type {\n SignalConfig,\n SignalContextValue,\n SignalBridgeProps,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// Heavy machinery — loaded client-side only, never wraps content.\nconst LazySignalCore = dynamic(\n () => import('./SignalCore').then(m => ({ default: m.SignalCore })),\n { ssr: false },\n)\n\n// ============================================\n// Context\n// ============================================\n\nconst SignalContext = createContext<SignalContextValue | null>(null)\n\nexport function useSignal(): SignalContextValue {\n const context = useContext(SignalContext)\n if (!context) {\n throw new Error('useSignal must be used within a SignalBridge')\n }\n return context\n}\n\n// ============================================\n// SignalBridge Component (shell)\n// ============================================\n\nexport function SignalBridge({\n enabled = true,\n realtime = true,\n experiments = true,\n behaviorTracking = true,\n visitorId: externalVisitorId,\n sessionId: externalSessionId,\n pageMetadataRef,\n children,\n}: SignalBridgeProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const coreRef = useRef<SignalCoreApi | null>(null)\n // Calls made before the core chunk loads are buffered here and drained on\n // registration — consumers can call trackEvent/trackOutcome from first render.\n const pendingEventsRef = useRef<Partial<SignalEvent>[]>([])\n const pendingOutcomesRef = useRef<SignalOutcome[]>([])\n\n const handleState = useCallback((state: SignalCoreState) => {\n setConfig(state.config)\n setLoading(state.loading)\n setError(state.error)\n }, [])\n\n const handleRegister = useCallback((api: SignalCoreApi | null) => {\n coreRef.current = api\n if (api) {\n pendingEventsRef.current.splice(0).forEach(event => api.trackEvent(event))\n pendingOutcomesRef.current.splice(0).forEach(outcome => api.trackOutcome(outcome))\n }\n }, [])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (coreRef.current) {\n coreRef.current.trackEvent(event)\n } else {\n pendingEventsRef.current.push(event)\n }\n }, [])\n\n const trackOutcome = useCallback((outcome: SignalOutcome) => {\n if (coreRef.current) {\n coreRef.current.trackOutcome(outcome)\n } else {\n pendingOutcomesRef.current.push(outcome)\n }\n }, [])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n // null before the core loads — identical to the pre-config-fetch behavior\n // consumers already handle via `loading`.\n return coreRef.current?.getExperiment(experimentId) ?? null\n }, [])\n\n const refreshConfig = useCallback(async () => {\n await coreRef.current?.refreshConfig()\n }, [])\n\n const contextValue = useMemo<SignalContextValue>(() => ({\n config,\n loading,\n error,\n trackEvent,\n trackOutcome,\n getExperiment,\n refreshConfig,\n }), [config, loading, error, trackEvent, trackOutcome, getExperiment, refreshConfig])\n\n return (\n <SignalContext.Provider value={contextValue}>\n {children}\n {enabled && (\n <LazySignalCore\n enabled={enabled}\n realtime={realtime}\n experiments={experiments}\n behaviorTracking={behaviorTracking}\n externalVisitorId={externalVisitorId}\n externalSessionId={externalSessionId}\n pageMetadataRef={pageMetadataRef}\n onRegister={handleRegister}\n onState={handleState}\n />\n )}\n </SignalContext.Provider>\n )\n}\n\n// ============================================\n// Convenience Hooks\n// ============================================\n\n/**\n * Hook to access Signal config\n */\nexport function useSignalConfig(): SignalConfig | null {\n const { config } = useSignal()\n return config\n}\n\n/**\n * Hook for tracking events\n */\nexport function useSignalEvent() {\n const { trackEvent } = useSignal()\n return trackEvent\n}\n\n/**\n * Hook for tracking outcomes/conversions\n */\nexport function useSignalOutcome() {\n const { trackOutcome } = useSignal()\n return { trackOutcome }\n}\n\n/**\n * Hook for experiment assignment\n */\nexport function useSignalExperiment(experimentId: string): {\n assignment: ExperimentAssignment | null\n variant: string | null\n isControl: boolean\n} {\n const { getExperiment, config } = useSignal()\n const assignment = getExperiment(experimentId)\n\n // Check if experiment is running\n const experiment = config?.experiments?.find(e => e.id === experimentId)\n const isRunning = experiment?.status === 'running'\n\n return {\n assignment: isRunning ? assignment : null,\n variant: isRunning && assignment ? assignment.variant_key : null,\n isControl: !assignment || assignment.variant_key === 'control',\n }\n}\n"]}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { FleetHeartbeat } from './chunk-
|
|
2
|
+
import { FleetHeartbeat } from './chunk-X72PFC4X.mjs';
|
|
3
3
|
import { useDeferredActivation } from './chunk-ZVBLXXNJ.mjs';
|
|
4
4
|
import { normalizeSiteHost } from './chunk-X4OPM3SK.mjs';
|
|
5
|
-
import { SignalBridge } from './chunk-
|
|
5
|
+
import { SignalBridge } from './chunk-ZCZEKWFW.mjs';
|
|
6
6
|
import { getOrCreateVisitorId, getOrCreateSessionId, SiteKitIdentityProvider } from './chunk-EE6SFAZP.mjs';
|
|
7
|
-
import { configureSiteCredential, currentCredential } from './chunk-
|
|
7
|
+
import { configureSiteCredential, currentCredential } from './chunk-FO6Y27AH.mjs';
|
|
8
8
|
import { useState, useRef, useCallback, Suspense } from 'react';
|
|
9
9
|
import dynamic from 'next/dynamic';
|
|
10
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
11
|
|
|
12
12
|
var LazyAnalyticsProvider = dynamic(
|
|
13
|
-
() => import('./AnalyticsProvider-
|
|
13
|
+
() => import('./AnalyticsProvider-AMHG4DIE.mjs').then((m) => ({ default: m.AnalyticsProvider })),
|
|
14
14
|
{ ssr: false }
|
|
15
15
|
);
|
|
16
16
|
var LazyEngageWidget = dynamic(
|
|
17
|
-
() => import('./EngageWidget-
|
|
17
|
+
() => import('./EngageWidget-S76ZMDEF.mjs').then((m) => ({ default: m.EngageWidget })),
|
|
18
18
|
{ ssr: false }
|
|
19
19
|
);
|
|
20
20
|
var LazySitemapSync = dynamic(
|
|
21
|
-
() => import('./SitemapSync-
|
|
21
|
+
() => import('./SitemapSync-RBHXPQAQ.mjs').then((m) => ({ default: m.SitemapSync })),
|
|
22
22
|
{ ssr: false }
|
|
23
23
|
);
|
|
24
24
|
function SiteKitClientProviders({
|
|
@@ -150,5 +150,5 @@ function SiteKitClientProviders({
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
export { SiteKitClientProviders };
|
|
153
|
-
//# sourceMappingURL=chunk-
|
|
154
|
-
//# sourceMappingURL=chunk-
|
|
153
|
+
//# sourceMappingURL=chunk-AXFM4MFK.mjs.map
|
|
154
|
+
//# sourceMappingURL=chunk-AXFM4MFK.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/layout/SiteKitClientProviders.tsx"],"names":[],"mappings":"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","file":"chunk-VTHCUHMK.mjs","sourcesContent":["'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 { normalizeSiteHost } from '../sites/contract'\n// Defer non-critical module mounting until the page is quiet: the lazy\n// modules below are dynamic(ssr:false) and never render on the server, but\n// rendering them during hydration still kicks off their chunk downloads +\n// mount effects inside the critical startup window. useDeferredActivation\n// holds them until window.load + idle or first interaction — the same\n// strategy as the hand-rolled per-site deferrals this replaces (upforge\n// `deferred-analytics.tsx`, TPS `DeferredAnalytics.tsx`). The hook is public\n// (`@sonordev/site-kit/client`) so sites can reuse it for their own scripts.\nimport { useDeferredActivation } from '../shared/defer'\nimport { configureSiteCredential, currentCredential } from '../shared/siteToken'\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 LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n// SignalBridge is imported STATICALLY, not via dynamic(ssr:false): it is a\n// tiny SSR-safe context shell that renders children immediately and\n// lazy-loads its machinery (SignalCore) as a childless sibling internally.\n// Wrapping children in a dynamic(ssr:false) component was the old SSR-bailout\n// failure mode — do not reintroduce it.\nimport { SignalBridge } from '../signal/SignalBridge'\n// Fleet heartbeat: a deferred, CHILDLESS SIBLING (like Analytics/Engage) that\n// reports this site's kit version + active modules once per session, so the\n// platform can see version drift across the fleet. Tiny and SSR-safe — renders\n// null until the shared idle gate fires; never wraps page content.\nimport { FleetHeartbeat } from '../fleet/FleetHeartbeat'\nimport type { FleetModule } from '../fleet/contract'\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 /**\n * Fleet heartbeat — reports kit version + active modules to Sonor once per\n * session so the platform can track version drift and key state across every\n * site. Default true. Deferred exactly like Analytics; never in the hydration\n * path, carries no visitor data.\n */\n fleet?: boolean\n /**\n * Defer Analytics / Engage / SitemapSync until window load + idle or first\n * interaction (default true). Pass false to restore legacy eager mounting\n * on hydration. SignalBridge is never deferred — it must apply experiment\n * variants as early as possible.\n */\n defer?: 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 fleet = true,\n defer = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // One shared activation gate for all deferred siblings, so they mount in a\n // single commit instead of staggered re-renders.\n const modulesReady = useDeferredActivation(defer)\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 // Normalize with the shared site contract (lowercase host, no protocol/path/\n // port) so `__SITE_KIT_SITE__` matches exactly what the Sonor API stores —\n // servers re-normalize with the same rule, so this only makes the client\n // emit the canonical value. Always a string (possibly empty).\n const site = normalizeSiteHost(resolvedSite) ?? ''\n\n // Set window globals for modules that still read from them.\n if (typeof window !== 'undefined') {\n // Seed the client token manager. In 3.2+ `apiKey` is a short-lived minted\n // token that sonorFetch refreshes transparently; the window global is set to\n // the freshest token held (a prior page this session may have refreshed).\n // In raw-key mode (2.x kit or mint-failed fallback) this is a passthrough.\n configureSiteCredential({ credential: apiKey, apiUrl })\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = currentCredential(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. Safe to wrap: the shell is SSR-safe\n // and renders children straight through — the heavy machinery mounts as a\n // childless sibling inside it. Not gated on modulesReady: experiment\n // variants must apply as early as possible.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 </SignalBridge>\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 // Each deferred sibling is appended as `{modulesReady && <Module/>}` so the\n // children slot never moves in the tree — flipping ready only mounts the\n // sibling, it never remounts page content.\n if (analytics) {\n content = (\n <>\n {content}\n {modulesReady && (\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 sessionTimeout={analyticsConfig.sessionDuration}\n excludePaths={analyticsConfig.excludePaths}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n )}\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 {modulesReady && (\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n zIndex={engageConfig.zIndex}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n )}\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n {modulesReady && <LazySitemapSync debug={debug} />}\n </>\n )\n }\n\n // Fleet heartbeat — childless sibling on the same modulesReady idle gate.\n // Reports the modules actually enabled on THIS layout (honest client-observable\n // set) so the platform can answer \"which version / modules is each site\n // running\". defer={false}: the modulesReady gate already handled deferral, so\n // the heartbeat fires on mount (still bounded to once per session internally).\n if (fleet) {\n const activeModules: FleetModule[] = []\n if (analytics) activeModules.push('analytics')\n if (engage) activeModules.push('engage')\n if (signal) activeModules.push('signal')\n if (sitemapSync) activeModules.push('sitemapSync')\n content = (\n <>\n {content}\n {modulesReady && (\n <FleetHeartbeat\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n modules={activeModules}\n defer={false}\n debug={debug}\n />\n )}\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/layout/SiteKitClientProviders.tsx"],"names":[],"mappings":"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","file":"chunk-AXFM4MFK.mjs","sourcesContent":["'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 { normalizeSiteHost } from '../sites/contract'\n// Defer non-critical module mounting until the page is quiet: the lazy\n// modules below are dynamic(ssr:false) and never render on the server, but\n// rendering them during hydration still kicks off their chunk downloads +\n// mount effects inside the critical startup window. useDeferredActivation\n// holds them until window.load + idle or first interaction — the same\n// strategy as the hand-rolled per-site deferrals this replaces (upforge\n// `deferred-analytics.tsx`, TPS `DeferredAnalytics.tsx`). The hook is public\n// (`@sonordev/site-kit/client`) so sites can reuse it for their own scripts.\nimport { useDeferredActivation } from '../shared/defer'\nimport { configureSiteCredential, currentCredential } from '../shared/siteToken'\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 LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n// SignalBridge is imported STATICALLY, not via dynamic(ssr:false): it is a\n// tiny SSR-safe context shell that renders children immediately and\n// lazy-loads its machinery (SignalCore) as a childless sibling internally.\n// Wrapping children in a dynamic(ssr:false) component was the old SSR-bailout\n// failure mode — do not reintroduce it.\nimport { SignalBridge } from '../signal/SignalBridge'\n// Fleet heartbeat: a deferred, CHILDLESS SIBLING (like Analytics/Engage) that\n// reports this site's kit version + active modules once per session, so the\n// platform can see version drift across the fleet. Tiny and SSR-safe — renders\n// null until the shared idle gate fires; never wraps page content.\nimport { FleetHeartbeat } from '../fleet/FleetHeartbeat'\nimport type { FleetModule } from '../fleet/contract'\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 /**\n * Fleet heartbeat — reports kit version + active modules to Sonor once per\n * session so the platform can track version drift and key state across every\n * site. Default true. Deferred exactly like Analytics; never in the hydration\n * path, carries no visitor data.\n */\n fleet?: boolean\n /**\n * Defer Analytics / Engage / SitemapSync until window load + idle or first\n * interaction (default true). Pass false to restore legacy eager mounting\n * on hydration. SignalBridge is never deferred — it must apply experiment\n * variants as early as possible.\n */\n defer?: 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 fleet = true,\n defer = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // One shared activation gate for all deferred siblings, so they mount in a\n // single commit instead of staggered re-renders.\n const modulesReady = useDeferredActivation(defer)\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 // Normalize with the shared site contract (lowercase host, no protocol/path/\n // port) so `__SITE_KIT_SITE__` matches exactly what the Sonor API stores —\n // servers re-normalize with the same rule, so this only makes the client\n // emit the canonical value. Always a string (possibly empty).\n const site = normalizeSiteHost(resolvedSite) ?? ''\n\n // Set window globals for modules that still read from them.\n if (typeof window !== 'undefined') {\n // Seed the client token manager. In 3.2+ `apiKey` is a short-lived minted\n // token that sonorFetch refreshes transparently; the window global is set to\n // the freshest token held (a prior page this session may have refreshed).\n // In raw-key mode (2.x kit or mint-failed fallback) this is a passthrough.\n configureSiteCredential({ credential: apiKey, apiUrl })\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = currentCredential(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. Safe to wrap: the shell is SSR-safe\n // and renders children straight through — the heavy machinery mounts as a\n // childless sibling inside it. Not gated on modulesReady: experiment\n // variants must apply as early as possible.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 </SignalBridge>\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 // Each deferred sibling is appended as `{modulesReady && <Module/>}` so the\n // children slot never moves in the tree — flipping ready only mounts the\n // sibling, it never remounts page content.\n if (analytics) {\n content = (\n <>\n {content}\n {modulesReady && (\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 sessionTimeout={analyticsConfig.sessionDuration}\n excludePaths={analyticsConfig.excludePaths}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n )}\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 {modulesReady && (\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n zIndex={engageConfig.zIndex}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n )}\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n {modulesReady && <LazySitemapSync debug={debug} />}\n </>\n )\n }\n\n // Fleet heartbeat — childless sibling on the same modulesReady idle gate.\n // Reports the modules actually enabled on THIS layout (honest client-observable\n // set) so the platform can answer \"which version / modules is each site\n // running\". defer={false}: the modulesReady gate already handled deferral, so\n // the heartbeat fires on mount (still bounded to once per session internally).\n if (fleet) {\n const activeModules: FleetModule[] = []\n if (analytics) activeModules.push('analytics')\n if (engage) activeModules.push('engage')\n if (signal) activeModules.push('signal')\n if (sitemapSync) activeModules.push('sitemapSync')\n content = (\n <>\n {content}\n {modulesReady && (\n <FleetHeartbeat\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n modules={activeModules}\n defer={false}\n debug={debug}\n />\n )}\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkFX3VR4BF_js = require('./chunk-FX3VR4BF.js');
|
|
5
5
|
var chunkHGNSJXWT_js = require('./chunk-HGNSJXWT.js');
|
|
6
6
|
var chunkWZHWWOUC_js = require('./chunk-WZHWWOUC.js');
|
|
7
|
-
var
|
|
7
|
+
var chunk6UK5JIKE_js = require('./chunk-6UK5JIKE.js');
|
|
8
8
|
var chunk3BNFUMLL_js = require('./chunk-3BNFUMLL.js');
|
|
9
|
-
var
|
|
9
|
+
var chunkM2EGCGIT_js = require('./chunk-M2EGCGIT.js');
|
|
10
10
|
var react = require('react');
|
|
11
11
|
var dynamic = require('next/dynamic');
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -16,15 +16,15 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
16
16
|
var dynamic__default = /*#__PURE__*/_interopDefault(dynamic);
|
|
17
17
|
|
|
18
18
|
var LazyAnalyticsProvider = dynamic__default.default(
|
|
19
|
-
() => import('./AnalyticsProvider-
|
|
19
|
+
() => import('./AnalyticsProvider-26VS3CQR.js').then((m) => ({ default: m.AnalyticsProvider })),
|
|
20
20
|
{ ssr: false }
|
|
21
21
|
);
|
|
22
22
|
var LazyEngageWidget = dynamic__default.default(
|
|
23
|
-
() => import('./EngageWidget-
|
|
23
|
+
() => import('./EngageWidget-33QCFWQW.js').then((m) => ({ default: m.EngageWidget })),
|
|
24
24
|
{ ssr: false }
|
|
25
25
|
);
|
|
26
26
|
var LazySitemapSync = dynamic__default.default(
|
|
27
|
-
() => import('./SitemapSync-
|
|
27
|
+
() => import('./SitemapSync-WQJMHJNY.js').then((m) => ({ default: m.SitemapSync })),
|
|
28
28
|
{ ssr: false }
|
|
29
29
|
);
|
|
30
30
|
function SiteKitClientProviders({
|
|
@@ -56,9 +56,9 @@ function SiteKitClientProviders({
|
|
|
56
56
|
}
|
|
57
57
|
const site = chunkWZHWWOUC_js.normalizeSiteHost(resolvedSite) ?? "";
|
|
58
58
|
if (typeof window !== "undefined") {
|
|
59
|
-
|
|
59
|
+
chunkM2EGCGIT_js.configureSiteCredential({ credential: apiKey, apiUrl });
|
|
60
60
|
window.__SITE_KIT_API_URL__ = apiUrl;
|
|
61
|
-
window.__SITE_KIT_API_KEY__ =
|
|
61
|
+
window.__SITE_KIT_API_KEY__ = chunkM2EGCGIT_js.currentCredential(apiKey);
|
|
62
62
|
window.__SITE_KIT_DEBUG__ = debug;
|
|
63
63
|
window.__SITE_KIT_SITE__ = site;
|
|
64
64
|
}
|
|
@@ -72,7 +72,7 @@ function SiteKitClientProviders({
|
|
|
72
72
|
if (signal) {
|
|
73
73
|
const signalConfig = typeof signal === "object" ? signal : {};
|
|
74
74
|
content = /* @__PURE__ */ jsxRuntime.jsx(
|
|
75
|
-
|
|
75
|
+
chunk6UK5JIKE_js.SignalBridge,
|
|
76
76
|
{
|
|
77
77
|
enabled: true,
|
|
78
78
|
realtime: signalConfig.realtime !== false,
|
|
@@ -140,7 +140,7 @@ function SiteKitClientProviders({
|
|
|
140
140
|
content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
141
141
|
content,
|
|
142
142
|
modulesReady && /* @__PURE__ */ jsxRuntime.jsx(
|
|
143
|
-
|
|
143
|
+
chunkFX3VR4BF_js.FleetHeartbeat,
|
|
144
144
|
{
|
|
145
145
|
apiUrl,
|
|
146
146
|
apiKey,
|
|
@@ -156,5 +156,5 @@ function SiteKitClientProviders({
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
exports.SiteKitClientProviders = SiteKitClientProviders;
|
|
159
|
-
//# sourceMappingURL=chunk-
|
|
160
|
-
//# sourceMappingURL=chunk-
|
|
159
|
+
//# sourceMappingURL=chunk-BOTWTNHW.js.map
|
|
160
|
+
//# sourceMappingURL=chunk-BOTWTNHW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/layout/SiteKitClientProviders.tsx"],"names":["dynamic","useDeferredActivation","normalizeSiteHost","configureSiteCredential","currentCredential","useState","getOrCreateVisitorId","getOrCreateSessionId","useRef","useCallback","jsx","SignalBridge","jsxs","Fragment","Suspense","FleetHeartbeat","SiteKitIdentityProvider"],"mappings":"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","file":"chunk-BNBCSHTK.js","sourcesContent":["'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 { normalizeSiteHost } from '../sites/contract'\n// Defer non-critical module mounting until the page is quiet: the lazy\n// modules below are dynamic(ssr:false) and never render on the server, but\n// rendering them during hydration still kicks off their chunk downloads +\n// mount effects inside the critical startup window. useDeferredActivation\n// holds them until window.load + idle or first interaction — the same\n// strategy as the hand-rolled per-site deferrals this replaces (upforge\n// `deferred-analytics.tsx`, TPS `DeferredAnalytics.tsx`). The hook is public\n// (`@sonordev/site-kit/client`) so sites can reuse it for their own scripts.\nimport { useDeferredActivation } from '../shared/defer'\nimport { configureSiteCredential, currentCredential } from '../shared/siteToken'\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 LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n// SignalBridge is imported STATICALLY, not via dynamic(ssr:false): it is a\n// tiny SSR-safe context shell that renders children immediately and\n// lazy-loads its machinery (SignalCore) as a childless sibling internally.\n// Wrapping children in a dynamic(ssr:false) component was the old SSR-bailout\n// failure mode — do not reintroduce it.\nimport { SignalBridge } from '../signal/SignalBridge'\n// Fleet heartbeat: a deferred, CHILDLESS SIBLING (like Analytics/Engage) that\n// reports this site's kit version + active modules once per session, so the\n// platform can see version drift across the fleet. Tiny and SSR-safe — renders\n// null until the shared idle gate fires; never wraps page content.\nimport { FleetHeartbeat } from '../fleet/FleetHeartbeat'\nimport type { FleetModule } from '../fleet/contract'\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 /**\n * Fleet heartbeat — reports kit version + active modules to Sonor once per\n * session so the platform can track version drift and key state across every\n * site. Default true. Deferred exactly like Analytics; never in the hydration\n * path, carries no visitor data.\n */\n fleet?: boolean\n /**\n * Defer Analytics / Engage / SitemapSync until window load + idle or first\n * interaction (default true). Pass false to restore legacy eager mounting\n * on hydration. SignalBridge is never deferred — it must apply experiment\n * variants as early as possible.\n */\n defer?: 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 fleet = true,\n defer = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // One shared activation gate for all deferred siblings, so they mount in a\n // single commit instead of staggered re-renders.\n const modulesReady = useDeferredActivation(defer)\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 // Normalize with the shared site contract (lowercase host, no protocol/path/\n // port) so `__SITE_KIT_SITE__` matches exactly what the Sonor API stores —\n // servers re-normalize with the same rule, so this only makes the client\n // emit the canonical value. Always a string (possibly empty).\n const site = normalizeSiteHost(resolvedSite) ?? ''\n\n // Set window globals for modules that still read from them.\n if (typeof window !== 'undefined') {\n // Seed the client token manager. In 3.2+ `apiKey` is a short-lived minted\n // token that sonorFetch refreshes transparently; the window global is set to\n // the freshest token held (a prior page this session may have refreshed).\n // In raw-key mode (2.x kit or mint-failed fallback) this is a passthrough.\n configureSiteCredential({ credential: apiKey, apiUrl })\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = currentCredential(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. Safe to wrap: the shell is SSR-safe\n // and renders children straight through — the heavy machinery mounts as a\n // childless sibling inside it. Not gated on modulesReady: experiment\n // variants must apply as early as possible.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 </SignalBridge>\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 // Each deferred sibling is appended as `{modulesReady && <Module/>}` so the\n // children slot never moves in the tree — flipping ready only mounts the\n // sibling, it never remounts page content.\n if (analytics) {\n content = (\n <>\n {content}\n {modulesReady && (\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 sessionTimeout={analyticsConfig.sessionDuration}\n excludePaths={analyticsConfig.excludePaths}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n )}\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 {modulesReady && (\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n zIndex={engageConfig.zIndex}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n )}\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n {modulesReady && <LazySitemapSync debug={debug} />}\n </>\n )\n }\n\n // Fleet heartbeat — childless sibling on the same modulesReady idle gate.\n // Reports the modules actually enabled on THIS layout (honest client-observable\n // set) so the platform can answer \"which version / modules is each site\n // running\". defer={false}: the modulesReady gate already handled deferral, so\n // the heartbeat fires on mount (still bounded to once per session internally).\n if (fleet) {\n const activeModules: FleetModule[] = []\n if (analytics) activeModules.push('analytics')\n if (engage) activeModules.push('engage')\n if (signal) activeModules.push('signal')\n if (sitemapSync) activeModules.push('sitemapSync')\n content = (\n <>\n {content}\n {modulesReady && (\n <FleetHeartbeat\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n modules={activeModules}\n defer={false}\n debug={debug}\n />\n )}\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/layout/SiteKitClientProviders.tsx"],"names":["dynamic","useDeferredActivation","normalizeSiteHost","configureSiteCredential","currentCredential","useState","getOrCreateVisitorId","getOrCreateSessionId","useRef","useCallback","jsx","SignalBridge","jsxs","Fragment","Suspense","FleetHeartbeat","SiteKitIdentityProvider"],"mappings":"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","file":"chunk-BOTWTNHW.js","sourcesContent":["'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 { normalizeSiteHost } from '../sites/contract'\n// Defer non-critical module mounting until the page is quiet: the lazy\n// modules below are dynamic(ssr:false) and never render on the server, but\n// rendering them during hydration still kicks off their chunk downloads +\n// mount effects inside the critical startup window. useDeferredActivation\n// holds them until window.load + idle or first interaction — the same\n// strategy as the hand-rolled per-site deferrals this replaces (upforge\n// `deferred-analytics.tsx`, TPS `DeferredAnalytics.tsx`). The hook is public\n// (`@sonordev/site-kit/client`) so sites can reuse it for their own scripts.\nimport { useDeferredActivation } from '../shared/defer'\nimport { configureSiteCredential, currentCredential } from '../shared/siteToken'\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 LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n// SignalBridge is imported STATICALLY, not via dynamic(ssr:false): it is a\n// tiny SSR-safe context shell that renders children immediately and\n// lazy-loads its machinery (SignalCore) as a childless sibling internally.\n// Wrapping children in a dynamic(ssr:false) component was the old SSR-bailout\n// failure mode — do not reintroduce it.\nimport { SignalBridge } from '../signal/SignalBridge'\n// Fleet heartbeat: a deferred, CHILDLESS SIBLING (like Analytics/Engage) that\n// reports this site's kit version + active modules once per session, so the\n// platform can see version drift across the fleet. Tiny and SSR-safe — renders\n// null until the shared idle gate fires; never wraps page content.\nimport { FleetHeartbeat } from '../fleet/FleetHeartbeat'\nimport type { FleetModule } from '../fleet/contract'\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 /**\n * Fleet heartbeat — reports kit version + active modules to Sonor once per\n * session so the platform can track version drift and key state across every\n * site. Default true. Deferred exactly like Analytics; never in the hydration\n * path, carries no visitor data.\n */\n fleet?: boolean\n /**\n * Defer Analytics / Engage / SitemapSync until window load + idle or first\n * interaction (default true). Pass false to restore legacy eager mounting\n * on hydration. SignalBridge is never deferred — it must apply experiment\n * variants as early as possible.\n */\n defer?: 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 fleet = true,\n defer = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // One shared activation gate for all deferred siblings, so they mount in a\n // single commit instead of staggered re-renders.\n const modulesReady = useDeferredActivation(defer)\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 // Normalize with the shared site contract (lowercase host, no protocol/path/\n // port) so `__SITE_KIT_SITE__` matches exactly what the Sonor API stores —\n // servers re-normalize with the same rule, so this only makes the client\n // emit the canonical value. Always a string (possibly empty).\n const site = normalizeSiteHost(resolvedSite) ?? ''\n\n // Set window globals for modules that still read from them.\n if (typeof window !== 'undefined') {\n // Seed the client token manager. In 3.2+ `apiKey` is a short-lived minted\n // token that sonorFetch refreshes transparently; the window global is set to\n // the freshest token held (a prior page this session may have refreshed).\n // In raw-key mode (2.x kit or mint-failed fallback) this is a passthrough.\n configureSiteCredential({ credential: apiKey, apiUrl })\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = currentCredential(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. Safe to wrap: the shell is SSR-safe\n // and renders children straight through — the heavy machinery mounts as a\n // childless sibling inside it. Not gated on modulesReady: experiment\n // variants must apply as early as possible.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <SignalBridge\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 </SignalBridge>\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 // Each deferred sibling is appended as `{modulesReady && <Module/>}` so the\n // children slot never moves in the tree — flipping ready only mounts the\n // sibling, it never remounts page content.\n if (analytics) {\n content = (\n <>\n {content}\n {modulesReady && (\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 sessionTimeout={analyticsConfig.sessionDuration}\n excludePaths={analyticsConfig.excludePaths}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n )}\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 {modulesReady && (\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n zIndex={engageConfig.zIndex}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n )}\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n {modulesReady && <LazySitemapSync debug={debug} />}\n </>\n )\n }\n\n // Fleet heartbeat — childless sibling on the same modulesReady idle gate.\n // Reports the modules actually enabled on THIS layout (honest client-observable\n // set) so the platform can answer \"which version / modules is each site\n // running\". defer={false}: the modulesReady gate already handled deferral, so\n // the heartbeat fires on mount (still bounded to once per session internally).\n if (fleet) {\n const activeModules: FleetModule[] = []\n if (analytics) activeModules.push('analytics')\n if (engage) activeModules.push('engage')\n if (signal) activeModules.push('signal')\n if (sitemapSync) activeModules.push('sitemapSync')\n content = (\n <>\n {content}\n {modulesReady && (\n <FleetHeartbeat\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n modules={activeModules}\n defer={false}\n debug={debug}\n />\n )}\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkM2EGCGIT_js = require('./chunk-M2EGCGIT.js');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
|
|
@@ -22,7 +22,7 @@ async function fetchBookingTypes(orgSlug, apiUrl, apiKey) {
|
|
|
22
22
|
const url = apiUrl || cfg.apiUrl;
|
|
23
23
|
const key = apiKey || cfg.apiKey;
|
|
24
24
|
const endpoint = key ? `${url}/sync/widget/types` : `${url}/sync/public/${orgSlug}/types`;
|
|
25
|
-
const response = await
|
|
25
|
+
const response = await chunkM2EGCGIT_js.sonorFetch(endpoint, { headers: buildHeaders() }, { apiKey: key, retries: 0 });
|
|
26
26
|
if (!response.ok) {
|
|
27
27
|
const msg = await response.json().catch(() => ({ message: response.statusText }));
|
|
28
28
|
const detail = msg && typeof msg.message === "string" ? msg.message : response.statusText;
|
|
@@ -36,7 +36,7 @@ async function fetchBookingTypeDetails(typeSlug, orgSlug, apiUrl, apiKey) {
|
|
|
36
36
|
const url = apiUrl || cfg.apiUrl;
|
|
37
37
|
const key = apiKey || cfg.apiKey;
|
|
38
38
|
const endpoint = key ? `${url}/sync/widget/types/${typeSlug}` : `${url}/sync/public/${orgSlug}/types/${typeSlug}`;
|
|
39
|
-
const response = await
|
|
39
|
+
const response = await chunkM2EGCGIT_js.sonorFetch(endpoint, { headers: buildHeaders() }, { apiKey: key, retries: 0 });
|
|
40
40
|
if (!response.ok) {
|
|
41
41
|
const msg = await response.json().catch(() => ({ message: response.statusText }));
|
|
42
42
|
const detail = msg && typeof msg.message === "string" ? msg.message : response.statusText;
|
|
@@ -52,7 +52,7 @@ async function fetchAvailability(typeSlug, date, orgSlug, apiUrl, apiKey, timezo
|
|
|
52
52
|
if (timezone) params.append("timezone", timezone);
|
|
53
53
|
if (hostId) params.append("hostId", hostId);
|
|
54
54
|
const endpoint = key ? `${url}/sync/widget/availability/${typeSlug}?${params}` : `${url}/sync/public/${orgSlug}/availability/${typeSlug}?${params}`;
|
|
55
|
-
const response = await
|
|
55
|
+
const response = await chunkM2EGCGIT_js.sonorFetch(endpoint, { headers: buildHeaders() }, { apiKey: key, retries: 0 });
|
|
56
56
|
if (!response.ok) {
|
|
57
57
|
const msg = await response.json().catch(() => ({ message: response.statusText }));
|
|
58
58
|
let detail = msg && typeof msg.message === "string" ? String(msg.message).trim() : (response.statusText || "").trim();
|
|
@@ -75,7 +75,7 @@ async function createSlotHold(holdData, apiUrl, apiKey) {
|
|
|
75
75
|
const url = apiUrl || cfg.apiUrl;
|
|
76
76
|
const key = apiKey || cfg.apiKey;
|
|
77
77
|
const endpoint = key ? `${url}/sync/widget/hold` : `${url}/sync/public/hold`;
|
|
78
|
-
const response = await
|
|
78
|
+
const response = await chunkM2EGCGIT_js.sonorFetch(endpoint, {
|
|
79
79
|
method: "POST",
|
|
80
80
|
headers: buildHeaders(true),
|
|
81
81
|
body: JSON.stringify(holdData)
|
|
@@ -90,7 +90,7 @@ async function releaseSlotHold(holdId, apiUrl, apiKey) {
|
|
|
90
90
|
const url = apiUrl || cfg.apiUrl;
|
|
91
91
|
const key = apiKey || cfg.apiKey;
|
|
92
92
|
const endpoint = key ? `${url}/sync/widget/hold/${holdId}` : `${url}/sync/public/hold/${holdId}`;
|
|
93
|
-
await
|
|
93
|
+
await chunkM2EGCGIT_js.sonorFetch(endpoint, {
|
|
94
94
|
method: "DELETE",
|
|
95
95
|
headers: buildHeaders()
|
|
96
96
|
}, { apiKey: key, retries: 0 });
|
|
@@ -100,7 +100,7 @@ async function createBooking(bookingData, apiUrl, apiKey) {
|
|
|
100
100
|
const url = apiUrl || cfg.apiUrl;
|
|
101
101
|
const key = apiKey || cfg.apiKey;
|
|
102
102
|
const endpoint = key ? `${url}/sync/widget/booking` : `${url}/sync/public/booking`;
|
|
103
|
-
const response = await
|
|
103
|
+
const response = await chunkM2EGCGIT_js.sonorFetch(endpoint, {
|
|
104
104
|
method: "POST",
|
|
105
105
|
headers: buildHeaders(true),
|
|
106
106
|
body: JSON.stringify(bookingData)
|
|
@@ -125,7 +125,7 @@ async function fetchAvailableDates(typeSlug, startDate, endDate, orgSlug, apiUrl
|
|
|
125
125
|
}
|
|
126
126
|
} catch {
|
|
127
127
|
}
|
|
128
|
-
current.
|
|
128
|
+
current.setUTCDate(current.getUTCDate() + 1);
|
|
129
129
|
}
|
|
130
130
|
return availableDates;
|
|
131
131
|
}
|
|
@@ -198,6 +198,12 @@ function calendarDays(year, month) {
|
|
|
198
198
|
for (let d = 1; d <= last.getDate(); d++) cells.push(new Date(year, month, d));
|
|
199
199
|
return cells;
|
|
200
200
|
}
|
|
201
|
+
function toLocalDateStr(d) {
|
|
202
|
+
const y = d.getFullYear();
|
|
203
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
204
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
205
|
+
return `${y}-${m}-${day}`;
|
|
206
|
+
}
|
|
201
207
|
function ChevronLeft() {
|
|
202
208
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12.5 15L7.5 10L12.5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
203
209
|
}
|
|
@@ -251,6 +257,7 @@ function BookingWidget({
|
|
|
251
257
|
onBookingComplete,
|
|
252
258
|
onError,
|
|
253
259
|
hideTypeSelector = false,
|
|
260
|
+
autoSelectFirstDay = true,
|
|
254
261
|
styles = {}
|
|
255
262
|
}) {
|
|
256
263
|
const apiKey = propApiKey || (typeof window !== "undefined" ? window.__SITE_KIT_API_KEY__ : void 0);
|
|
@@ -270,6 +277,9 @@ function BookingWidget({
|
|
|
270
277
|
const [guestInfo, setGuestInfo] = react.useState({ name: "", email: "" });
|
|
271
278
|
const [bookingResult, setBookingResult] = react.useState(null);
|
|
272
279
|
const [submitting, setSubmitting] = react.useState(false);
|
|
280
|
+
const [autoProbing, setAutoProbing] = react.useState(false);
|
|
281
|
+
const probeRef = react.useRef(0);
|
|
282
|
+
const prefetchedRef = react.useRef(null);
|
|
273
283
|
const slotsRef = react.useRef(null);
|
|
274
284
|
const today = react.useMemo(() => {
|
|
275
285
|
const d = /* @__PURE__ */ new Date();
|
|
@@ -311,16 +321,57 @@ function BookingWidget({
|
|
|
311
321
|
}, [orgSlug, apiKey, bookingTypeSlug, apiUrl, onError]);
|
|
312
322
|
react.useEffect(() => {
|
|
313
323
|
if (!selectedDate || !selectedType) return;
|
|
314
|
-
const dateStr = selectedDate
|
|
315
|
-
setSlotsLoading(true);
|
|
316
|
-
setSlots([]);
|
|
324
|
+
const dateStr = toLocalDateStr(selectedDate);
|
|
317
325
|
setSelectedSlot(null);
|
|
318
326
|
setConfirmedSlot(false);
|
|
327
|
+
const prefetched = prefetchedRef.current;
|
|
328
|
+
if (prefetched && prefetched.dateStr === dateStr) {
|
|
329
|
+
prefetchedRef.current = null;
|
|
330
|
+
setSlots(prefetched.slots);
|
|
331
|
+
setSlotsLoading(false);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
setSlotsLoading(true);
|
|
335
|
+
setSlots([]);
|
|
319
336
|
fetchAvailability(selectedType.slug, dateStr, orgSlug, apiUrl, apiKey, timezone).then((s) => setSlots(s.filter((slot) => slot.available))).catch((err) => {
|
|
320
337
|
setError(err.message);
|
|
321
338
|
onError?.(err);
|
|
322
339
|
}).finally(() => setSlotsLoading(false));
|
|
323
340
|
}, [selectedDate, selectedType, orgSlug, apiKey, apiUrl, timezone, onError]);
|
|
341
|
+
react.useEffect(() => {
|
|
342
|
+
if (!autoSelectFirstDay || !selectedType || selectedDate) return;
|
|
343
|
+
const probeId = ++probeRef.current;
|
|
344
|
+
let cancelled = false;
|
|
345
|
+
const PROBE_DAYS = 14;
|
|
346
|
+
const startOffset = Math.floor((selectedType.min_notice_hours || 0) / 24);
|
|
347
|
+
(async () => {
|
|
348
|
+
setAutoProbing(true);
|
|
349
|
+
try {
|
|
350
|
+
for (let i = startOffset; i < startOffset + PROBE_DAYS; i++) {
|
|
351
|
+
const d = new Date(today);
|
|
352
|
+
d.setDate(d.getDate() + i);
|
|
353
|
+
if (d > maxDate) break;
|
|
354
|
+
const dateStr = toLocalDateStr(d);
|
|
355
|
+
const s = await fetchAvailability(selectedType.slug, dateStr, orgSlug, apiUrl, apiKey, timezone);
|
|
356
|
+
if (cancelled || probeRef.current !== probeId) return;
|
|
357
|
+
const open = s.filter((slot) => slot.available);
|
|
358
|
+
if (open.length > 0) {
|
|
359
|
+
prefetchedRef.current = { dateStr, slots: open };
|
|
360
|
+
setViewMonth(new Date(d.getFullYear(), d.getMonth(), 1));
|
|
361
|
+
setSelectedDate(d);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
} catch {
|
|
366
|
+
} finally {
|
|
367
|
+
if (!cancelled && probeRef.current === probeId) setAutoProbing(false);
|
|
368
|
+
}
|
|
369
|
+
})();
|
|
370
|
+
return () => {
|
|
371
|
+
cancelled = true;
|
|
372
|
+
setAutoProbing(false);
|
|
373
|
+
};
|
|
374
|
+
}, [autoSelectFirstDay, selectedType, selectedDate, orgSlug, apiKey, apiUrl, timezone, today, maxDate]);
|
|
324
375
|
const handleSlotSelect = react.useCallback((slot) => {
|
|
325
376
|
setSelectedSlot(slot);
|
|
326
377
|
setConfirmedSlot(false);
|
|
@@ -412,7 +463,7 @@ function BookingWidget({
|
|
|
412
463
|
const cssVars = {
|
|
413
464
|
"--sk-primary": styles.primaryColor || "#0069ff",
|
|
414
465
|
"--sk-primary-hover": styles.primaryColor ? `color-mix(in srgb, ${styles.primaryColor} 90%, black)` : "#0055d4",
|
|
415
|
-
"--sk-primary-light": styles.primaryColor ? `color-mix(in srgb, ${styles.primaryColor} 12%, white)` : "#e8f1ff",
|
|
466
|
+
"--sk-primary-light": styles.primaryColor ? `color-mix(in srgb, ${styles.primaryColor} 12%, ${styles.backgroundColor || "white"})` : "#e8f1ff",
|
|
416
467
|
"--sk-bg": styles.backgroundColor || "#ffffff",
|
|
417
468
|
"--sk-bg-elevated": styles.elevatedColor || "#f9fafb",
|
|
418
469
|
"--sk-surface": styles.surfaceColor || "#f3f4f6",
|
|
@@ -517,12 +568,15 @@ function BookingWidget({
|
|
|
517
568
|
);
|
|
518
569
|
}) })
|
|
519
570
|
] }),
|
|
520
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `bw-times${selectedDate ? " visible" : ""}`, ref: slotsRef, children: !selectedDate ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bw-times-
|
|
571
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `bw-times${selectedDate ? " visible" : ""}`, ref: slotsRef, children: !selectedDate ? autoProbing ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bw-times-skeleton", "aria-hidden": "true", children: [
|
|
572
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bw-skel-line" }),
|
|
573
|
+
[0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bw-skel-slot" }, i))
|
|
574
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bw-times-placeholder", children: [
|
|
521
575
|
/* @__PURE__ */ jsxRuntime.jsx(CalendarPlusIcon, {}),
|
|
522
576
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Select a date to view available times" })
|
|
523
|
-
] }) : slotsLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bw-
|
|
524
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
525
|
-
"
|
|
577
|
+
] }) : slotsLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bw-times-skeleton", "aria-hidden": "true", children: [
|
|
578
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bw-skel-line" }),
|
|
579
|
+
[0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bw-skel-slot" }, i))
|
|
526
580
|
] }) : slots.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bw-times-empty", children: "No available times on this date. Try another day." }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bw-times-scroll", children: [
|
|
527
581
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "bw-times-date", children: selectedDate.toLocaleDateString("en-US", { weekday: "long", month: "short", day: "numeric" }) }),
|
|
528
582
|
groupedSlots.morning.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bw-time-group", children: [
|
|
@@ -788,13 +842,34 @@ var WIDGET_CSS = `
|
|
|
788
842
|
/* \u2500\u2500 Animation \u2500\u2500 */
|
|
789
843
|
@keyframes bw-fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
|
|
790
844
|
@keyframes bw-spin { to { transform: rotate(360deg); } }
|
|
845
|
+
@keyframes bw-shimmer { to { background-position: -200% 0; } }
|
|
791
846
|
.bw-fade-in { animation: bw-fade-in 0.25s ease-out; }
|
|
792
847
|
.bw-spinner { animation: bw-spin 0.8s linear infinite; }
|
|
793
848
|
|
|
849
|
+
/* \u2500\u2500 Accessibility \u2500\u2500 */
|
|
850
|
+
.bw-root :is(button, a):focus-visible { outline: 2px solid var(--sk-primary); outline-offset: 2px; }
|
|
851
|
+
@media (prefers-reduced-motion: reduce) {
|
|
852
|
+
.bw-fade-in, .bw-skel-slot, .bw-skel-line { animation: none; }
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/* \u2500\u2500 Loading skeleton (time slots) \u2500\u2500 */
|
|
856
|
+
.bw-skel-line {
|
|
857
|
+
height: 14px; width: 70%; margin-bottom: 14px; border-radius: 4px;
|
|
858
|
+
background: linear-gradient(90deg, var(--sk-surface) 25%, var(--sk-bg-elevated) 50%, var(--sk-surface) 75%);
|
|
859
|
+
background-size: 200% 100%; animation: bw-shimmer 1.1s linear infinite;
|
|
860
|
+
}
|
|
861
|
+
.bw-skel-slot {
|
|
862
|
+
height: 44px; margin-bottom: 6px; border-radius: var(--sk-radius);
|
|
863
|
+
background: linear-gradient(90deg, var(--sk-surface) 25%, var(--sk-bg-elevated) 50%, var(--sk-surface) 75%);
|
|
864
|
+
background-size: 200% 100%; animation: bw-shimmer 1.1s linear infinite;
|
|
865
|
+
}
|
|
866
|
+
|
|
794
867
|
/* \u2500\u2500 Error \u2500\u2500 */
|
|
795
868
|
.bw-error {
|
|
796
869
|
display: flex; align-items: center; justify-content: space-between; gap: 12px;
|
|
797
|
-
background:
|
|
870
|
+
background: color-mix(in srgb, var(--sk-error) 10%, var(--sk-bg));
|
|
871
|
+
border: 1px solid color-mix(in srgb, var(--sk-error) 35%, var(--sk-bg));
|
|
872
|
+
color: var(--sk-error);
|
|
798
873
|
padding: 10px 14px; border-radius: var(--sk-radius); margin-bottom: 16px; font-size: 0.875rem;
|
|
799
874
|
}
|
|
800
875
|
.bw-error button { background: none; border: none; color: inherit; cursor: pointer; font-size: 1.25rem; line-height: 1; padding: 0; }
|
|
@@ -910,7 +985,7 @@ var WIDGET_CSS = `
|
|
|
910
985
|
.bw-time-label { display: block; font-size: 0.6875rem; font-weight: 600; color: var(--sk-text-tertiary); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px; }
|
|
911
986
|
|
|
912
987
|
.bw-time-btn {
|
|
913
|
-
display: block; width: 100%;
|
|
988
|
+
display: block; width: 100%; min-height: 44px;
|
|
914
989
|
padding: 10px 12px; margin-bottom: 6px;
|
|
915
990
|
border: 1.5px solid var(--sk-border); border-radius: var(--sk-radius);
|
|
916
991
|
background: var(--sk-bg); cursor: pointer;
|
|
@@ -936,7 +1011,7 @@ var WIDGET_CSS = `
|
|
|
936
1011
|
}
|
|
937
1012
|
.bw-time-confirm {
|
|
938
1013
|
display: inline-flex; align-items: center; justify-content: center; gap: 4px;
|
|
939
|
-
padding: 10px 16px; border: none;
|
|
1014
|
+
min-height: 44px; padding: 10px 16px; border: none;
|
|
940
1015
|
background: var(--sk-primary); color: #fff;
|
|
941
1016
|
font-size: 0.8125rem; font-weight: 600; cursor: pointer;
|
|
942
1017
|
transition: background 0.15s;
|
|
@@ -969,7 +1044,7 @@ var WIDGET_CSS = `
|
|
|
969
1044
|
}
|
|
970
1045
|
.bw-submit {
|
|
971
1046
|
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
|
972
|
-
width: 100%; padding: 14px; margin-top: 4px;
|
|
1047
|
+
width: 100%; min-height: 48px; padding: 14px; margin-top: 4px;
|
|
973
1048
|
background: var(--sk-primary); color: #fff; border: none;
|
|
974
1049
|
border-radius: var(--sk-radius); font-size: 0.9375rem; font-weight: 600;
|
|
975
1050
|
cursor: pointer; transition: background 0.15s;
|
|
@@ -1025,5 +1100,5 @@ exports.formatDate = formatDate;
|
|
|
1025
1100
|
exports.formatDuration = formatDuration;
|
|
1026
1101
|
exports.formatTime = formatTime;
|
|
1027
1102
|
exports.releaseSlotHold = releaseSlotHold;
|
|
1028
|
-
//# sourceMappingURL=chunk-
|
|
1029
|
-
//# sourceMappingURL=chunk-
|
|
1103
|
+
//# sourceMappingURL=chunk-BPKDRTEA.js.map
|
|
1104
|
+
//# sourceMappingURL=chunk-BPKDRTEA.js.map
|