@sonordev/site-kit 4.2.3 → 4.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-manifest.json +1 -1
- package/dist/AnalyticsProvider-HVPZPHZI.mjs +10 -0
- package/dist/{AnalyticsProvider-NW3UZYL5.mjs.map → AnalyticsProvider-HVPZPHZI.mjs.map} +1 -1
- package/dist/AnalyticsProvider-LFSSF7MQ.js +31 -0
- package/dist/{AnalyticsProvider-VSTTYP4W.js.map → AnalyticsProvider-LFSSF7MQ.js.map} +1 -1
- package/dist/ChatWidget-7E4PLIYQ.mjs +11 -0
- package/dist/{ChatWidget-EWQ7LRD4.mjs.map → ChatWidget-7E4PLIYQ.mjs.map} +1 -1
- package/dist/ChatWidget-RFVIYV5C.js +20 -0
- package/dist/{ChatWidget-BJOE2OSI.js.map → ChatWidget-RFVIYV5C.js.map} +1 -1
- package/dist/EngageWidget-LPMSXVT6.js +18 -0
- package/dist/{EngageWidget-CZMNLFWI.js.map → EngageWidget-LPMSXVT6.js.map} +1 -1
- package/dist/EngageWidget-N7EQGSSL.mjs +9 -0
- package/dist/{EngageWidget-F427CI6Y.mjs.map → EngageWidget-N7EQGSSL.mjs.map} +1 -1
- package/dist/{FileField-5RVBU3Z4.mjs → FileField-AS6TUTXA.mjs} +5 -5
- package/dist/{FileField-5RVBU3Z4.mjs.map → FileField-AS6TUTXA.mjs.map} +1 -1
- package/dist/{FileField-Y4ZA7DST.js → FileField-Y7NOLT27.js} +6 -6
- package/dist/{FileField-Y4ZA7DST.js.map → FileField-Y7NOLT27.js.map} +1 -1
- package/dist/{FormSpotlight-CJPI2MRJ.mjs → FormSpotlight-I6FEUYAA.mjs} +3 -3
- package/dist/{FormSpotlight-CJPI2MRJ.mjs.map → FormSpotlight-I6FEUYAA.mjs.map} +1 -1
- package/dist/{FormSpotlight-MAEV6SZK.js → FormSpotlight-RMYOXT2T.js} +15 -15
- package/dist/{FormSpotlight-MAEV6SZK.js.map → FormSpotlight-RMYOXT2T.js.map} +1 -1
- package/dist/{FormStage-D42NAHSN.js → FormStage-44OWEWZM.js} +13 -13
- package/dist/{FormStage-D42NAHSN.js.map → FormStage-44OWEWZM.js.map} +1 -1
- package/dist/{FormStage-Z7WW3DNA.mjs → FormStage-G3MUJMTC.mjs} +3 -3
- package/dist/{FormStage-Z7WW3DNA.mjs.map → FormStage-G3MUJMTC.mjs.map} +1 -1
- package/dist/ManagedForm-LVBNVUZE.mjs +14 -0
- package/dist/{ManagedForm-A7BROQIN.mjs.map → ManagedForm-LVBNVUZE.mjs.map} +1 -1
- package/dist/ManagedForm-YC6WLYVJ.js +23 -0
- package/dist/{ManagedForm-Z3Z5Z6OL.js.map → ManagedForm-YC6WLYVJ.js.map} +1 -1
- package/dist/{SignalCore-NA6TJFVE.js → SignalCore-AW5VDA4Y.js} +11 -11
- package/dist/{SignalCore-NA6TJFVE.js.map → SignalCore-AW5VDA4Y.js.map} +1 -1
- package/dist/{SignalCore-77UH6PZ4.mjs → SignalCore-DYBIG4JP.mjs} +5 -5
- package/dist/{SignalCore-77UH6PZ4.mjs.map → SignalCore-DYBIG4JP.mjs.map} +1 -1
- package/dist/SitemapSync-2JJOGL7D.mjs +8 -0
- package/dist/{SitemapSync-EY33A6P4.mjs.map → SitemapSync-2JJOGL7D.mjs.map} +1 -1
- package/dist/SitemapSync-S54TSZLM.js +17 -0
- package/dist/{SitemapSync-62F6HVAW.js.map → SitemapSync-S54TSZLM.js.map} +1 -1
- package/dist/analytics/index.js +9 -9
- package/dist/analytics/index.mjs +4 -4
- package/dist/{chunk-XOJYGBYF.js → chunk-2MFLOK2I.js} +3 -3
- package/dist/{chunk-XOJYGBYF.js.map → chunk-2MFLOK2I.js.map} +1 -1
- package/dist/{chunk-3P4HJAZA.mjs → chunk-2MLIU6OJ.mjs} +4 -4
- package/dist/{chunk-3P4HJAZA.mjs.map → chunk-2MLIU6OJ.mjs.map} +1 -1
- package/dist/{chunk-QJK2X3UK.js → chunk-2XLWCYB3.js} +12 -12
- package/dist/{chunk-QJK2X3UK.js.map → chunk-2XLWCYB3.js.map} +1 -1
- package/dist/{chunk-ZASFY4NR.mjs → chunk-33OSUHPZ.mjs} +4 -4
- package/dist/{chunk-ZASFY4NR.mjs.map → chunk-33OSUHPZ.mjs.map} +1 -1
- package/dist/chunk-4JVFWTER.js +8 -0
- package/dist/{chunk-S5L73KZQ.js.map → chunk-4JVFWTER.js.map} +1 -1
- package/dist/{chunk-N5RTJNMN.js → chunk-5K2CX5LK.js} +6 -6
- package/dist/{chunk-N5RTJNMN.js.map → chunk-5K2CX5LK.js.map} +1 -1
- package/dist/{chunk-535HXGDU.mjs → chunk-6ZQFCZPW.mjs} +3 -3
- package/dist/{chunk-535HXGDU.mjs.map → chunk-6ZQFCZPW.mjs.map} +1 -1
- package/dist/{chunk-3DSGMX7P.js → chunk-A7O7IWL7.js} +3 -3
- package/dist/{chunk-3DSGMX7P.js.map → chunk-A7O7IWL7.js.map} +1 -1
- package/dist/{chunk-WCTOQFAN.js → chunk-ARFWE2EL.js} +14 -14
- package/dist/{chunk-WCTOQFAN.js.map → chunk-ARFWE2EL.js.map} +1 -1
- package/dist/{chunk-GJKO2TZN.js → chunk-BDDTZJKC.js} +4 -4
- package/dist/{chunk-GJKO2TZN.js.map → chunk-BDDTZJKC.js.map} +1 -1
- package/dist/{chunk-DZUOLOYS.mjs → chunk-BJW6YR6W.mjs} +3 -3
- package/dist/{chunk-DZUOLOYS.mjs.map → chunk-BJW6YR6W.mjs.map} +1 -1
- package/dist/{chunk-KL4MV6HK.mjs → chunk-C6CNCDIN.mjs} +3 -3
- package/dist/{chunk-KL4MV6HK.mjs.map → chunk-C6CNCDIN.mjs.map} +1 -1
- package/dist/{chunk-OHA43BNK.js → chunk-C6HDI464.js} +14 -14
- package/dist/{chunk-OHA43BNK.js.map → chunk-C6HDI464.js.map} +1 -1
- package/dist/{chunk-NEIUWAAL.js → chunk-CLD3IE6D.js} +5 -5
- package/dist/{chunk-NEIUWAAL.js.map → chunk-CLD3IE6D.js.map} +1 -1
- package/dist/{chunk-TKVADZFD.mjs → chunk-CPJA5XTO.mjs} +4 -4
- package/dist/{chunk-TKVADZFD.mjs.map → chunk-CPJA5XTO.mjs.map} +1 -1
- package/dist/{chunk-TFAYDIWM.mjs → chunk-E3F6OOVQ.mjs} +3 -3
- package/dist/{chunk-TFAYDIWM.mjs.map → chunk-E3F6OOVQ.mjs.map} +1 -1
- package/dist/chunk-EFMPOC6L.mjs +6 -0
- package/dist/{chunk-XCFCG46K.mjs.map → chunk-EFMPOC6L.mjs.map} +1 -1
- package/dist/{chunk-T6T5IQMN.mjs → chunk-FSSVIYQ7.mjs} +3 -3
- package/dist/{chunk-T6T5IQMN.mjs.map → chunk-FSSVIYQ7.mjs.map} +1 -1
- package/dist/{chunk-I7ORAWYT.mjs → chunk-HP7V2DI3.mjs} +3 -3
- package/dist/{chunk-I7ORAWYT.mjs.map → chunk-HP7V2DI3.mjs.map} +1 -1
- package/dist/{chunk-HVDKAR77.js → chunk-ICJ7EU4Z.js} +7 -7
- package/dist/{chunk-HVDKAR77.js.map → chunk-ICJ7EU4Z.js.map} +1 -1
- package/dist/{chunk-SAR473OC.js → chunk-JHOMOLZA.js} +12 -12
- package/dist/{chunk-SAR473OC.js.map → chunk-JHOMOLZA.js.map} +1 -1
- package/dist/{chunk-2XRGCDDG.js → chunk-KDWKSL7U.js} +9 -9
- package/dist/{chunk-2XRGCDDG.js.map → chunk-KDWKSL7U.js.map} +1 -1
- package/dist/{chunk-RDISSFEH.js → chunk-KPSESCYA.js} +15 -15
- package/dist/{chunk-RDISSFEH.js.map → chunk-KPSESCYA.js.map} +1 -1
- package/dist/{chunk-EHNUPEFY.mjs → chunk-L5GUV4M7.mjs} +7 -7
- package/dist/{chunk-EHNUPEFY.mjs.map → chunk-L5GUV4M7.mjs.map} +1 -1
- package/dist/{chunk-GDMOAGVS.js → chunk-LSNIDSLQ.js} +18 -18
- package/dist/{chunk-GDMOAGVS.js.map → chunk-LSNIDSLQ.js.map} +1 -1
- package/dist/{chunk-YWXZ4YLU.js → chunk-LUXCT2NU.js} +4 -4
- package/dist/{chunk-YWXZ4YLU.js.map → chunk-LUXCT2NU.js.map} +1 -1
- package/dist/{chunk-XA7RBHKT.js → chunk-NK6K4VHD.js} +4 -4
- package/dist/{chunk-XA7RBHKT.js.map → chunk-NK6K4VHD.js.map} +1 -1
- package/dist/{chunk-7BVZLSUJ.js → chunk-OIY5O3SE.js} +8 -8
- package/dist/{chunk-7BVZLSUJ.js.map → chunk-OIY5O3SE.js.map} +1 -1
- package/dist/{chunk-MP7ZYKMM.js → chunk-QQCOIGLN.js} +8 -8
- package/dist/{chunk-MP7ZYKMM.js.map → chunk-QQCOIGLN.js.map} +1 -1
- package/dist/{chunk-M2SEYO5J.js → chunk-RH5WIBIA.js} +5 -5
- package/dist/{chunk-M2SEYO5J.js.map → chunk-RH5WIBIA.js.map} +1 -1
- package/dist/{chunk-ZAVNGZJZ.js → chunk-SACGTFCK.js} +22 -6
- package/dist/chunk-SACGTFCK.js.map +1 -0
- package/dist/{chunk-HTLWSCUQ.mjs → chunk-SRJSR6YP.mjs} +22 -6
- package/dist/chunk-SRJSR6YP.mjs.map +1 -0
- package/dist/{chunk-PTZB4ES3.mjs → chunk-SSRQHRZB.mjs} +8 -8
- package/dist/{chunk-PTZB4ES3.mjs.map → chunk-SSRQHRZB.mjs.map} +1 -1
- package/dist/{chunk-XR3MDDQT.mjs → chunk-SYR7YSB2.mjs} +3 -3
- package/dist/{chunk-XR3MDDQT.mjs.map → chunk-SYR7YSB2.mjs.map} +1 -1
- package/dist/{chunk-BN4AL7XB.js → chunk-U7L7FW3K.js} +4 -4
- package/dist/{chunk-BN4AL7XB.js.map → chunk-U7L7FW3K.js.map} +1 -1
- package/dist/{chunk-6D3HZKTZ.mjs → chunk-UBSZ466T.mjs} +3 -3
- package/dist/{chunk-6D3HZKTZ.mjs.map → chunk-UBSZ466T.mjs.map} +1 -1
- package/dist/{chunk-RCRDDMUO.mjs → chunk-UHVII7W7.mjs} +3 -3
- package/dist/{chunk-RCRDDMUO.mjs.map → chunk-UHVII7W7.mjs.map} +1 -1
- package/dist/{chunk-UDNXM6RB.mjs → chunk-ULV3DZ27.mjs} +3 -3
- package/dist/{chunk-UDNXM6RB.mjs.map → chunk-ULV3DZ27.mjs.map} +1 -1
- package/dist/{chunk-INA4NW3Y.mjs → chunk-UVRB4SQU.mjs} +3 -3
- package/dist/{chunk-INA4NW3Y.mjs.map → chunk-UVRB4SQU.mjs.map} +1 -1
- package/dist/{chunk-J6HWSJT7.mjs → chunk-V3HJLXAI.mjs} +3 -3
- package/dist/{chunk-J6HWSJT7.mjs.map → chunk-V3HJLXAI.mjs.map} +1 -1
- package/dist/{chunk-T3HGONNE.mjs → chunk-WX6VKFHW.mjs} +4 -4
- package/dist/{chunk-T3HGONNE.mjs.map → chunk-WX6VKFHW.mjs.map} +1 -1
- package/dist/{chunk-XWFUQMU6.mjs → chunk-XKBADVXN.mjs} +3 -3
- package/dist/{chunk-XWFUQMU6.mjs.map → chunk-XKBADVXN.mjs.map} +1 -1
- package/dist/{chunk-FZAAQE4Y.mjs → chunk-XLD6K3BV.mjs} +4 -4
- package/dist/{chunk-FZAAQE4Y.mjs.map → chunk-XLD6K3BV.mjs.map} +1 -1
- package/dist/{chunk-RRR6Y6Y5.mjs → chunk-XWBQLPTZ.mjs} +4 -4
- package/dist/{chunk-RRR6Y6Y5.mjs.map → chunk-XWBQLPTZ.mjs.map} +1 -1
- package/dist/{chunk-SL6ZGJVN.mjs → chunk-YDOWCCE2.mjs} +4 -4
- package/dist/{chunk-SL6ZGJVN.mjs.map → chunk-YDOWCCE2.mjs.map} +1 -1
- package/dist/{chunk-S5UATBC7.js → chunk-YHGMM2XF.js} +14 -14
- package/dist/{chunk-S5UATBC7.js.map → chunk-YHGMM2XF.js.map} +1 -1
- package/dist/{chunk-JJDY5XXG.js → chunk-YZ6UYIXD.js} +3 -3
- package/dist/{chunk-JJDY5XXG.js.map → chunk-YZ6UYIXD.js.map} +1 -1
- package/dist/{chunk-MF6XLEX5.js → chunk-ZJNIM4GQ.js} +15 -15
- package/dist/{chunk-MF6XLEX5.js.map → chunk-ZJNIM4GQ.js.map} +1 -1
- package/dist/cli/index.js +36 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +29 -16
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/commerce/index.js +56 -56
- package/dist/commerce/index.mjs +5 -5
- package/dist/engage/index.js +10 -10
- package/dist/engage/index.mjs +7 -7
- package/dist/fleet/index.js +8 -8
- package/dist/fleet/index.mjs +4 -4
- package/dist/forms/index.js +16 -16
- package/dist/forms/index.mjs +9 -9
- package/dist/forms/server.js +10 -10
- package/dist/forms/server.mjs +8 -8
- package/dist/forms/static.js +7 -7
- package/dist/forms/static.mjs +6 -6
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +4 -4
- package/dist/index.js +63 -63
- package/dist/index.mjs +9 -9
- package/dist/layout/client.js +8 -8
- package/dist/layout/client.mjs +7 -7
- package/dist/layout/index.js +10 -10
- package/dist/layout/index.mjs +8 -8
- package/dist/maps/index.js +5 -5
- package/dist/maps/index.mjs +3 -3
- package/dist/og/config.d.ts +11 -1
- package/dist/og/config.d.ts.map +1 -1
- package/dist/og/index.js +5 -5
- package/dist/og/index.mjs +1 -1
- package/dist/og/pages.d.ts.map +1 -1
- package/dist/og/template.d.ts.map +1 -1
- package/dist/search/index.js +4 -4
- package/dist/search/index.mjs +3 -3
- package/dist/seo/client.js +5 -5
- package/dist/seo/client.mjs +4 -4
- package/dist/seo/index.js +5 -5
- package/dist/seo/index.mjs +4 -4
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sync/index.js +16 -16
- package/dist/sync/index.mjs +4 -4
- package/package.json +1 -1
- package/dist/AnalyticsProvider-NW3UZYL5.mjs +0 -10
- package/dist/AnalyticsProvider-VSTTYP4W.js +0 -31
- package/dist/ChatWidget-BJOE2OSI.js +0 -20
- package/dist/ChatWidget-EWQ7LRD4.mjs +0 -11
- package/dist/EngageWidget-CZMNLFWI.js +0 -18
- package/dist/EngageWidget-F427CI6Y.mjs +0 -9
- package/dist/ManagedForm-A7BROQIN.mjs +0 -14
- package/dist/ManagedForm-Z3Z5Z6OL.js +0 -23
- package/dist/SitemapSync-62F6HVAW.js +0 -17
- package/dist/SitemapSync-EY33A6P4.mjs +0 -8
- package/dist/chunk-HTLWSCUQ.mjs.map +0 -1
- package/dist/chunk-S5L73KZQ.js +0 -8
- package/dist/chunk-XCFCG46K.mjs +0 -6
- package/dist/chunk-ZAVNGZJZ.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/signal/SignalCore.tsx"],"names":["useState","useRef","getOrCreateVisitorId","getOrCreateSessionId","useEffect","useCallback","sonorFetch","getFreshCredential","isSiteToken"],"mappings":"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","file":"SignalCore-NA6TJFVE.js","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalCore\n *\n * The heavy half of SignalBridge: config fetching, SSE streaming, experiment\n * assignment, event queue/flush, and behavioral tracking. Mounted by the\n * SignalBridge shell as a CHILDLESS lazy sibling — it never wraps page\n * content, so the signal machinery stays out of the server-render path and\n * off the critical hydration chunk. It reports state up to the shell via\n * `onState` and registers its imperative API via `onRegister`.\n */\n\n'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n// Single source of truth for visitor/session IDs (storage keys _sk_vid/_sk_sid)\n// — shared with Analytics and Engage. Do NOT re-fork ID logic into this module.\nimport { getOrCreateVisitorId, getOrCreateSessionId } from '../shared/identity'\n// Canonical client transport — the same wrapper Analytics/Forms/Engage route\n// through (see shared/sonorFetch header). It gives every request a per-attempt\n// AbortSignal timeout, so a hung API aborts cleanly instead of being left to log\n// net::ERR_TIMED_OUT — the console error that fails Lighthouse best-practices.\n// It also sets x-api-key from the `apiKey` option, so callers drop the header.\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { getFreshCredential, isSiteToken } from '../shared/siteToken'\nimport type {\n SignalConfig,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// ============================================\n// Shell ↔ core contract\n// ============================================\n\nexport interface SignalCoreApi {\n trackEvent: (event: Partial<SignalEvent>) => void\n trackOutcome: (outcome: SignalOutcome) => void\n getExperiment: (experimentId: string) => ExperimentAssignment | null\n refreshConfig: () => Promise<void>\n}\n\nexport interface SignalCoreState {\n config: SignalConfig | null\n loading: boolean\n error: Error | null\n}\n\nexport interface SignalCoreProps {\n enabled: boolean\n realtime: boolean\n experiments: boolean\n behaviorTracking: boolean\n externalVisitorId?: string\n externalSessionId?: string\n pageMetadataRef?: React.RefObject<Record<string, unknown> | null>\n /** Called with the imperative API on mount, and with null on unmount. */\n onRegister: (api: SignalCoreApi | null) => void\n /** Called whenever config/loading/error change, so the shell can re-render consumers. */\n onState: (state: SignalCoreState) => void\n}\n\n// ============================================\n// Utility Functions\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// A visitor's console must stay clean (Lighthouse \"errors logged to the console\"\n// best-practice) — Signal's diagnostics only surface when the site opts into\n// debug via SiteKitClientProviders' __SITE_KIT_DEBUG__ global, mirroring how\n// AnalyticsProvider gates every one of its logs behind its `debug` prop.\nfunction isDebug(): boolean {\n return typeof window !== 'undefined' && !!(window as any).__SITE_KIT_DEBUG__\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\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 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 return 'Other'\n}\n\nfunction getOS(): string {\n if (typeof window === 'undefined') return 'unknown'\n const ua = navigator.userAgent\n if (ua.includes('Windows')) return 'Windows'\n if (ua.includes('Mac')) 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 return 'Other'\n}\n\n// ============================================\n// SignalCore Component (childless)\n// ============================================\n\nexport function SignalCore({\n enabled,\n realtime,\n experiments,\n behaviorTracking,\n externalVisitorId,\n externalSessionId,\n pageMetadataRef,\n onRegister,\n onState,\n}: SignalCoreProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n // Refs for SSE and tracking\n const eventSourceRef = useRef<EventSource | null>(null)\n const eventQueueRef = useRef<Partial<SignalEvent>[]>([])\n const flushTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const assignmentsRef = useRef<Map<string, ExperimentAssignment>>(new Map())\n\n // Behavioral tracking state\n const pageLoadTimeRef = useRef<number>(Date.now())\n const scrollDepthRef = useRef<number>(0)\n const clickCountRef = useRef<number>(0)\n\n const { apiUrl, apiKey } = getApiConfig()\n\n // Use external IDs from shared identity, fall back to the shared generators\n const resolvedVisitorId = externalVisitorId || getOrCreateVisitorId()\n const resolvedSessionId = externalSessionId || getOrCreateSessionId()\n\n // Mirror state up to the shell so context consumers re-render\n useEffect(() => {\n onState({ config, loading, error })\n }, [config, loading, error, onState])\n\n // ============================================\n // Experiment Assignment\n // ============================================\n\n const loadExperimentAssignment = useCallback(async (experimentId: string): Promise<ExperimentAssignment | null> => {\n // Check localStorage first\n const storageKey = `_signal_exp_${experimentId}`\n const stored = localStorage.getItem(storageKey)\n\n if (stored) {\n try {\n const assignment = JSON.parse(stored) as ExperimentAssignment\n if (assignment.expires > Date.now()) {\n assignmentsRef.current.set(experimentId, assignment)\n return assignment\n }\n } catch {\n // Invalid stored data, continue to fetch\n }\n }\n\n // Fetch from API — idempotent read, so the transport's default retries apply.\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/experiment/${experimentId}`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) return null\n\n const assignment = await response.json() as ExperimentAssignment\n\n // Store assignment\n localStorage.setItem(storageKey, JSON.stringify(assignment))\n assignmentsRef.current.set(experimentId, assignment)\n\n return assignment\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment assignment error:', err)\n return null\n }\n }, [apiUrl, apiKey])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n return assignmentsRef.current.get(experimentId) || null\n }, [])\n\n // ============================================\n // Config Fetching\n // ============================================\n\n const fetchConfig = useCallback(async () => {\n if (!apiKey || !enabled) {\n setLoading(false)\n return\n }\n\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/config`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) {\n throw new Error(`Failed to fetch Signal config: ${response.statusText}`)\n }\n\n const data = await response.json()\n setConfig(data.config)\n setError(null)\n\n // Load experiment assignments\n if (experiments && data.config?.experiments) {\n for (const exp of data.config.experiments) {\n if (exp.status === 'running') {\n await loadExperimentAssignment(exp.id)\n }\n }\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Config fetch error:', err)\n setError(err as Error)\n } finally {\n setLoading(false)\n }\n }, [apiUrl, apiKey, enabled, experiments, resolvedVisitorId, loadExperimentAssignment])\n\n // ============================================\n // SSE Real-time Updates\n // ============================================\n\n const connectSSE = useCallback(() => {\n if (!apiKey || !enabled || !realtime) return\n\n // Close existing connection\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n eventSourceRef.current = null\n }\n\n // EventSource cannot send headers, so the credential rides in the URL —\n // which server/CDN access logs capture. Per the transport contract in\n // sonorFetch.ts, the raw API key NEVER goes in a URL: only the\n // short-lived minted site token may (bounded exposure, unforgeable HMAC).\n // Raw-key mode (2.x layouts, mint-failure fallback) skips the stream —\n // config still loads via POST, only live push is lost.\n void (async () => {\n const credential = await getFreshCredential(apiKey)\n if (!credential || !isSiteToken(credential)) {\n if (isDebug()) {\n console.warn('[Signal] Realtime stream disabled: requires site-token mode (raw keys never go in URLs)')\n }\n return\n }\n if (eventSourceRef.current) return\n\n const url = `${apiUrl}/api/public/signal/stream?token=${encodeURIComponent(credential)}`\n connectEventSource(url)\n })()\n\n function connectEventSource(url: string) {\n const eventSource = new EventSource(url)\n\n eventSource.addEventListener('config_update', (e) => {\n try {\n const { config: newConfig, version } = JSON.parse(e.data)\n setConfig(prev => {\n if (prev?.version !== version) {\n if (isDebug()) console.log('[Signal] Config updated to version:', version)\n return newConfig\n }\n return prev\n })\n } catch (err) {\n if (isDebug()) console.error('[Signal] SSE parse error:', err)\n }\n })\n\n eventSource.addEventListener('experiment_update', (e) => {\n try {\n const { experiment_id, action } = JSON.parse(e.data)\n if (action === 'started' || action === 'updated') {\n loadExperimentAssignment(experiment_id)\n } else if (action === 'stopped') {\n assignmentsRef.current.delete(experiment_id)\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment update error:', err)\n }\n })\n\n eventSource.onerror = () => {\n if (isDebug()) console.warn('[Signal] SSE connection error, reconnecting...')\n eventSource.close()\n if (eventSourceRef.current === eventSource) {\n eventSourceRef.current = null\n }\n // Reconnect after 5 seconds (re-mints the token if it expired)\n setTimeout(connectSSE, 5000)\n }\n\n eventSourceRef.current = eventSource\n }\n }, [apiUrl, apiKey, enabled, realtime, loadExperimentAssignment])\n\n // ============================================\n // Event Tracking\n // ============================================\n\n const flushEvents = useCallback(async () => {\n if (eventQueueRef.current.length === 0) return\n\n const events = [...eventQueueRef.current]\n eventQueueRef.current = []\n\n try {\n // retries: 0 — fire-and-forget tracking; a retried flush after a lost\n // response would double-count events. The transport still aborts a hung\n // request at its timeout (no net::ERR_TIMED_OUT).\n await sonorFetch(\n `${apiUrl}/api/public/signal/events`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n events,\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n // Re-queue failed events\n eventQueueRef.current = [...events, ...eventQueueRef.current]\n if (isDebug()) console.error('[Signal] Event flush error:', err)\n }\n }, [apiUrl, apiKey])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (!enabled || !apiKey) return\n\n // Enrich event with context\n const enrichedEvent: Partial<SignalEvent> = {\n ...event,\n page_url: window.location.href,\n page_path: window.location.pathname,\n referrer: document.referrer,\n device_type: getDeviceType(),\n browser: getBrowser(),\n os: getOS(),\n viewport_width: window.innerWidth,\n viewport_height: window.innerHeight,\n time_on_page: Date.now() - pageLoadTimeRef.current,\n scroll_depth: scrollDepthRef.current,\n click_count: clickCountRef.current,\n experiments: Array.from(assignmentsRef.current.values()).map(a => ({\n experiment_id: a.experiment_id,\n variant_key: a.variant_key,\n })),\n // Merge page metadata from Analytics if available\n page_metadata: pageMetadataRef?.current ?? undefined,\n timestamp: new Date().toISOString(),\n }\n\n eventQueueRef.current.push(enrichedEvent)\n\n // Debounce flush\n if (flushTimeoutRef.current) {\n clearTimeout(flushTimeoutRef.current)\n }\n flushTimeoutRef.current = setTimeout(flushEvents, 1000)\n }, [enabled, apiKey, flushEvents])\n\n // ============================================\n // Outcome Tracking\n // ============================================\n\n const trackOutcome = useCallback(async (outcome: SignalOutcome) => {\n if (!enabled || !apiKey) return\n\n try {\n // retries: 0 — fire-and-forget conversion signal; never double-fire on a\n // lost response. Still aborts a hung request at the transport timeout.\n await sonorFetch(\n `${apiUrl}/api/public/signal/outcome`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...outcome,\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n experiments: Array.from(assignmentsRef.current.keys()),\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n if (isDebug()) console.error('[Signal] Outcome tracking error:', err)\n }\n }, [apiUrl, apiKey, enabled])\n\n // ============================================\n // Behavioral Tracking\n // ============================================\n\n useEffect(() => {\n if (!behaviorTracking || typeof window === 'undefined') return\n\n // Track scroll depth\n const handleScroll = () => {\n const scrollTop = window.scrollY\n const docHeight = document.documentElement.scrollHeight - window.innerHeight\n const depth = docHeight > 0 ? Math.round((scrollTop / docHeight) * 100) : 0\n scrollDepthRef.current = Math.max(scrollDepthRef.current, depth)\n }\n\n // Track clicks\n const handleClick = () => {\n clickCountRef.current++\n }\n\n window.addEventListener('scroll', handleScroll, { passive: true })\n window.addEventListener('click', handleClick)\n\n // Flush on visibility change or page hide.\n // `pagehide` (not `beforeunload`): fires on iOS Safari, bfcache-safe.\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n flushEvents()\n }\n }\n\n document.addEventListener('visibilitychange', handleVisibilityChange)\n window.addEventListener('pagehide', flushEvents)\n\n return () => {\n window.removeEventListener('scroll', handleScroll)\n window.removeEventListener('click', handleClick)\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n window.removeEventListener('pagehide', flushEvents)\n }\n }, [behaviorTracking, flushEvents])\n\n // ============================================\n // Initialization + shell registration\n // ============================================\n\n useEffect(() => {\n fetchConfig()\n }, [fetchConfig])\n\n useEffect(() => {\n if (config && realtime) {\n connectSSE()\n }\n\n return () => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n }\n }\n }, [config, realtime, connectSSE])\n\n // Hand the imperative API to the shell; buffered calls drain on register.\n useEffect(() => {\n onRegister({\n trackEvent,\n trackOutcome: (outcome: SignalOutcome) => { void trackOutcome(outcome) },\n getExperiment,\n refreshConfig: fetchConfig,\n })\n return () => onRegister(null)\n }, [onRegister, trackEvent, trackOutcome, getExperiment, fetchConfig])\n\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/signal/SignalCore.tsx"],"names":["useState","useRef","getOrCreateVisitorId","getOrCreateSessionId","useEffect","useCallback","sonorFetch","getFreshCredential","isSiteToken"],"mappings":"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","file":"SignalCore-AW5VDA4Y.js","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalCore\n *\n * The heavy half of SignalBridge: config fetching, SSE streaming, experiment\n * assignment, event queue/flush, and behavioral tracking. Mounted by the\n * SignalBridge shell as a CHILDLESS lazy sibling — it never wraps page\n * content, so the signal machinery stays out of the server-render path and\n * off the critical hydration chunk. It reports state up to the shell via\n * `onState` and registers its imperative API via `onRegister`.\n */\n\n'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n// Single source of truth for visitor/session IDs (storage keys _sk_vid/_sk_sid)\n// — shared with Analytics and Engage. Do NOT re-fork ID logic into this module.\nimport { getOrCreateVisitorId, getOrCreateSessionId } from '../shared/identity'\n// Canonical client transport — the same wrapper Analytics/Forms/Engage route\n// through (see shared/sonorFetch header). It gives every request a per-attempt\n// AbortSignal timeout, so a hung API aborts cleanly instead of being left to log\n// net::ERR_TIMED_OUT — the console error that fails Lighthouse best-practices.\n// It also sets x-api-key from the `apiKey` option, so callers drop the header.\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { getFreshCredential, isSiteToken } from '../shared/siteToken'\nimport type {\n SignalConfig,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// ============================================\n// Shell ↔ core contract\n// ============================================\n\nexport interface SignalCoreApi {\n trackEvent: (event: Partial<SignalEvent>) => void\n trackOutcome: (outcome: SignalOutcome) => void\n getExperiment: (experimentId: string) => ExperimentAssignment | null\n refreshConfig: () => Promise<void>\n}\n\nexport interface SignalCoreState {\n config: SignalConfig | null\n loading: boolean\n error: Error | null\n}\n\nexport interface SignalCoreProps {\n enabled: boolean\n realtime: boolean\n experiments: boolean\n behaviorTracking: boolean\n externalVisitorId?: string\n externalSessionId?: string\n pageMetadataRef?: React.RefObject<Record<string, unknown> | null>\n /** Called with the imperative API on mount, and with null on unmount. */\n onRegister: (api: SignalCoreApi | null) => void\n /** Called whenever config/loading/error change, so the shell can re-render consumers. */\n onState: (state: SignalCoreState) => void\n}\n\n// ============================================\n// Utility Functions\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// A visitor's console must stay clean (Lighthouse \"errors logged to the console\"\n// best-practice) — Signal's diagnostics only surface when the site opts into\n// debug via SiteKitClientProviders' __SITE_KIT_DEBUG__ global, mirroring how\n// AnalyticsProvider gates every one of its logs behind its `debug` prop.\nfunction isDebug(): boolean {\n return typeof window !== 'undefined' && !!(window as any).__SITE_KIT_DEBUG__\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\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 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 return 'Other'\n}\n\nfunction getOS(): string {\n if (typeof window === 'undefined') return 'unknown'\n const ua = navigator.userAgent\n if (ua.includes('Windows')) return 'Windows'\n if (ua.includes('Mac')) 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 return 'Other'\n}\n\n// ============================================\n// SignalCore Component (childless)\n// ============================================\n\nexport function SignalCore({\n enabled,\n realtime,\n experiments,\n behaviorTracking,\n externalVisitorId,\n externalSessionId,\n pageMetadataRef,\n onRegister,\n onState,\n}: SignalCoreProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n // Refs for SSE and tracking\n const eventSourceRef = useRef<EventSource | null>(null)\n const eventQueueRef = useRef<Partial<SignalEvent>[]>([])\n const flushTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const assignmentsRef = useRef<Map<string, ExperimentAssignment>>(new Map())\n\n // Behavioral tracking state\n const pageLoadTimeRef = useRef<number>(Date.now())\n const scrollDepthRef = useRef<number>(0)\n const clickCountRef = useRef<number>(0)\n\n const { apiUrl, apiKey } = getApiConfig()\n\n // Use external IDs from shared identity, fall back to the shared generators\n const resolvedVisitorId = externalVisitorId || getOrCreateVisitorId()\n const resolvedSessionId = externalSessionId || getOrCreateSessionId()\n\n // Mirror state up to the shell so context consumers re-render\n useEffect(() => {\n onState({ config, loading, error })\n }, [config, loading, error, onState])\n\n // ============================================\n // Experiment Assignment\n // ============================================\n\n const loadExperimentAssignment = useCallback(async (experimentId: string): Promise<ExperimentAssignment | null> => {\n // Check localStorage first\n const storageKey = `_signal_exp_${experimentId}`\n const stored = localStorage.getItem(storageKey)\n\n if (stored) {\n try {\n const assignment = JSON.parse(stored) as ExperimentAssignment\n if (assignment.expires > Date.now()) {\n assignmentsRef.current.set(experimentId, assignment)\n return assignment\n }\n } catch {\n // Invalid stored data, continue to fetch\n }\n }\n\n // Fetch from API — idempotent read, so the transport's default retries apply.\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/experiment/${experimentId}`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) return null\n\n const assignment = await response.json() as ExperimentAssignment\n\n // Store assignment\n localStorage.setItem(storageKey, JSON.stringify(assignment))\n assignmentsRef.current.set(experimentId, assignment)\n\n return assignment\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment assignment error:', err)\n return null\n }\n }, [apiUrl, apiKey])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n return assignmentsRef.current.get(experimentId) || null\n }, [])\n\n // ============================================\n // Config Fetching\n // ============================================\n\n const fetchConfig = useCallback(async () => {\n if (!apiKey || !enabled) {\n setLoading(false)\n return\n }\n\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/config`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) {\n throw new Error(`Failed to fetch Signal config: ${response.statusText}`)\n }\n\n const data = await response.json()\n setConfig(data.config)\n setError(null)\n\n // Load experiment assignments\n if (experiments && data.config?.experiments) {\n for (const exp of data.config.experiments) {\n if (exp.status === 'running') {\n await loadExperimentAssignment(exp.id)\n }\n }\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Config fetch error:', err)\n setError(err as Error)\n } finally {\n setLoading(false)\n }\n }, [apiUrl, apiKey, enabled, experiments, resolvedVisitorId, loadExperimentAssignment])\n\n // ============================================\n // SSE Real-time Updates\n // ============================================\n\n const connectSSE = useCallback(() => {\n if (!apiKey || !enabled || !realtime) return\n\n // Close existing connection\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n eventSourceRef.current = null\n }\n\n // EventSource cannot send headers, so the credential rides in the URL —\n // which server/CDN access logs capture. Per the transport contract in\n // sonorFetch.ts, the raw API key NEVER goes in a URL: only the\n // short-lived minted site token may (bounded exposure, unforgeable HMAC).\n // Raw-key mode (2.x layouts, mint-failure fallback) skips the stream —\n // config still loads via POST, only live push is lost.\n void (async () => {\n const credential = await getFreshCredential(apiKey)\n if (!credential || !isSiteToken(credential)) {\n if (isDebug()) {\n console.warn('[Signal] Realtime stream disabled: requires site-token mode (raw keys never go in URLs)')\n }\n return\n }\n if (eventSourceRef.current) return\n\n const url = `${apiUrl}/api/public/signal/stream?token=${encodeURIComponent(credential)}`\n connectEventSource(url)\n })()\n\n function connectEventSource(url: string) {\n const eventSource = new EventSource(url)\n\n eventSource.addEventListener('config_update', (e) => {\n try {\n const { config: newConfig, version } = JSON.parse(e.data)\n setConfig(prev => {\n if (prev?.version !== version) {\n if (isDebug()) console.log('[Signal] Config updated to version:', version)\n return newConfig\n }\n return prev\n })\n } catch (err) {\n if (isDebug()) console.error('[Signal] SSE parse error:', err)\n }\n })\n\n eventSource.addEventListener('experiment_update', (e) => {\n try {\n const { experiment_id, action } = JSON.parse(e.data)\n if (action === 'started' || action === 'updated') {\n loadExperimentAssignment(experiment_id)\n } else if (action === 'stopped') {\n assignmentsRef.current.delete(experiment_id)\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment update error:', err)\n }\n })\n\n eventSource.onerror = () => {\n if (isDebug()) console.warn('[Signal] SSE connection error, reconnecting...')\n eventSource.close()\n if (eventSourceRef.current === eventSource) {\n eventSourceRef.current = null\n }\n // Reconnect after 5 seconds (re-mints the token if it expired)\n setTimeout(connectSSE, 5000)\n }\n\n eventSourceRef.current = eventSource\n }\n }, [apiUrl, apiKey, enabled, realtime, loadExperimentAssignment])\n\n // ============================================\n // Event Tracking\n // ============================================\n\n const flushEvents = useCallback(async () => {\n if (eventQueueRef.current.length === 0) return\n\n const events = [...eventQueueRef.current]\n eventQueueRef.current = []\n\n try {\n // retries: 0 — fire-and-forget tracking; a retried flush after a lost\n // response would double-count events. The transport still aborts a hung\n // request at its timeout (no net::ERR_TIMED_OUT).\n await sonorFetch(\n `${apiUrl}/api/public/signal/events`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n events,\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n // Re-queue failed events\n eventQueueRef.current = [...events, ...eventQueueRef.current]\n if (isDebug()) console.error('[Signal] Event flush error:', err)\n }\n }, [apiUrl, apiKey])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (!enabled || !apiKey) return\n\n // Enrich event with context\n const enrichedEvent: Partial<SignalEvent> = {\n ...event,\n page_url: window.location.href,\n page_path: window.location.pathname,\n referrer: document.referrer,\n device_type: getDeviceType(),\n browser: getBrowser(),\n os: getOS(),\n viewport_width: window.innerWidth,\n viewport_height: window.innerHeight,\n time_on_page: Date.now() - pageLoadTimeRef.current,\n scroll_depth: scrollDepthRef.current,\n click_count: clickCountRef.current,\n experiments: Array.from(assignmentsRef.current.values()).map(a => ({\n experiment_id: a.experiment_id,\n variant_key: a.variant_key,\n })),\n // Merge page metadata from Analytics if available\n page_metadata: pageMetadataRef?.current ?? undefined,\n timestamp: new Date().toISOString(),\n }\n\n eventQueueRef.current.push(enrichedEvent)\n\n // Debounce flush\n if (flushTimeoutRef.current) {\n clearTimeout(flushTimeoutRef.current)\n }\n flushTimeoutRef.current = setTimeout(flushEvents, 1000)\n }, [enabled, apiKey, flushEvents])\n\n // ============================================\n // Outcome Tracking\n // ============================================\n\n const trackOutcome = useCallback(async (outcome: SignalOutcome) => {\n if (!enabled || !apiKey) return\n\n try {\n // retries: 0 — fire-and-forget conversion signal; never double-fire on a\n // lost response. Still aborts a hung request at the transport timeout.\n await sonorFetch(\n `${apiUrl}/api/public/signal/outcome`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...outcome,\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n experiments: Array.from(assignmentsRef.current.keys()),\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n if (isDebug()) console.error('[Signal] Outcome tracking error:', err)\n }\n }, [apiUrl, apiKey, enabled])\n\n // ============================================\n // Behavioral Tracking\n // ============================================\n\n useEffect(() => {\n if (!behaviorTracking || typeof window === 'undefined') return\n\n // Track scroll depth\n const handleScroll = () => {\n const scrollTop = window.scrollY\n const docHeight = document.documentElement.scrollHeight - window.innerHeight\n const depth = docHeight > 0 ? Math.round((scrollTop / docHeight) * 100) : 0\n scrollDepthRef.current = Math.max(scrollDepthRef.current, depth)\n }\n\n // Track clicks\n const handleClick = () => {\n clickCountRef.current++\n }\n\n window.addEventListener('scroll', handleScroll, { passive: true })\n window.addEventListener('click', handleClick)\n\n // Flush on visibility change or page hide.\n // `pagehide` (not `beforeunload`): fires on iOS Safari, bfcache-safe.\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n flushEvents()\n }\n }\n\n document.addEventListener('visibilitychange', handleVisibilityChange)\n window.addEventListener('pagehide', flushEvents)\n\n return () => {\n window.removeEventListener('scroll', handleScroll)\n window.removeEventListener('click', handleClick)\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n window.removeEventListener('pagehide', flushEvents)\n }\n }, [behaviorTracking, flushEvents])\n\n // ============================================\n // Initialization + shell registration\n // ============================================\n\n useEffect(() => {\n fetchConfig()\n }, [fetchConfig])\n\n useEffect(() => {\n if (config && realtime) {\n connectSSE()\n }\n\n return () => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n }\n }\n }, [config, realtime, connectSSE])\n\n // Hand the imperative API to the shell; buffered calls drain on register.\n useEffect(() => {\n onRegister({\n trackEvent,\n trackOutcome: (outcome: SignalOutcome) => { void trackOutcome(outcome) },\n getExperiment,\n refreshConfig: fetchConfig,\n })\n return () => onRegister(null)\n }, [onRegister, trackEvent, trackOutcome, getExperiment, fetchConfig])\n\n return null\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-ZZQAGCSI.mjs';
|
|
3
3
|
import './chunk-6EDVCUAG.mjs';
|
|
4
|
-
import { sonorFetch } from './chunk-
|
|
5
|
-
import { getFreshCredential, isSiteToken } from './chunk-
|
|
6
|
-
import './chunk-
|
|
4
|
+
import { sonorFetch } from './chunk-XWBQLPTZ.mjs';
|
|
5
|
+
import { getFreshCredential, isSiteToken } from './chunk-FSSVIYQ7.mjs';
|
|
6
|
+
import './chunk-EFMPOC6L.mjs';
|
|
7
7
|
import './chunk-BEXTDHO4.mjs';
|
|
8
8
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
9
9
|
|
|
@@ -326,5 +326,5 @@ function SignalCore({
|
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
export { SignalCore };
|
|
329
|
-
//# sourceMappingURL=SignalCore-
|
|
330
|
-
//# sourceMappingURL=SignalCore-
|
|
329
|
+
//# sourceMappingURL=SignalCore-DYBIG4JP.mjs.map
|
|
330
|
+
//# sourceMappingURL=SignalCore-DYBIG4JP.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/signal/SignalCore.tsx"],"names":[],"mappings":"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","file":"SignalCore-77UH6PZ4.mjs","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalCore\n *\n * The heavy half of SignalBridge: config fetching, SSE streaming, experiment\n * assignment, event queue/flush, and behavioral tracking. Mounted by the\n * SignalBridge shell as a CHILDLESS lazy sibling — it never wraps page\n * content, so the signal machinery stays out of the server-render path and\n * off the critical hydration chunk. It reports state up to the shell via\n * `onState` and registers its imperative API via `onRegister`.\n */\n\n'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n// Single source of truth for visitor/session IDs (storage keys _sk_vid/_sk_sid)\n// — shared with Analytics and Engage. Do NOT re-fork ID logic into this module.\nimport { getOrCreateVisitorId, getOrCreateSessionId } from '../shared/identity'\n// Canonical client transport — the same wrapper Analytics/Forms/Engage route\n// through (see shared/sonorFetch header). It gives every request a per-attempt\n// AbortSignal timeout, so a hung API aborts cleanly instead of being left to log\n// net::ERR_TIMED_OUT — the console error that fails Lighthouse best-practices.\n// It also sets x-api-key from the `apiKey` option, so callers drop the header.\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { getFreshCredential, isSiteToken } from '../shared/siteToken'\nimport type {\n SignalConfig,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// ============================================\n// Shell ↔ core contract\n// ============================================\n\nexport interface SignalCoreApi {\n trackEvent: (event: Partial<SignalEvent>) => void\n trackOutcome: (outcome: SignalOutcome) => void\n getExperiment: (experimentId: string) => ExperimentAssignment | null\n refreshConfig: () => Promise<void>\n}\n\nexport interface SignalCoreState {\n config: SignalConfig | null\n loading: boolean\n error: Error | null\n}\n\nexport interface SignalCoreProps {\n enabled: boolean\n realtime: boolean\n experiments: boolean\n behaviorTracking: boolean\n externalVisitorId?: string\n externalSessionId?: string\n pageMetadataRef?: React.RefObject<Record<string, unknown> | null>\n /** Called with the imperative API on mount, and with null on unmount. */\n onRegister: (api: SignalCoreApi | null) => void\n /** Called whenever config/loading/error change, so the shell can re-render consumers. */\n onState: (state: SignalCoreState) => void\n}\n\n// ============================================\n// Utility Functions\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// A visitor's console must stay clean (Lighthouse \"errors logged to the console\"\n// best-practice) — Signal's diagnostics only surface when the site opts into\n// debug via SiteKitClientProviders' __SITE_KIT_DEBUG__ global, mirroring how\n// AnalyticsProvider gates every one of its logs behind its `debug` prop.\nfunction isDebug(): boolean {\n return typeof window !== 'undefined' && !!(window as any).__SITE_KIT_DEBUG__\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\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 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 return 'Other'\n}\n\nfunction getOS(): string {\n if (typeof window === 'undefined') return 'unknown'\n const ua = navigator.userAgent\n if (ua.includes('Windows')) return 'Windows'\n if (ua.includes('Mac')) 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 return 'Other'\n}\n\n// ============================================\n// SignalCore Component (childless)\n// ============================================\n\nexport function SignalCore({\n enabled,\n realtime,\n experiments,\n behaviorTracking,\n externalVisitorId,\n externalSessionId,\n pageMetadataRef,\n onRegister,\n onState,\n}: SignalCoreProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n // Refs for SSE and tracking\n const eventSourceRef = useRef<EventSource | null>(null)\n const eventQueueRef = useRef<Partial<SignalEvent>[]>([])\n const flushTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const assignmentsRef = useRef<Map<string, ExperimentAssignment>>(new Map())\n\n // Behavioral tracking state\n const pageLoadTimeRef = useRef<number>(Date.now())\n const scrollDepthRef = useRef<number>(0)\n const clickCountRef = useRef<number>(0)\n\n const { apiUrl, apiKey } = getApiConfig()\n\n // Use external IDs from shared identity, fall back to the shared generators\n const resolvedVisitorId = externalVisitorId || getOrCreateVisitorId()\n const resolvedSessionId = externalSessionId || getOrCreateSessionId()\n\n // Mirror state up to the shell so context consumers re-render\n useEffect(() => {\n onState({ config, loading, error })\n }, [config, loading, error, onState])\n\n // ============================================\n // Experiment Assignment\n // ============================================\n\n const loadExperimentAssignment = useCallback(async (experimentId: string): Promise<ExperimentAssignment | null> => {\n // Check localStorage first\n const storageKey = `_signal_exp_${experimentId}`\n const stored = localStorage.getItem(storageKey)\n\n if (stored) {\n try {\n const assignment = JSON.parse(stored) as ExperimentAssignment\n if (assignment.expires > Date.now()) {\n assignmentsRef.current.set(experimentId, assignment)\n return assignment\n }\n } catch {\n // Invalid stored data, continue to fetch\n }\n }\n\n // Fetch from API — idempotent read, so the transport's default retries apply.\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/experiment/${experimentId}`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) return null\n\n const assignment = await response.json() as ExperimentAssignment\n\n // Store assignment\n localStorage.setItem(storageKey, JSON.stringify(assignment))\n assignmentsRef.current.set(experimentId, assignment)\n\n return assignment\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment assignment error:', err)\n return null\n }\n }, [apiUrl, apiKey])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n return assignmentsRef.current.get(experimentId) || null\n }, [])\n\n // ============================================\n // Config Fetching\n // ============================================\n\n const fetchConfig = useCallback(async () => {\n if (!apiKey || !enabled) {\n setLoading(false)\n return\n }\n\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/config`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) {\n throw new Error(`Failed to fetch Signal config: ${response.statusText}`)\n }\n\n const data = await response.json()\n setConfig(data.config)\n setError(null)\n\n // Load experiment assignments\n if (experiments && data.config?.experiments) {\n for (const exp of data.config.experiments) {\n if (exp.status === 'running') {\n await loadExperimentAssignment(exp.id)\n }\n }\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Config fetch error:', err)\n setError(err as Error)\n } finally {\n setLoading(false)\n }\n }, [apiUrl, apiKey, enabled, experiments, resolvedVisitorId, loadExperimentAssignment])\n\n // ============================================\n // SSE Real-time Updates\n // ============================================\n\n const connectSSE = useCallback(() => {\n if (!apiKey || !enabled || !realtime) return\n\n // Close existing connection\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n eventSourceRef.current = null\n }\n\n // EventSource cannot send headers, so the credential rides in the URL —\n // which server/CDN access logs capture. Per the transport contract in\n // sonorFetch.ts, the raw API key NEVER goes in a URL: only the\n // short-lived minted site token may (bounded exposure, unforgeable HMAC).\n // Raw-key mode (2.x layouts, mint-failure fallback) skips the stream —\n // config still loads via POST, only live push is lost.\n void (async () => {\n const credential = await getFreshCredential(apiKey)\n if (!credential || !isSiteToken(credential)) {\n if (isDebug()) {\n console.warn('[Signal] Realtime stream disabled: requires site-token mode (raw keys never go in URLs)')\n }\n return\n }\n if (eventSourceRef.current) return\n\n const url = `${apiUrl}/api/public/signal/stream?token=${encodeURIComponent(credential)}`\n connectEventSource(url)\n })()\n\n function connectEventSource(url: string) {\n const eventSource = new EventSource(url)\n\n eventSource.addEventListener('config_update', (e) => {\n try {\n const { config: newConfig, version } = JSON.parse(e.data)\n setConfig(prev => {\n if (prev?.version !== version) {\n if (isDebug()) console.log('[Signal] Config updated to version:', version)\n return newConfig\n }\n return prev\n })\n } catch (err) {\n if (isDebug()) console.error('[Signal] SSE parse error:', err)\n }\n })\n\n eventSource.addEventListener('experiment_update', (e) => {\n try {\n const { experiment_id, action } = JSON.parse(e.data)\n if (action === 'started' || action === 'updated') {\n loadExperimentAssignment(experiment_id)\n } else if (action === 'stopped') {\n assignmentsRef.current.delete(experiment_id)\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment update error:', err)\n }\n })\n\n eventSource.onerror = () => {\n if (isDebug()) console.warn('[Signal] SSE connection error, reconnecting...')\n eventSource.close()\n if (eventSourceRef.current === eventSource) {\n eventSourceRef.current = null\n }\n // Reconnect after 5 seconds (re-mints the token if it expired)\n setTimeout(connectSSE, 5000)\n }\n\n eventSourceRef.current = eventSource\n }\n }, [apiUrl, apiKey, enabled, realtime, loadExperimentAssignment])\n\n // ============================================\n // Event Tracking\n // ============================================\n\n const flushEvents = useCallback(async () => {\n if (eventQueueRef.current.length === 0) return\n\n const events = [...eventQueueRef.current]\n eventQueueRef.current = []\n\n try {\n // retries: 0 — fire-and-forget tracking; a retried flush after a lost\n // response would double-count events. The transport still aborts a hung\n // request at its timeout (no net::ERR_TIMED_OUT).\n await sonorFetch(\n `${apiUrl}/api/public/signal/events`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n events,\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n // Re-queue failed events\n eventQueueRef.current = [...events, ...eventQueueRef.current]\n if (isDebug()) console.error('[Signal] Event flush error:', err)\n }\n }, [apiUrl, apiKey])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (!enabled || !apiKey) return\n\n // Enrich event with context\n const enrichedEvent: Partial<SignalEvent> = {\n ...event,\n page_url: window.location.href,\n page_path: window.location.pathname,\n referrer: document.referrer,\n device_type: getDeviceType(),\n browser: getBrowser(),\n os: getOS(),\n viewport_width: window.innerWidth,\n viewport_height: window.innerHeight,\n time_on_page: Date.now() - pageLoadTimeRef.current,\n scroll_depth: scrollDepthRef.current,\n click_count: clickCountRef.current,\n experiments: Array.from(assignmentsRef.current.values()).map(a => ({\n experiment_id: a.experiment_id,\n variant_key: a.variant_key,\n })),\n // Merge page metadata from Analytics if available\n page_metadata: pageMetadataRef?.current ?? undefined,\n timestamp: new Date().toISOString(),\n }\n\n eventQueueRef.current.push(enrichedEvent)\n\n // Debounce flush\n if (flushTimeoutRef.current) {\n clearTimeout(flushTimeoutRef.current)\n }\n flushTimeoutRef.current = setTimeout(flushEvents, 1000)\n }, [enabled, apiKey, flushEvents])\n\n // ============================================\n // Outcome Tracking\n // ============================================\n\n const trackOutcome = useCallback(async (outcome: SignalOutcome) => {\n if (!enabled || !apiKey) return\n\n try {\n // retries: 0 — fire-and-forget conversion signal; never double-fire on a\n // lost response. Still aborts a hung request at the transport timeout.\n await sonorFetch(\n `${apiUrl}/api/public/signal/outcome`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...outcome,\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n experiments: Array.from(assignmentsRef.current.keys()),\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n if (isDebug()) console.error('[Signal] Outcome tracking error:', err)\n }\n }, [apiUrl, apiKey, enabled])\n\n // ============================================\n // Behavioral Tracking\n // ============================================\n\n useEffect(() => {\n if (!behaviorTracking || typeof window === 'undefined') return\n\n // Track scroll depth\n const handleScroll = () => {\n const scrollTop = window.scrollY\n const docHeight = document.documentElement.scrollHeight - window.innerHeight\n const depth = docHeight > 0 ? Math.round((scrollTop / docHeight) * 100) : 0\n scrollDepthRef.current = Math.max(scrollDepthRef.current, depth)\n }\n\n // Track clicks\n const handleClick = () => {\n clickCountRef.current++\n }\n\n window.addEventListener('scroll', handleScroll, { passive: true })\n window.addEventListener('click', handleClick)\n\n // Flush on visibility change or page hide.\n // `pagehide` (not `beforeunload`): fires on iOS Safari, bfcache-safe.\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n flushEvents()\n }\n }\n\n document.addEventListener('visibilitychange', handleVisibilityChange)\n window.addEventListener('pagehide', flushEvents)\n\n return () => {\n window.removeEventListener('scroll', handleScroll)\n window.removeEventListener('click', handleClick)\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n window.removeEventListener('pagehide', flushEvents)\n }\n }, [behaviorTracking, flushEvents])\n\n // ============================================\n // Initialization + shell registration\n // ============================================\n\n useEffect(() => {\n fetchConfig()\n }, [fetchConfig])\n\n useEffect(() => {\n if (config && realtime) {\n connectSSE()\n }\n\n return () => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n }\n }\n }, [config, realtime, connectSSE])\n\n // Hand the imperative API to the shell; buffered calls drain on register.\n useEffect(() => {\n onRegister({\n trackEvent,\n trackOutcome: (outcome: SignalOutcome) => { void trackOutcome(outcome) },\n getExperiment,\n refreshConfig: fetchConfig,\n })\n return () => onRegister(null)\n }, [onRegister, trackEvent, trackOutcome, getExperiment, fetchConfig])\n\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/signal/SignalCore.tsx"],"names":[],"mappings":"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","file":"SignalCore-DYBIG4JP.mjs","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalCore\n *\n * The heavy half of SignalBridge: config fetching, SSE streaming, experiment\n * assignment, event queue/flush, and behavioral tracking. Mounted by the\n * SignalBridge shell as a CHILDLESS lazy sibling — it never wraps page\n * content, so the signal machinery stays out of the server-render path and\n * off the critical hydration chunk. It reports state up to the shell via\n * `onState` and registers its imperative API via `onRegister`.\n */\n\n'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n// Single source of truth for visitor/session IDs (storage keys _sk_vid/_sk_sid)\n// — shared with Analytics and Engage. Do NOT re-fork ID logic into this module.\nimport { getOrCreateVisitorId, getOrCreateSessionId } from '../shared/identity'\n// Canonical client transport — the same wrapper Analytics/Forms/Engage route\n// through (see shared/sonorFetch header). It gives every request a per-attempt\n// AbortSignal timeout, so a hung API aborts cleanly instead of being left to log\n// net::ERR_TIMED_OUT — the console error that fails Lighthouse best-practices.\n// It also sets x-api-key from the `apiKey` option, so callers drop the header.\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { getFreshCredential, isSiteToken } from '../shared/siteToken'\nimport type {\n SignalConfig,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// ============================================\n// Shell ↔ core contract\n// ============================================\n\nexport interface SignalCoreApi {\n trackEvent: (event: Partial<SignalEvent>) => void\n trackOutcome: (outcome: SignalOutcome) => void\n getExperiment: (experimentId: string) => ExperimentAssignment | null\n refreshConfig: () => Promise<void>\n}\n\nexport interface SignalCoreState {\n config: SignalConfig | null\n loading: boolean\n error: Error | null\n}\n\nexport interface SignalCoreProps {\n enabled: boolean\n realtime: boolean\n experiments: boolean\n behaviorTracking: boolean\n externalVisitorId?: string\n externalSessionId?: string\n pageMetadataRef?: React.RefObject<Record<string, unknown> | null>\n /** Called with the imperative API on mount, and with null on unmount. */\n onRegister: (api: SignalCoreApi | null) => void\n /** Called whenever config/loading/error change, so the shell can re-render consumers. */\n onState: (state: SignalCoreState) => void\n}\n\n// ============================================\n// Utility Functions\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// A visitor's console must stay clean (Lighthouse \"errors logged to the console\"\n// best-practice) — Signal's diagnostics only surface when the site opts into\n// debug via SiteKitClientProviders' __SITE_KIT_DEBUG__ global, mirroring how\n// AnalyticsProvider gates every one of its logs behind its `debug` prop.\nfunction isDebug(): boolean {\n return typeof window !== 'undefined' && !!(window as any).__SITE_KIT_DEBUG__\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\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 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 return 'Other'\n}\n\nfunction getOS(): string {\n if (typeof window === 'undefined') return 'unknown'\n const ua = navigator.userAgent\n if (ua.includes('Windows')) return 'Windows'\n if (ua.includes('Mac')) 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 return 'Other'\n}\n\n// ============================================\n// SignalCore Component (childless)\n// ============================================\n\nexport function SignalCore({\n enabled,\n realtime,\n experiments,\n behaviorTracking,\n externalVisitorId,\n externalSessionId,\n pageMetadataRef,\n onRegister,\n onState,\n}: SignalCoreProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n // Refs for SSE and tracking\n const eventSourceRef = useRef<EventSource | null>(null)\n const eventQueueRef = useRef<Partial<SignalEvent>[]>([])\n const flushTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const assignmentsRef = useRef<Map<string, ExperimentAssignment>>(new Map())\n\n // Behavioral tracking state\n const pageLoadTimeRef = useRef<number>(Date.now())\n const scrollDepthRef = useRef<number>(0)\n const clickCountRef = useRef<number>(0)\n\n const { apiUrl, apiKey } = getApiConfig()\n\n // Use external IDs from shared identity, fall back to the shared generators\n const resolvedVisitorId = externalVisitorId || getOrCreateVisitorId()\n const resolvedSessionId = externalSessionId || getOrCreateSessionId()\n\n // Mirror state up to the shell so context consumers re-render\n useEffect(() => {\n onState({ config, loading, error })\n }, [config, loading, error, onState])\n\n // ============================================\n // Experiment Assignment\n // ============================================\n\n const loadExperimentAssignment = useCallback(async (experimentId: string): Promise<ExperimentAssignment | null> => {\n // Check localStorage first\n const storageKey = `_signal_exp_${experimentId}`\n const stored = localStorage.getItem(storageKey)\n\n if (stored) {\n try {\n const assignment = JSON.parse(stored) as ExperimentAssignment\n if (assignment.expires > Date.now()) {\n assignmentsRef.current.set(experimentId, assignment)\n return assignment\n }\n } catch {\n // Invalid stored data, continue to fetch\n }\n }\n\n // Fetch from API — idempotent read, so the transport's default retries apply.\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/experiment/${experimentId}`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) return null\n\n const assignment = await response.json() as ExperimentAssignment\n\n // Store assignment\n localStorage.setItem(storageKey, JSON.stringify(assignment))\n assignmentsRef.current.set(experimentId, assignment)\n\n return assignment\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment assignment error:', err)\n return null\n }\n }, [apiUrl, apiKey])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n return assignmentsRef.current.get(experimentId) || null\n }, [])\n\n // ============================================\n // Config Fetching\n // ============================================\n\n const fetchConfig = useCallback(async () => {\n if (!apiKey || !enabled) {\n setLoading(false)\n return\n }\n\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/signal/config`,\n {\n headers: {\n 'x-visitor-id': resolvedVisitorId,\n },\n },\n { apiKey },\n )\n\n if (!response.ok) {\n throw new Error(`Failed to fetch Signal config: ${response.statusText}`)\n }\n\n const data = await response.json()\n setConfig(data.config)\n setError(null)\n\n // Load experiment assignments\n if (experiments && data.config?.experiments) {\n for (const exp of data.config.experiments) {\n if (exp.status === 'running') {\n await loadExperimentAssignment(exp.id)\n }\n }\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Config fetch error:', err)\n setError(err as Error)\n } finally {\n setLoading(false)\n }\n }, [apiUrl, apiKey, enabled, experiments, resolvedVisitorId, loadExperimentAssignment])\n\n // ============================================\n // SSE Real-time Updates\n // ============================================\n\n const connectSSE = useCallback(() => {\n if (!apiKey || !enabled || !realtime) return\n\n // Close existing connection\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n eventSourceRef.current = null\n }\n\n // EventSource cannot send headers, so the credential rides in the URL —\n // which server/CDN access logs capture. Per the transport contract in\n // sonorFetch.ts, the raw API key NEVER goes in a URL: only the\n // short-lived minted site token may (bounded exposure, unforgeable HMAC).\n // Raw-key mode (2.x layouts, mint-failure fallback) skips the stream —\n // config still loads via POST, only live push is lost.\n void (async () => {\n const credential = await getFreshCredential(apiKey)\n if (!credential || !isSiteToken(credential)) {\n if (isDebug()) {\n console.warn('[Signal] Realtime stream disabled: requires site-token mode (raw keys never go in URLs)')\n }\n return\n }\n if (eventSourceRef.current) return\n\n const url = `${apiUrl}/api/public/signal/stream?token=${encodeURIComponent(credential)}`\n connectEventSource(url)\n })()\n\n function connectEventSource(url: string) {\n const eventSource = new EventSource(url)\n\n eventSource.addEventListener('config_update', (e) => {\n try {\n const { config: newConfig, version } = JSON.parse(e.data)\n setConfig(prev => {\n if (prev?.version !== version) {\n if (isDebug()) console.log('[Signal] Config updated to version:', version)\n return newConfig\n }\n return prev\n })\n } catch (err) {\n if (isDebug()) console.error('[Signal] SSE parse error:', err)\n }\n })\n\n eventSource.addEventListener('experiment_update', (e) => {\n try {\n const { experiment_id, action } = JSON.parse(e.data)\n if (action === 'started' || action === 'updated') {\n loadExperimentAssignment(experiment_id)\n } else if (action === 'stopped') {\n assignmentsRef.current.delete(experiment_id)\n }\n } catch (err) {\n if (isDebug()) console.error('[Signal] Experiment update error:', err)\n }\n })\n\n eventSource.onerror = () => {\n if (isDebug()) console.warn('[Signal] SSE connection error, reconnecting...')\n eventSource.close()\n if (eventSourceRef.current === eventSource) {\n eventSourceRef.current = null\n }\n // Reconnect after 5 seconds (re-mints the token if it expired)\n setTimeout(connectSSE, 5000)\n }\n\n eventSourceRef.current = eventSource\n }\n }, [apiUrl, apiKey, enabled, realtime, loadExperimentAssignment])\n\n // ============================================\n // Event Tracking\n // ============================================\n\n const flushEvents = useCallback(async () => {\n if (eventQueueRef.current.length === 0) return\n\n const events = [...eventQueueRef.current]\n eventQueueRef.current = []\n\n try {\n // retries: 0 — fire-and-forget tracking; a retried flush after a lost\n // response would double-count events. The transport still aborts a hung\n // request at its timeout (no net::ERR_TIMED_OUT).\n await sonorFetch(\n `${apiUrl}/api/public/signal/events`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n events,\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n // Re-queue failed events\n eventQueueRef.current = [...events, ...eventQueueRef.current]\n if (isDebug()) console.error('[Signal] Event flush error:', err)\n }\n }, [apiUrl, apiKey])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (!enabled || !apiKey) return\n\n // Enrich event with context\n const enrichedEvent: Partial<SignalEvent> = {\n ...event,\n page_url: window.location.href,\n page_path: window.location.pathname,\n referrer: document.referrer,\n device_type: getDeviceType(),\n browser: getBrowser(),\n os: getOS(),\n viewport_width: window.innerWidth,\n viewport_height: window.innerHeight,\n time_on_page: Date.now() - pageLoadTimeRef.current,\n scroll_depth: scrollDepthRef.current,\n click_count: clickCountRef.current,\n experiments: Array.from(assignmentsRef.current.values()).map(a => ({\n experiment_id: a.experiment_id,\n variant_key: a.variant_key,\n })),\n // Merge page metadata from Analytics if available\n page_metadata: pageMetadataRef?.current ?? undefined,\n timestamp: new Date().toISOString(),\n }\n\n eventQueueRef.current.push(enrichedEvent)\n\n // Debounce flush\n if (flushTimeoutRef.current) {\n clearTimeout(flushTimeoutRef.current)\n }\n flushTimeoutRef.current = setTimeout(flushEvents, 1000)\n }, [enabled, apiKey, flushEvents])\n\n // ============================================\n // Outcome Tracking\n // ============================================\n\n const trackOutcome = useCallback(async (outcome: SignalOutcome) => {\n if (!enabled || !apiKey) return\n\n try {\n // retries: 0 — fire-and-forget conversion signal; never double-fire on a\n // lost response. Still aborts a hung request at the transport timeout.\n await sonorFetch(\n `${apiUrl}/api/public/signal/outcome`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...outcome,\n visitor_id: resolvedVisitorId,\n session_id: resolvedSessionId,\n experiments: Array.from(assignmentsRef.current.keys()),\n page_url: window.location.href,\n timestamp: new Date().toISOString(),\n }),\n },\n { apiKey, retries: 0 },\n )\n } catch (err) {\n if (isDebug()) console.error('[Signal] Outcome tracking error:', err)\n }\n }, [apiUrl, apiKey, enabled])\n\n // ============================================\n // Behavioral Tracking\n // ============================================\n\n useEffect(() => {\n if (!behaviorTracking || typeof window === 'undefined') return\n\n // Track scroll depth\n const handleScroll = () => {\n const scrollTop = window.scrollY\n const docHeight = document.documentElement.scrollHeight - window.innerHeight\n const depth = docHeight > 0 ? Math.round((scrollTop / docHeight) * 100) : 0\n scrollDepthRef.current = Math.max(scrollDepthRef.current, depth)\n }\n\n // Track clicks\n const handleClick = () => {\n clickCountRef.current++\n }\n\n window.addEventListener('scroll', handleScroll, { passive: true })\n window.addEventListener('click', handleClick)\n\n // Flush on visibility change or page hide.\n // `pagehide` (not `beforeunload`): fires on iOS Safari, bfcache-safe.\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n flushEvents()\n }\n }\n\n document.addEventListener('visibilitychange', handleVisibilityChange)\n window.addEventListener('pagehide', flushEvents)\n\n return () => {\n window.removeEventListener('scroll', handleScroll)\n window.removeEventListener('click', handleClick)\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n window.removeEventListener('pagehide', flushEvents)\n }\n }, [behaviorTracking, flushEvents])\n\n // ============================================\n // Initialization + shell registration\n // ============================================\n\n useEffect(() => {\n fetchConfig()\n }, [fetchConfig])\n\n useEffect(() => {\n if (config && realtime) {\n connectSSE()\n }\n\n return () => {\n if (eventSourceRef.current) {\n eventSourceRef.current.close()\n }\n }\n }, [config, realtime, connectSSE])\n\n // Hand the imperative API to the shell; buffered calls drain on register.\n useEffect(() => {\n onRegister({\n trackEvent,\n trackOutcome: (outcome: SignalOutcome) => { void trackOutcome(outcome) },\n getExperiment,\n refreshConfig: fetchConfig,\n })\n return () => onRegister(null)\n }, [onRegister, trackEvent, trackOutcome, getExperiment, fetchConfig])\n\n return null\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { SitemapSync } from './chunk-XKBADVXN.mjs';
|
|
2
|
+
import './chunk-QJU6HBSK.mjs';
|
|
3
|
+
import './chunk-XWBQLPTZ.mjs';
|
|
4
|
+
import './chunk-FSSVIYQ7.mjs';
|
|
5
|
+
import './chunk-EFMPOC6L.mjs';
|
|
6
|
+
import './chunk-BEXTDHO4.mjs';
|
|
7
|
+
//# sourceMappingURL=SitemapSync-2JJOGL7D.mjs.map
|
|
8
|
+
//# sourceMappingURL=SitemapSync-2JJOGL7D.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"SitemapSync-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SitemapSync-2JJOGL7D.mjs"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkCLD3IE6D_js = require('./chunk-CLD3IE6D.js');
|
|
4
|
+
require('./chunk-JEOKDUPQ.js');
|
|
5
|
+
require('./chunk-ZJNIM4GQ.js');
|
|
6
|
+
require('./chunk-NK6K4VHD.js');
|
|
7
|
+
require('./chunk-4JVFWTER.js');
|
|
8
|
+
require('./chunk-SNAQBZPT.js');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Object.defineProperty(exports, "SitemapSync", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkCLD3IE6D_js.SitemapSync; }
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=SitemapSync-S54TSZLM.js.map
|
|
17
|
+
//# sourceMappingURL=SitemapSync-S54TSZLM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"SitemapSync-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SitemapSync-S54TSZLM.js"}
|
package/dist/analytics/index.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var chunkEDZWNCSE_js = require('../chunk-EDZWNCSE.js');
|
|
5
|
-
var
|
|
5
|
+
var chunkYHGMM2XF_js = require('../chunk-YHGMM2XF.js');
|
|
6
6
|
var chunkHMFFAUCD_js = require('../chunk-HMFFAUCD.js');
|
|
7
7
|
require('../chunk-RC4WWQXR.js');
|
|
8
8
|
require('../chunk-VJMPIRSD.js');
|
|
9
|
-
require('../chunk-
|
|
10
|
-
require('../chunk-
|
|
11
|
-
require('../chunk-
|
|
9
|
+
require('../chunk-ZJNIM4GQ.js');
|
|
10
|
+
require('../chunk-NK6K4VHD.js');
|
|
11
|
+
require('../chunk-4JVFWTER.js');
|
|
12
12
|
require('../chunk-SNAQBZPT.js');
|
|
13
13
|
|
|
14
14
|
|
|
@@ -23,23 +23,23 @@ Object.defineProperty(exports, "useContactTracking", {
|
|
|
23
23
|
});
|
|
24
24
|
Object.defineProperty(exports, "AnalyticsProvider", {
|
|
25
25
|
enumerable: true,
|
|
26
|
-
get: function () { return
|
|
26
|
+
get: function () { return chunkYHGMM2XF_js.AnalyticsProvider; }
|
|
27
27
|
});
|
|
28
28
|
Object.defineProperty(exports, "WebVitals", {
|
|
29
29
|
enumerable: true,
|
|
30
|
-
get: function () { return
|
|
30
|
+
get: function () { return chunkYHGMM2XF_js.WebVitals; }
|
|
31
31
|
});
|
|
32
32
|
Object.defineProperty(exports, "useAnalytics", {
|
|
33
33
|
enumerable: true,
|
|
34
|
-
get: function () { return
|
|
34
|
+
get: function () { return chunkYHGMM2XF_js.useAnalytics; }
|
|
35
35
|
});
|
|
36
36
|
Object.defineProperty(exports, "useAnalyticsOptional", {
|
|
37
37
|
enumerable: true,
|
|
38
|
-
get: function () { return
|
|
38
|
+
get: function () { return chunkYHGMM2XF_js.useAnalyticsOptional; }
|
|
39
39
|
});
|
|
40
40
|
Object.defineProperty(exports, "useTrackEvent", {
|
|
41
41
|
enumerable: true,
|
|
42
|
-
get: function () { return
|
|
42
|
+
get: function () { return chunkYHGMM2XF_js.useTrackEvent; }
|
|
43
43
|
});
|
|
44
44
|
Object.defineProperty(exports, "trackConversion", {
|
|
45
45
|
enumerable: true,
|
package/dist/analytics/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
export { ContactTracking, useContactTracking } from '../chunk-26JXNW7B.mjs';
|
|
3
|
-
export { AnalyticsProvider, WebVitals, useAnalytics, useAnalyticsOptional, useTrackEvent } from '../chunk-
|
|
3
|
+
export { AnalyticsProvider, WebVitals, useAnalytics, useAnalyticsOptional, useTrackEvent } from '../chunk-6ZQFCZPW.mjs';
|
|
4
4
|
export { trackConversion, trackEvent } from '../chunk-3DPXOZAU.mjs';
|
|
5
5
|
import '../chunk-ZZQAGCSI.mjs';
|
|
6
6
|
import '../chunk-6EDVCUAG.mjs';
|
|
7
|
-
import '../chunk-
|
|
8
|
-
import '../chunk-
|
|
9
|
-
import '../chunk-
|
|
7
|
+
import '../chunk-XWBQLPTZ.mjs';
|
|
8
|
+
import '../chunk-FSSVIYQ7.mjs';
|
|
9
|
+
import '../chunk-EFMPOC6L.mjs';
|
|
10
10
|
import '../chunk-BEXTDHO4.mjs';
|
|
11
11
|
//# sourceMappingURL=index.mjs.map
|
|
12
12
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -10,7 +10,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
10
10
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
11
11
|
|
|
12
12
|
var InteractiveForm = React.lazy(
|
|
13
|
-
() => import('./ManagedForm-
|
|
13
|
+
() => import('./ManagedForm-YC6WLYVJ.js').then((m) => ({ default: m.ManagedForm }))
|
|
14
14
|
);
|
|
15
15
|
function FormEnhancer({
|
|
16
16
|
formId,
|
|
@@ -106,5 +106,5 @@ function EnterStyles() {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
exports.FormEnhancer = FormEnhancer;
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
110
|
-
//# sourceMappingURL=chunk-
|
|
109
|
+
//# sourceMappingURL=chunk-2MFLOK2I.js.map
|
|
110
|
+
//# sourceMappingURL=chunk-2MFLOK2I.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/forms/FormEnhancer.tsx"],"names":["lazy","useDeferredActivation","useState","jsxs","jsx","Suspense","React","useRef","useEffect"],"mappings":"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","file":"chunk-XOJYGBYF.js","sourcesContent":["'use client'\n\n/**\n * FormEnhancer — the only client code a managed form needs up front.\n *\n * Renders the server-rendered shell (<StaticForm>, passed as `children`) until\n * an idle/first-interaction gate fires, then lazy-imports the interactive form\n * and swaps it in. Everything expensive — validation, conditional logic,\n * spotlight/stage, celebration, momentum — lives behind that dynamic import,\n * so a page ships this boundary and nothing else in its initial chunk set.\n *\n * The shell is a REAL form the whole time (native action + signed token), so\n * the progression is:\n *\n * no JS at all -> shell, submits natively. Works.\n * JS, pre-idle -> shell, submits natively. Works.\n * JS, post-idle -> enhanced form, submits over JSON. Works, with delight.\n * chunk 404s -> shell stays. Works. (Never left blank.)\n *\n * That last line is the invariant to protect: the shell is only removed once\n * the enhancement has actually rendered. Do not \"hide the shell then load\" —\n * a CDN hiccup would leave a visitor staring at an empty box where the form\n * used to be.\n *\n * ── Entrance animation ──────────────────────────────────────────────────\n *\n * Above-the-fold forms upgrade while the visitor is looking at them, so the\n * swap must not pop. The wrapper carries `data-sk-form-mount=\"shell\"` and\n * flips to `\"enhanced\"`, and the enhanced form gets `data-sk-enter` for one\n * frame, so a site can style the transition entirely in CSS:\n *\n * [data-sk-form-mount] { transition: opacity .35s ease }\n * [data-sk-form-mount=\"shell\"] { opacity: .6 }\n *\n * Defaults ship as CSS variables rather than hard-coded values:\n *\n * --sk-form-enter-duration (default 320ms)\n * --sk-form-enter-easing (default cubic-bezier(.22,1,.36,1))\n * --sk-form-enter-distance (default 6px)\n *\n * `enter=\"none\"` opts out entirely; `enter=\"custom\"` emits the data\n * attributes but no site-kit styles, leaving the animation to the site.\n * Every default is collapsed by prefers-reduced-motion.\n */\n\nimport React, { lazy, Suspense, useEffect, useRef, useState } from 'react'\nimport { useDeferredActivation } from '../shared/defer'\nimport type { FormExperience, FormSubmission } from './types'\n\n/** The heavy half. Nothing else in this module may import it statically. */\nconst InteractiveForm = lazy(() =>\n import('./ManagedForm').then((m) => ({ default: m.ManagedForm })),\n)\n\nexport type FormEnterAnimation = 'fade' | 'none' | 'custom'\n\nexport interface FormEnhancerProps {\n formId: string\n /** Server-fetched raw config — hands the enhancement its fields instantly. */\n initialConfig?: Record<string, unknown> | null\n className?: string\n nativeReturnTo?: string\n experience?: FormExperience\n /** Pre-fill field values by slug. See ManagedForm.defaultValues. */\n defaultValues?: Record<string, unknown>\n onSuccess?: (submission: FormSubmission) => void\n onError?: (error: Error) => void\n /**\n * How the enhanced form arrives. 'fade' (default) crossfades and lifts it\n * into place; 'none' swaps instantly; 'custom' emits the data attributes\n * and no styles so the site owns the animation.\n */\n enter?: FormEnterAnimation\n /**\n * Set false to enhance immediately instead of waiting for idle. Only worth\n * it for a form that is the entire point of the page AND above the fold.\n */\n defer?: boolean\n /** The server-rendered <StaticForm>. Shown until the enhancement mounts. */\n children: React.ReactNode\n}\n\nexport function FormEnhancer({\n formId,\n initialConfig,\n className,\n nativeReturnTo,\n experience,\n defaultValues,\n onSuccess,\n onError,\n enter = 'fade',\n defer = true,\n children,\n}: FormEnhancerProps) {\n const ready = useDeferredActivation(defer)\n // Flipped only after the enhancement has actually committed to the DOM, so\n // the shell never disappears ahead of its replacement.\n const [enhanced, setEnhanced] = useState(false)\n\n return (\n <div\n data-sk-form-mount={enhanced ? 'enhanced' : 'shell'}\n data-sk-part=\"form-mount\"\n style={enter === 'fade' ? FADE_HOST : undefined}\n >\n {enter === 'fade' && <EnterStyles />}\n {ready ? (\n <Suspense fallback={children}>\n <Enhanced onMount={() => setEnhanced(true)} fallback={children}>\n <InteractiveForm\n formId={formId}\n initialConfig={initialConfig}\n className={className}\n nativeReturnTo={nativeReturnTo}\n experience={experience}\n defaultValues={defaultValues}\n onSuccess={onSuccess}\n onError={onError}\n />\n </Enhanced>\n </Suspense>\n ) : (\n children\n )}\n </div>\n )\n}\n\n/**\n * Reports the moment the enhancement is on screen, and keeps the shell\n * rendered if it throws. An error boundary is the difference between \"the\n * fancy version failed\" and \"there is no form on this page\".\n */\nclass Enhanced extends React.Component<\n { onMount: () => void; fallback: React.ReactNode; children: React.ReactNode },\n { failed: boolean }\n> {\n state = { failed: false }\n\n static getDerivedStateFromError() {\n return { failed: true }\n }\n\n componentDidCatch(err: unknown) {\n console.error('[Forms] Enhancement failed; keeping the native form:', err)\n }\n\n componentDidMount() {\n if (!this.state.failed) this.props.onMount()\n }\n\n render() {\n if (this.state.failed) return this.props.fallback\n return <FrameTag>{this.props.children}</FrameTag>\n }\n}\n\n/** Adds data-sk-enter for one frame so a CSS transition has something to run. */\nfunction FrameTag({ children }: { children: React.ReactNode }) {\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n const el = ref.current\n if (!el) return\n el.setAttribute('data-sk-enter', '')\n const id = requestAnimationFrame(() => el.removeAttribute('data-sk-enter'))\n return () => cancelAnimationFrame(id)\n }, [])\n return (\n <div ref={ref} style={{ display: 'contents' }}>\n {children}\n </div>\n )\n}\n\nconst FADE_HOST: React.CSSProperties = {\n transition:\n 'opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))',\n}\n\n/**\n * Scoped to [data-sk-part=\"form-mount\"] so it can never touch a site's own\n * markup. Emitted once per form; identical text dedupes in every browser's\n * style cache and gzips to nothing.\n */\nfunction EnterStyles() {\n return (\n <style\n // biome-ignore lint/security/noDangerouslySetInnerHtml: static string, no interpolation\n dangerouslySetInnerHTML={{\n __html: `\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:.55}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"enhanced\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}\n[data-sk-part=\"form-mount\"] [data-sk-enter] *{transition:none!important}\n@media (prefers-reduced-motion: reduce){\n[data-sk-part=\"form-mount\"]{transition:none!important}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:1;transform:none}\n}`,\n }}\n />\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/forms/FormEnhancer.tsx"],"names":["lazy","useDeferredActivation","useState","jsxs","jsx","Suspense","React","useRef","useEffect"],"mappings":"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","file":"chunk-2MFLOK2I.js","sourcesContent":["'use client'\n\n/**\n * FormEnhancer — the only client code a managed form needs up front.\n *\n * Renders the server-rendered shell (<StaticForm>, passed as `children`) until\n * an idle/first-interaction gate fires, then lazy-imports the interactive form\n * and swaps it in. Everything expensive — validation, conditional logic,\n * spotlight/stage, celebration, momentum — lives behind that dynamic import,\n * so a page ships this boundary and nothing else in its initial chunk set.\n *\n * The shell is a REAL form the whole time (native action + signed token), so\n * the progression is:\n *\n * no JS at all -> shell, submits natively. Works.\n * JS, pre-idle -> shell, submits natively. Works.\n * JS, post-idle -> enhanced form, submits over JSON. Works, with delight.\n * chunk 404s -> shell stays. Works. (Never left blank.)\n *\n * That last line is the invariant to protect: the shell is only removed once\n * the enhancement has actually rendered. Do not \"hide the shell then load\" —\n * a CDN hiccup would leave a visitor staring at an empty box where the form\n * used to be.\n *\n * ── Entrance animation ──────────────────────────────────────────────────\n *\n * Above-the-fold forms upgrade while the visitor is looking at them, so the\n * swap must not pop. The wrapper carries `data-sk-form-mount=\"shell\"` and\n * flips to `\"enhanced\"`, and the enhanced form gets `data-sk-enter` for one\n * frame, so a site can style the transition entirely in CSS:\n *\n * [data-sk-form-mount] { transition: opacity .35s ease }\n * [data-sk-form-mount=\"shell\"] { opacity: .6 }\n *\n * Defaults ship as CSS variables rather than hard-coded values:\n *\n * --sk-form-enter-duration (default 320ms)\n * --sk-form-enter-easing (default cubic-bezier(.22,1,.36,1))\n * --sk-form-enter-distance (default 6px)\n *\n * `enter=\"none\"` opts out entirely; `enter=\"custom\"` emits the data\n * attributes but no site-kit styles, leaving the animation to the site.\n * Every default is collapsed by prefers-reduced-motion.\n */\n\nimport React, { lazy, Suspense, useEffect, useRef, useState } from 'react'\nimport { useDeferredActivation } from '../shared/defer'\nimport type { FormExperience, FormSubmission } from './types'\n\n/** The heavy half. Nothing else in this module may import it statically. */\nconst InteractiveForm = lazy(() =>\n import('./ManagedForm').then((m) => ({ default: m.ManagedForm })),\n)\n\nexport type FormEnterAnimation = 'fade' | 'none' | 'custom'\n\nexport interface FormEnhancerProps {\n formId: string\n /** Server-fetched raw config — hands the enhancement its fields instantly. */\n initialConfig?: Record<string, unknown> | null\n className?: string\n nativeReturnTo?: string\n experience?: FormExperience\n /** Pre-fill field values by slug. See ManagedForm.defaultValues. */\n defaultValues?: Record<string, unknown>\n onSuccess?: (submission: FormSubmission) => void\n onError?: (error: Error) => void\n /**\n * How the enhanced form arrives. 'fade' (default) crossfades and lifts it\n * into place; 'none' swaps instantly; 'custom' emits the data attributes\n * and no styles so the site owns the animation.\n */\n enter?: FormEnterAnimation\n /**\n * Set false to enhance immediately instead of waiting for idle. Only worth\n * it for a form that is the entire point of the page AND above the fold.\n */\n defer?: boolean\n /** The server-rendered <StaticForm>. Shown until the enhancement mounts. */\n children: React.ReactNode\n}\n\nexport function FormEnhancer({\n formId,\n initialConfig,\n className,\n nativeReturnTo,\n experience,\n defaultValues,\n onSuccess,\n onError,\n enter = 'fade',\n defer = true,\n children,\n}: FormEnhancerProps) {\n const ready = useDeferredActivation(defer)\n // Flipped only after the enhancement has actually committed to the DOM, so\n // the shell never disappears ahead of its replacement.\n const [enhanced, setEnhanced] = useState(false)\n\n return (\n <div\n data-sk-form-mount={enhanced ? 'enhanced' : 'shell'}\n data-sk-part=\"form-mount\"\n style={enter === 'fade' ? FADE_HOST : undefined}\n >\n {enter === 'fade' && <EnterStyles />}\n {ready ? (\n <Suspense fallback={children}>\n <Enhanced onMount={() => setEnhanced(true)} fallback={children}>\n <InteractiveForm\n formId={formId}\n initialConfig={initialConfig}\n className={className}\n nativeReturnTo={nativeReturnTo}\n experience={experience}\n defaultValues={defaultValues}\n onSuccess={onSuccess}\n onError={onError}\n />\n </Enhanced>\n </Suspense>\n ) : (\n children\n )}\n </div>\n )\n}\n\n/**\n * Reports the moment the enhancement is on screen, and keeps the shell\n * rendered if it throws. An error boundary is the difference between \"the\n * fancy version failed\" and \"there is no form on this page\".\n */\nclass Enhanced extends React.Component<\n { onMount: () => void; fallback: React.ReactNode; children: React.ReactNode },\n { failed: boolean }\n> {\n state = { failed: false }\n\n static getDerivedStateFromError() {\n return { failed: true }\n }\n\n componentDidCatch(err: unknown) {\n console.error('[Forms] Enhancement failed; keeping the native form:', err)\n }\n\n componentDidMount() {\n if (!this.state.failed) this.props.onMount()\n }\n\n render() {\n if (this.state.failed) return this.props.fallback\n return <FrameTag>{this.props.children}</FrameTag>\n }\n}\n\n/** Adds data-sk-enter for one frame so a CSS transition has something to run. */\nfunction FrameTag({ children }: { children: React.ReactNode }) {\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n const el = ref.current\n if (!el) return\n el.setAttribute('data-sk-enter', '')\n const id = requestAnimationFrame(() => el.removeAttribute('data-sk-enter'))\n return () => cancelAnimationFrame(id)\n }, [])\n return (\n <div ref={ref} style={{ display: 'contents' }}>\n {children}\n </div>\n )\n}\n\nconst FADE_HOST: React.CSSProperties = {\n transition:\n 'opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))',\n}\n\n/**\n * Scoped to [data-sk-part=\"form-mount\"] so it can never touch a site's own\n * markup. Emitted once per form; identical text dedupes in every browser's\n * style cache and gzips to nothing.\n */\nfunction EnterStyles() {\n return (\n <style\n // biome-ignore lint/security/noDangerouslySetInnerHtml: static string, no interpolation\n dangerouslySetInnerHTML={{\n __html: `\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:.55}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"enhanced\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}\n[data-sk-part=\"form-mount\"] [data-sk-enter] *{transition:none!important}\n@media (prefers-reduced-motion: reduce){\n[data-sk-part=\"form-mount\"]{transition:none!important}\n[data-sk-part=\"form-mount\"][data-sk-form-mount=\"shell\"]{opacity:1}\n[data-sk-part=\"form-mount\"] [data-sk-enter]{opacity:1;transform:none}\n}`,\n }}\n />\n )\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { HoneypotField, NativeFallbackFields, nativeFormProps } from './chunk-
|
|
1
|
+
import { HoneypotField, NativeFallbackFields, nativeFormProps } from './chunk-UBSZ466T.mjs';
|
|
2
2
|
import { FormField } from './chunk-LB7LHVWI.mjs';
|
|
3
|
-
import { normalizeFormConfig } from './chunk-
|
|
3
|
+
import { normalizeFormConfig } from './chunk-E3F6OOVQ.mjs';
|
|
4
4
|
import { DEFAULT_HONEYPOT_FIELD } from './chunk-TMVKRQGJ.mjs';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -40,5 +40,5 @@ function StaticForm({ config: raw, className, nativeReturnTo }) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export { StaticForm };
|
|
43
|
-
//# sourceMappingURL=chunk-
|
|
44
|
-
//# sourceMappingURL=chunk-
|
|
43
|
+
//# sourceMappingURL=chunk-2MLIU6OJ.mjs.map
|
|
44
|
+
//# sourceMappingURL=chunk-2MLIU6OJ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/forms/StaticForm.tsx"],"names":[],"mappings":";;;;;;AA6DA,SAAS,oBAAoB,MAAA,EAA2B;AACtD,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,MAAA,IAAU,EAAC;AAC9B,EAAA,IAAI,CAAC,MAAA,CAAO,aAAA,EAAe,OAAO,GAAA;AAGlC,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAA,EAAG,EAAA;AACvC,EAAA,OAAO,GAAA,CAAI,OAAO,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,OAAA,KAAY,WAAW,CAAA;AAClE;AAEO,SAAS,WAAW,EAAE,MAAA,EAAQ,GAAA,EAAK,SAAA,EAAW,gBAAe,EAAoB;AACtF,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,MAAM,MAAA,GAAS,oBAAoB,GAAU,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,oBAAoB,MAAM,CAAA;AACzC,EAAA,MAAM,iBAAA,GAAoB,OAAO,cAAA,IAAkB,sBAAA;AAEnD,EAAA,uBACE,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MAGC,eAAA,EAAc,MAAA;AAAA,MACd,eAAA,EAAc,OAAA;AAAA,MACd,SAAA,EAAW,CAAA,QAAA,EAAW,SAAA,IAAa,EAAE,CAAA,CAAA;AAAA,MACpC,GAAG,gBAAgB,MAAM,CAAA;AAAA,MAE1B,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eAAA,EACb,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,iBAAA,EACZ,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,qBACX,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YAEC,SAAA,EAAW,CAAA,+CAAA,EAAkD,KAAA,CAAM,KAAA,IAAS,MAAM,CAAA,CAAA;AAAA,YAGlF,8BAAC,SAAA,EAAA,EAAU,KAAA,EAAc,KAAA,EAAO,KAAA,CAAM,iBAAiB,EAAA,EAAI;AAAA,WAAA;AAAA,UAJtD,KAAA,CAAM,MAAM,KAAA,CAAM;AAAA,SAM1B,GACH,CAAA,EACF,CAAA;AAAA,4BAEC,KAAA,EAAA,EAAI,SAAA,EAAU,oBAAmB,KAAA,EAAO,EAAE,gBAAgB,UAAA,EAAW,EACpE,QAAA,kBAAA,GAAA,CAAC,QAAA,EAAA,EAAO,MAAK,QAAA,EAAS,SAAA,EAAU,qCAC7B,QAAA,EAAA,MAAA,CAAO,kBAAA,IAAsB,UAChC,CAAA,EACF,CAAA;AAAA,QAIC,MAAA,CAAO,gBAAA,oBAAoB,GAAA,CAAC,aAAA,EAAA,EAAc,MAAM,iBAAA,EAAmB,CAAA;AAAA,wBAGpE,GAAA,CAAC,oBAAA,EAAA,EAAqB,MAAA,EAAgB,QAAA,EAAU,cAAA,EAAgB;AAAA;AAAA;AAAA,GAClE;AAEJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/forms/StaticForm.tsx"],"names":[],"mappings":";;;;;;AA6DA,SAAS,oBAAoB,MAAA,EAA2B;AACtD,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,MAAA,IAAU,EAAC;AAC9B,EAAA,IAAI,CAAC,MAAA,CAAO,aAAA,EAAe,OAAO,GAAA;AAGlC,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAA,EAAG,EAAA;AACvC,EAAA,OAAO,GAAA,CAAI,OAAO,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,OAAA,KAAY,WAAW,CAAA;AAClE;AAEO,SAAS,WAAW,EAAE,MAAA,EAAQ,GAAA,EAAK,SAAA,EAAW,gBAAe,EAAoB;AACtF,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,MAAM,MAAA,GAAS,oBAAoB,GAAU,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,oBAAoB,MAAM,CAAA;AACzC,EAAA,MAAM,iBAAA,GAAoB,OAAO,cAAA,IAAkB,sBAAA;AAEnD,EAAA,uBACE,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MAGC,eAAA,EAAc,MAAA;AAAA,MACd,eAAA,EAAc,OAAA;AAAA,MACd,SAAA,EAAW,CAAA,QAAA,EAAW,SAAA,IAAa,EAAE,CAAA,CAAA;AAAA,MACpC,GAAG,gBAAgB,MAAM,CAAA;AAAA,MAE1B,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eAAA,EACb,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,iBAAA,EACZ,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,qBACX,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YAEC,SAAA,EAAW,CAAA,+CAAA,EAAkD,KAAA,CAAM,KAAA,IAAS,MAAM,CAAA,CAAA;AAAA,YAGlF,8BAAC,SAAA,EAAA,EAAU,KAAA,EAAc,KAAA,EAAO,KAAA,CAAM,iBAAiB,EAAA,EAAI;AAAA,WAAA;AAAA,UAJtD,KAAA,CAAM,MAAM,KAAA,CAAM;AAAA,SAM1B,GACH,CAAA,EACF,CAAA;AAAA,4BAEC,KAAA,EAAA,EAAI,SAAA,EAAU,oBAAmB,KAAA,EAAO,EAAE,gBAAgB,UAAA,EAAW,EACpE,QAAA,kBAAA,GAAA,CAAC,QAAA,EAAA,EAAO,MAAK,QAAA,EAAS,SAAA,EAAU,qCAC7B,QAAA,EAAA,MAAA,CAAO,kBAAA,IAAsB,UAChC,CAAA,EACF,CAAA;AAAA,QAIC,MAAA,CAAO,gBAAA,oBAAoB,GAAA,CAAC,aAAA,EAAA,EAAc,MAAM,iBAAA,EAAmB,CAAA;AAAA,wBAGpE,GAAA,CAAC,oBAAA,EAAA,EAAqB,MAAA,EAAgB,QAAA,EAAU,cAAA,EAAgB;AAAA;AAAA;AAAA,GAClE;AAEJ","file":"chunk-2MLIU6OJ.mjs","sourcesContent":["/**\n * StaticForm — a complete, submittable managed form with ZERO client JavaScript.\n *\n * No `'use client'`. This renders in a Server Component, and what it emits is\n * a real `<form>`: every field, the honeypot, the signed native token, and a\n * submit button. With JavaScript disabled, off, or still downloading, the\n * browser performs an ordinary form-encoded POST to\n * `/api/public/forms/submit-native`, sonor-api runs the honeypot +\n * render-timestamp + quarantine stack, and the lead lands. 4.0.1 built that\n * endpoint; this is what finally puts it under every form by default.\n *\n * ── Why this exists ─────────────────────────────────────────────────────\n *\n * ManagedForm was a client component for historical reasons that no longer\n * hold: it used to fetch its own config (getFormConfig removed that) and it\n * could only submit via JSON (the native endpoint removed that). Nobody moved\n * the boundary afterward, so every site that rendered a form paid for the\n * whole forms runtime — validation, spotlight, celebration, momentum — as an\n * INITIAL script, on the LCP-critical path.\n *\n * Measured on upforge.io's homepage: 48 KB of form code in the initial chunk\n * set cost 6 Lighthouse points (88 -> 82, LCP 3.8s -> 4.7s). Deferring the\n * client component recovered the score but deleted the form from the HTML,\n * taking the no-JS floor and crawlable fields with it. Neither half was\n * acceptable; a server-rendered form is what makes both true at once.\n *\n * Pair it with <FormEnhancer> to upgrade this markup at idle. Alone, it is\n * still a working form — that is the point. Never make this file `'use\n * client'`, and never import a hook into it.\n */\n\nimport React from 'react'\nimport { DEFAULT_HONEYPOT_FIELD } from './contract'\nimport { FormField } from './FormField'\nimport { HoneypotField } from './HoneypotField'\nimport { nativeFormProps, NativeFallbackFields } from './native-fallback'\nimport { normalizeFormConfig } from './normalize-config'\nimport type { ManagedFormConfig } from './types'\n\nexport interface StaticFormProps {\n /**\n * RAW /api/public/forms/config payload from `getFormConfig`, or an\n * already-normalized config. Normalized here through the SAME function the\n * client fetch uses, so the shell and the enhancement cannot disagree about\n * field order, step count, or success copy.\n */\n config: Record<string, unknown> | ManagedFormConfig | null | undefined\n className?: string\n /**\n * Absolute URL the no-JS 303 should return to (usually the page hosting the\n * form). Without it the API falls back to the Referer origin — right site,\n * wrong page.\n */\n nativeReturnTo?: string\n}\n\n/**\n * Fields the static shell can render meaningfully. Conditional logic is a\n * runtime concern (it depends on values the visitor has not entered yet), so\n * a conditional field renders here and the enhancement takes over hiding it.\n */\nfunction visibleStaticFields(config: ManagedFormConfig) {\n const all = config.fields || []\n if (!config.is_multi_step) return all\n // Multi-step is JS-only navigation and is excluded from native POST, so the\n // shell shows step one as a preview of what the form asks for.\n const firstStepId = config.steps?.[0]?.id\n return all.filter((f) => !f.step_id || f.step_id === firstStepId)\n}\n\nexport function StaticForm({ config: raw, className, nativeReturnTo }: StaticFormProps) {\n if (!raw) return null\n const config = normalizeFormConfig(raw as any)\n const fields = visibleStaticFields(config)\n const honeypotFieldName = config.honeypot_field || DEFAULT_HONEYPOT_FIELD\n\n return (\n <form\n // Matches FormClient's classic branch attribute-for-attribute so the\n // enhancement swap is invisible. Change one, change the other.\n data-sk-state=\"idle\"\n data-sk-mount=\"shell\"\n className={`sk-form ${className || ''}`}\n {...nativeFormProps(config)}\n >\n <div className=\"sk-form__step\">\n <div className=\"sk-form__fields\">\n {fields.map((field) => (\n <div\n key={field.id || field.slug}\n className={`sk-form__field-wrapper sk-form__field-wrapper--${field.width || 'full'}`}\n >\n {/* No onChange — FormField renders native uncontrolled controls. */}\n <FormField field={field} value={field.default_value ?? ''} />\n </div>\n ))}\n </div>\n </div>\n\n <div className=\"sk-form__actions\" style={{ justifyContent: 'flex-end' }}>\n <button type=\"submit\" className=\"sk-form__btn sk-form__btn--submit\">\n {config.submit_button_text || 'Submit'}\n </button>\n </div>\n\n {/* Same trap the hydrated form uses; no state needed because the value\n is read and stripped server-side. */}\n {config.honeypot_enabled && <HoneypotField name={honeypotFieldName} />}\n\n {/* _sk_token auth + _sk_return destination for the native POST. */}\n <NativeFallbackFields config={config} returnTo={nativeReturnTo} />\n </form>\n )\n}\n"]}
|