@sonordev/site-kit 3.2.0 → 3.2.1
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-A3STXJ65.js +29 -0
- package/dist/{AnalyticsProvider-WK2Z6AIN.js.map → AnalyticsProvider-A3STXJ65.js.map} +1 -1
- package/dist/AnalyticsProvider-LEXGFM2K.mjs +8 -0
- package/dist/{AnalyticsProvider-CD635CHQ.mjs.map → AnalyticsProvider-LEXGFM2K.mjs.map} +1 -1
- package/dist/ChatWidget-4QR2ZDRE.mjs +8 -0
- package/dist/{ChatWidget-UAAWDBNS.mjs.map → ChatWidget-4QR2ZDRE.mjs.map} +1 -1
- package/dist/ChatWidget-U3K2VHVN.js +17 -0
- package/dist/{ChatWidget-AIOOZY6H.js.map → ChatWidget-U3K2VHVN.js.map} +1 -1
- package/dist/EngageWidget-2FMKYJJT.mjs +7 -0
- package/dist/{EngageWidget-EZ5T6H3K.mjs.map → EngageWidget-2FMKYJJT.mjs.map} +1 -1
- package/dist/EngageWidget-TOGMQ2G6.js +16 -0
- package/dist/{EngageWidget-RWVWW56C.js.map → EngageWidget-TOGMQ2G6.js.map} +1 -1
- package/dist/{SignalCore-4B4RNYLV.mjs → SignalCore-5QJG3IJB.mjs} +4 -4
- package/dist/{SignalCore-4B4RNYLV.mjs.map → SignalCore-5QJG3IJB.mjs.map} +1 -1
- package/dist/{SignalCore-AECW2JFP.js → SignalCore-JB3VHHTG.js} +8 -8
- package/dist/{SignalCore-AECW2JFP.js.map → SignalCore-JB3VHHTG.js.map} +1 -1
- package/dist/SitemapSync-BJWSTERT.js +15 -0
- package/dist/{SitemapSync-AICU4SSV.js.map → SitemapSync-BJWSTERT.js.map} +1 -1
- package/dist/SitemapSync-T6PIDW64.mjs +6 -0
- package/dist/{SitemapSync-CIZCAZXK.mjs.map → SitemapSync-T6PIDW64.mjs.map} +1 -1
- package/dist/analytics/index.js +11 -11
- package/dist/analytics/index.mjs +4 -4
- package/dist/brand.css +13 -3
- package/dist/{chunk-GCDVKOSM.js → chunk-52VXHSVT.js} +3 -3
- package/dist/{chunk-GCDVKOSM.js.map → chunk-52VXHSVT.js.map} +1 -1
- package/dist/{chunk-I2GTT2DG.js → chunk-5RX4CUR2.js} +19 -21
- package/dist/chunk-5RX4CUR2.js.map +1 -0
- package/dist/{chunk-OTY7EWET.mjs → chunk-5ZNKNNJ4.mjs} +4 -4
- package/dist/{chunk-OTY7EWET.mjs.map → chunk-5ZNKNNJ4.mjs.map} +1 -1
- package/dist/{chunk-RFIWVH3D.mjs → chunk-7OK6BI3A.mjs} +3 -3
- package/dist/{chunk-RFIWVH3D.mjs.map → chunk-7OK6BI3A.mjs.map} +1 -1
- package/dist/{chunk-N2HR2E4Z.mjs → chunk-7R7SGJG3.mjs} +15 -21
- package/dist/chunk-7R7SGJG3.mjs.map +1 -0
- package/dist/{chunk-FMZOZQBV.mjs → chunk-AMBTOIYM.mjs} +19 -21
- package/dist/chunk-AMBTOIYM.mjs.map +1 -0
- package/dist/{chunk-5OWZUNNE.js → chunk-B5YNHSRA.js} +7 -7
- package/dist/{chunk-5OWZUNNE.js.map → chunk-B5YNHSRA.js.map} +1 -1
- package/dist/{chunk-S3YQGTBF.js → chunk-BNBCSHTK.js} +12 -12
- package/dist/{chunk-S3YQGTBF.js.map → chunk-BNBCSHTK.js.map} +1 -1
- package/dist/{chunk-45QHDA7Q.mjs → chunk-BUCF5FUY.mjs} +3 -3
- package/dist/{chunk-45QHDA7Q.mjs.map → chunk-BUCF5FUY.mjs.map} +1 -1
- package/dist/{chunk-TE3W5REY.js → chunk-DCZUMCEC.js} +14 -14
- package/dist/{chunk-TE3W5REY.js.map → chunk-DCZUMCEC.js.map} +1 -1
- package/dist/{chunk-6HPNFWSC.mjs → chunk-DYCEEU67.mjs} +3 -3
- package/dist/{chunk-6HPNFWSC.mjs.map → chunk-DYCEEU67.mjs.map} +1 -1
- package/dist/{chunk-NDHFU4HV.mjs → chunk-E4TWVVSW.mjs} +4 -4
- package/dist/{chunk-NDHFU4HV.mjs.map → chunk-E4TWVVSW.mjs.map} +1 -1
- package/dist/{chunk-NAVDN4AE.js → chunk-E7M5MDGC.js} +29 -40
- package/dist/chunk-E7M5MDGC.js.map +1 -0
- package/dist/{chunk-2WYEJOGA.mjs → chunk-GMO6POZ2.mjs} +3 -3
- package/dist/{chunk-2WYEJOGA.mjs.map → chunk-GMO6POZ2.mjs.map} +1 -1
- package/dist/{chunk-EAASMIWX.js → chunk-GMSPDTEV.js} +15 -9
- package/dist/chunk-GMSPDTEV.js.map +1 -0
- package/dist/{chunk-T2DEEKVQ.mjs → chunk-IR5UC236.mjs} +3 -3
- package/dist/{chunk-T2DEEKVQ.mjs.map → chunk-IR5UC236.mjs.map} +1 -1
- package/dist/{chunk-HAZN43I6.js → chunk-LF3ID6WN.js} +20 -26
- package/dist/chunk-LF3ID6WN.js.map +1 -0
- package/dist/{chunk-57QV6NIY.mjs → chunk-MKZHVSKL.mjs} +3 -3
- package/dist/{chunk-57QV6NIY.mjs.map → chunk-MKZHVSKL.mjs.map} +1 -1
- package/dist/{chunk-SLWTG2LJ.js → chunk-MX6DK246.js} +13 -13
- package/dist/{chunk-SLWTG2LJ.js.map → chunk-MX6DK246.js.map} +1 -1
- package/dist/{chunk-R5A64DCX.js → chunk-MYAXI33P.js} +8 -8
- package/dist/{chunk-R5A64DCX.js.map → chunk-MYAXI33P.js.map} +1 -1
- package/dist/{chunk-4NTMIU6V.js → chunk-NDROQRDB.js} +6 -6
- package/dist/{chunk-4NTMIU6V.js.map → chunk-NDROQRDB.js.map} +1 -1
- package/dist/{chunk-4FBV5BJW.js → chunk-NJIHMZPC.js} +5 -5
- package/dist/{chunk-4FBV5BJW.js.map → chunk-NJIHMZPC.js.map} +1 -1
- package/dist/{chunk-DSRPKUQI.mjs → chunk-NQ2P7AB3.mjs} +28 -39
- package/dist/chunk-NQ2P7AB3.mjs.map +1 -0
- package/dist/chunk-QLM7RNQI.mjs +6 -0
- package/dist/{chunk-SN2O72UF.mjs.map → chunk-QLM7RNQI.mjs.map} +1 -1
- package/dist/{chunk-LZSCCJ4O.mjs → chunk-SBT4J733.mjs} +11 -5
- package/dist/chunk-SBT4J733.mjs.map +1 -0
- package/dist/{chunk-UT2CF4FC.js → chunk-SGPIGHMN.js} +4 -4
- package/dist/{chunk-UT2CF4FC.js.map → chunk-SGPIGHMN.js.map} +1 -1
- package/dist/{chunk-GN62H6EG.mjs → chunk-VTHCUHMK.mjs} +8 -8
- package/dist/{chunk-GN62H6EG.mjs.map → chunk-VTHCUHMK.mjs.map} +1 -1
- package/dist/chunk-WAAFJPNR.js +8 -0
- package/dist/{chunk-WRZQS7O4.js.map → chunk-WAAFJPNR.js.map} +1 -1
- package/dist/{chunk-EIWRPGOK.mjs → chunk-XHEXIYKY.mjs} +4 -4
- package/dist/{chunk-EIWRPGOK.mjs.map → chunk-XHEXIYKY.mjs.map} +1 -1
- package/dist/{chunk-TVCCZ7NR.js → chunk-XM67L4HL.js} +14 -14
- package/dist/{chunk-TVCCZ7NR.js.map → chunk-XM67L4HL.js.map} +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.mjs +1 -1
- package/dist/commerce/index.js +50 -50
- package/dist/commerce/index.mjs +5 -5
- package/dist/engage/index.js +8 -8
- package/dist/engage/index.mjs +5 -5
- package/dist/fleet/index.js +7 -7
- package/dist/fleet/index.mjs +3 -3
- package/dist/forms/index.js +18 -18
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +10 -10
- package/dist/forms/index.mjs.map +1 -1
- package/dist/forms/styles.css +4 -2
- package/dist/images/index.js +10 -10
- package/dist/images/index.mjs +3 -3
- package/dist/index.js +67 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -15
- package/dist/index.mjs.map +1 -1
- package/dist/layout/client.js +6 -6
- package/dist/layout/client.mjs +5 -5
- package/dist/layout/index.js +7 -7
- package/dist/layout/index.mjs +5 -5
- package/dist/maps/index.d.mts +4 -2
- package/dist/maps/index.d.ts +4 -2
- package/dist/maps/index.js +4 -4
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/index.mjs +2 -2
- package/dist/maps/index.mjs.map +1 -1
- package/dist/seo/client.js +4 -4
- package/dist/seo/client.mjs +3 -3
- package/dist/seo/index.js +4 -4
- package/dist/seo/index.mjs +3 -3
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sync/index.js +15 -13
- package/dist/sync/index.mjs +3 -1
- package/package.json +1 -1
- package/dist/AnalyticsProvider-CD635CHQ.mjs +0 -8
- package/dist/AnalyticsProvider-WK2Z6AIN.js +0 -29
- package/dist/ChatWidget-AIOOZY6H.js +0 -17
- package/dist/ChatWidget-UAAWDBNS.mjs +0 -8
- package/dist/EngageWidget-EZ5T6H3K.mjs +0 -7
- package/dist/EngageWidget-RWVWW56C.js +0 -16
- package/dist/SitemapSync-AICU4SSV.js +0 -15
- package/dist/SitemapSync-CIZCAZXK.mjs +0 -6
- package/dist/chunk-DSRPKUQI.mjs.map +0 -1
- package/dist/chunk-EAASMIWX.js.map +0 -1
- package/dist/chunk-FMZOZQBV.mjs.map +0 -1
- package/dist/chunk-HAZN43I6.js.map +0 -1
- package/dist/chunk-I2GTT2DG.js.map +0 -1
- package/dist/chunk-LZSCCJ4O.mjs.map +0 -1
- package/dist/chunk-N2HR2E4Z.mjs.map +0 -1
- package/dist/chunk-NAVDN4AE.js.map +0 -1
- package/dist/chunk-SN2O72UF.mjs +0 -6
- package/dist/chunk-WRZQS7O4.js +0 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useSignalExperiment, useSignalEvent } from './chunk-
|
|
2
|
+
import { useSignalExperiment, useSignalEvent } from './chunk-MKZHVSKL.mjs';
|
|
3
3
|
import React, { useEffect } from 'react';
|
|
4
4
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -71,5 +71,5 @@ function ExperimentConversion({
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
export { ExperimentConversion, SignalExperiment, useExperimentVariant };
|
|
74
|
-
//# sourceMappingURL=chunk-
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
74
|
+
//# sourceMappingURL=chunk-DYCEEU67.mjs.map
|
|
75
|
+
//# sourceMappingURL=chunk-DYCEEU67.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/signal/SignalExperiment.tsx"],"names":[],"mappings":";;;;AAgDO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA,GAAkB,IAAA;AAAA,EAClB;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,SAAA,EAAU,GAAI,oBAAoB,YAAY,CAAA;AAC3E,EAAA,MAAM,aAAa,cAAA,EAAe;AAGlC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,mBAAmB,OAAA,EAAS;AAC9B,MAAA,UAAA,CAAW;AAAA,QACT,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,aAAA,EAAe,YAAA;AAAA,UACf,WAAA,EAAa;AAAA;AACf,OACD,CAAA;AAAA,IACH;AAAA,EACF,GAAG,CAAC,YAAA,EAAc,OAAA,EAAS,eAAA,EAAiB,UAAU,CAAC,CAAA;AAGvD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAG,mBAAS,EAAE,OAAA,EAAS,WAAW,SAAA,EAAW,SAAA,EAAW,CAAA,EAAE,CAAA;AAAA,EACnE;AAGA,EAAA,MAAM,kBAAkB,OAAA,IAAW,SAAA;AACnC,EAAA,MAAM,OAAA,GAAU,SAAS,eAAe,CAAA;AAExC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,uCAAU,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EACpB;AAGA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uCAAU,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,QAAA,CAAS,OAAA,IAAW,IAAA,EAAK,CAAA;AACrC;AAYO,SAAS,qBAAqB,YAAA,EAAsB;AACzD,EAAA,OAAO,oBAAoB,YAAY,CAAA;AACzC;AAoBO,SAAS,oBAAA,CAAqB;AAAA,EACnC,YAAA;AAAA,EACA,WAAA,GAAc,OAAA;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,MAAM,aAAa,cAAA,EAAe;AAClC,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,mBAAA,CAAoB,YAAY,CAAA;AAEpD,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,UAAA,CAAW;AAAA,MACT,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY;AAAA,QACV,aAAA,EAAe,YAAA;AAAA,QACf,WAAA,EAAa,OAAA;AAAA,QACb,YAAA,EAAc,WAAA;AAAA,QACd;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAO,KAAA,CAAM,aAAa,QAAA,EAAU;AAAA,IAClC,OAAA,EAAS,CAAC,CAAA,KAAwB;AAChC,MAAA,iBAAA,EAAkB;AAElB,MAAA,IAAK,QAAA,CAAS,MAAsD,OAAA,EAAS;AAC3E,QAAC,QAAA,CAAS,KAAA,CAAsD,OAAA,CAAS,CAAC,CAAA;AAAA,MAC5E;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/signal/SignalExperiment.tsx"],"names":[],"mappings":";;;;AAgDO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA,GAAkB,IAAA;AAAA,EAClB;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,SAAA,EAAU,GAAI,oBAAoB,YAAY,CAAA;AAC3E,EAAA,MAAM,aAAa,cAAA,EAAe;AAGlC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,mBAAmB,OAAA,EAAS;AAC9B,MAAA,UAAA,CAAW;AAAA,QACT,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,aAAA,EAAe,YAAA;AAAA,UACf,WAAA,EAAa;AAAA;AACf,OACD,CAAA;AAAA,IACH;AAAA,EACF,GAAG,CAAC,YAAA,EAAc,OAAA,EAAS,eAAA,EAAiB,UAAU,CAAC,CAAA;AAGvD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAG,mBAAS,EAAE,OAAA,EAAS,WAAW,SAAA,EAAW,SAAA,EAAW,CAAA,EAAE,CAAA;AAAA,EACnE;AAGA,EAAA,MAAM,kBAAkB,OAAA,IAAW,SAAA;AACnC,EAAA,MAAM,OAAA,GAAU,SAAS,eAAe,CAAA;AAExC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,uCAAU,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EACpB;AAGA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uCAAU,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,QAAA,CAAS,OAAA,IAAW,IAAA,EAAK,CAAA;AACrC;AAYO,SAAS,qBAAqB,YAAA,EAAsB;AACzD,EAAA,OAAO,oBAAoB,YAAY,CAAA;AACzC;AAoBO,SAAS,oBAAA,CAAqB;AAAA,EACnC,YAAA;AAAA,EACA,WAAA,GAAc,OAAA;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,MAAM,aAAa,cAAA,EAAe;AAClC,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,mBAAA,CAAoB,YAAY,CAAA;AAEpD,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,UAAA,CAAW;AAAA,MACT,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY;AAAA,QACV,aAAA,EAAe,YAAA;AAAA,QACf,WAAA,EAAa,OAAA;AAAA,QACb,YAAA,EAAc,WAAA;AAAA,QACd;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAO,KAAA,CAAM,aAAa,QAAA,EAAU;AAAA,IAClC,OAAA,EAAS,CAAC,CAAA,KAAwB;AAChC,MAAA,iBAAA,EAAkB;AAElB,MAAA,IAAK,QAAA,CAAS,MAAsD,OAAA,EAAS;AAC3E,QAAC,QAAA,CAAS,KAAA,CAAsD,OAAA,CAAS,CAAC,CAAA;AAAA,MAC5E;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-DYCEEU67.mjs","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalExperiment\n * \n * A/B test component that renders different variants based on Signal assignment.\n * Uses Thompson Sampling (Bayesian bandit) for optimization.\n */\n\n'use client'\n\nimport React, { useMemo, useEffect } from 'react'\nimport { useSignalExperiment, useSignalEvent } from './SignalBridge'\n\ninterface SignalExperimentProps {\n /** Unique experiment ID */\n experimentId: string\n \n /** Variants to test - keys are variant names, values are React nodes */\n variants: Record<string, React.ReactNode>\n \n /** Fallback content if no assignment (defaults to 'control' variant) */\n fallback?: React.ReactNode\n \n /** Track impression automatically */\n trackImpression?: boolean\n \n /** Children function for more control */\n children?: (props: { variant: string; isControl: boolean }) => React.ReactNode\n}\n\n/**\n * Renders different content variants based on Signal's A/B assignment.\n * \n * @example\n * // Simple variant switching\n * <SignalExperiment experimentId=\"hero-cta\" variants={{\n * control: <Button>Get Started</Button>,\n * variant_a: <Button variant=\"primary\">Start Free Trial</Button>,\n * variant_b: <Button variant=\"secondary\">Book a Demo</Button>,\n * }} />\n * \n * @example\n * // With render prop for more control\n * <SignalExperiment experimentId=\"pricing-layout\">\n * {({ variant, isControl }) => (\n * <PricingSection layout={isControl ? 'cards' : 'table'} />\n * )}\n * </SignalExperiment>\n */\nexport function SignalExperiment({\n experimentId,\n variants,\n fallback,\n trackImpression = true,\n children,\n}: SignalExperimentProps) {\n const { assignment, variant, isControl } = useSignalExperiment(experimentId)\n const trackEvent = useSignalEvent()\n \n // Track impression when variant is rendered\n useEffect(() => {\n if (trackImpression && variant) {\n trackEvent({\n event_type: 'experiment',\n event_name: 'impression',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n },\n })\n }\n }, [experimentId, variant, trackImpression, trackEvent])\n \n // If using render prop\n if (children) {\n return <>{children({ variant: variant || 'control', isControl })}</>\n }\n \n // Determine what to render\n const selectedVariant = variant || 'control'\n const content = variants[selectedVariant]\n \n if (content !== undefined) {\n return <>{content}</>\n }\n \n // Fallback to provided fallback or control\n if (fallback) {\n return <>{fallback}</>\n }\n \n return <>{variants.control || null}</>\n}\n\n/**\n * Hook for conditional experiment logic\n * \n * @example\n * const { variant, isControl } = useExperimentVariant('pricing-test')\n * \n * return isControl \n * ? <OldPricing />\n * : <NewPricing showAnnual={variant === 'annual_first'} />\n */\nexport function useExperimentVariant(experimentId: string) {\n return useSignalExperiment(experimentId)\n}\n\n/**\n * Component for tracking experiment conversions\n * Wraps interactive elements to track when they convert\n * \n * @example\n * <SignalExperiment experimentId=\"signup-button\" variants={{\n * control: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button>Sign Up</Button>\n * </ExperimentConversion>\n * ),\n * variant_a: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button variant=\"large\">Join Now - It's Free!</Button>\n * </ExperimentConversion>\n * ),\n * }} />\n */\nexport function ExperimentConversion({\n experimentId,\n outcomeType = 'click',\n value,\n children,\n}: {\n experimentId: string\n outcomeType?: string\n value?: number\n children: React.ReactElement<{ onClick?: (e: React.MouseEvent) => void }>\n}) {\n const trackEvent = useSignalEvent()\n const { variant } = useSignalExperiment(experimentId)\n\n const handleInteraction = () => {\n trackEvent({\n event_type: 'experiment',\n event_name: 'conversion',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n outcome_type: outcomeType,\n value,\n },\n })\n }\n\n return React.cloneElement(children, {\n onClick: (e: React.MouseEvent) => {\n handleInteraction()\n // Call original onClick if exists\n if ((children.props as { onClick?: (e: React.MouseEvent) => void }).onClick) {\n (children.props as { onClick?: (e: React.MouseEvent) => void }).onClick!(e)\n }\n },\n })\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useDeferredActivation } from './chunk-ZVBLXXNJ.mjs';
|
|
3
3
|
import { sanitizeFleetVersion, buildFleetHeartbeatPayload } from './chunk-ZPLN537Q.mjs';
|
|
4
|
-
import { sonorFetch } from './chunk-
|
|
5
|
-
import { SITE_KIT_VERSION } from './chunk-
|
|
4
|
+
import { sonorFetch } from './chunk-SBT4J733.mjs';
|
|
5
|
+
import { SITE_KIT_VERSION } from './chunk-QLM7RNQI.mjs';
|
|
6
6
|
import { useRef, useEffect } from 'react';
|
|
7
7
|
|
|
8
8
|
// src/fleet/heartbeat.ts
|
|
@@ -93,5 +93,5 @@ function FleetHeartbeat({
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
export { FLEET_HEARTBEAT_PATH, FleetHeartbeat, detectNextVersion, sendFleetHeartbeat };
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
96
|
+
//# sourceMappingURL=chunk-E4TWVVSW.mjs.map
|
|
97
|
+
//# sourceMappingURL=chunk-E4TWVVSW.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/fleet/heartbeat.ts","../src/fleet/FleetHeartbeat.tsx"],"names":[],"mappings":"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","file":"chunk-NDHFU4HV.mjs","sourcesContent":["/**\n * @sonordev/site-kit/fleet — heartbeat sender (single source of truth for the POST)\n *\n * One place that turns fleet inputs into a validated payload and ships it to\n * `/api/public/fleet/heartbeat`. Used by BOTH the client component\n * (FleetHeartbeat) and any build-time caller, so the send path never forks.\n *\n * It routes through the canonical `sonorFetch` transport, which already stamps\n * the x-sitekit-version header, attaches x-api-key, and honors the auth\n * circuit breaker — a site on a stale/canceled key will not spam the API.\n */\n\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { SITE_KIT_VERSION } from '../shared/version'\nimport {\n buildFleetHeartbeatPayload,\n sanitizeFleetVersion,\n type FleetHeartbeatPayload,\n type FleetHeartbeatSource,\n type FleetModule,\n} from './contract'\n\n/** Canonical ingest path — resolved against the site's Sonor API origin. */\nexport const FLEET_HEARTBEAT_PATH = '/api/public/fleet/heartbeat'\n\nexport interface SendFleetHeartbeatOptions {\n /** Sonor API origin (e.g. https://api.sonor.io). Trailing slash tolerated. */\n apiUrl: string\n /** Project API key — scopes the request; the project is resolved server-side. */\n apiKey: string\n /** Client-observable active modules (validated/deduped by the contract). */\n modules?: FleetModule[] | string[]\n /** Normalized host for the multi-site sub-dimension (server re-normalizes). */\n site?: string | null\n /** Installed Next.js version, if the caller can resolve it. */\n nextVersion?: string | null\n /** 'client' (runtime boot) or 'build' (CI). Default 'client'. */\n source?: FleetHeartbeatSource\n /** Override the reported kit version. Defaults to the runtime SITE_KIT_VERSION. */\n kitVersion?: string\n /** Log one info line with the result. Never logs at error level. */\n debug?: boolean\n}\n\n/**\n * Best-effort runtime detection of the host Next.js version. Unreliable by\n * design — Next does not expose its version consistently across app/pages\n * router — so it returns null unless a site injects `__SITE_KIT_NEXT_VERSION__`\n * or `window.next.version` is present. Build-time callers should pass\n * `nextVersion` explicitly (resolvable from `next/package.json`).\n */\nexport function detectNextVersion(): string | null {\n if (typeof window === 'undefined') return null\n const w = window as unknown as {\n __SITE_KIT_NEXT_VERSION__?: string\n next?: { version?: string }\n }\n return sanitizeFleetVersion(w.__SITE_KIT_NEXT_VERSION__ ?? w.next?.version ?? null)\n}\n\n/**\n * Fire one heartbeat. Fire-and-forget by contract: it never throws — a\n * telemetry POST must never break a visitor's page or a site's build. Returns\n * true only when the POST was accepted (2xx).\n */\nexport async function sendFleetHeartbeat(opts: SendFleetHeartbeatOptions): Promise<boolean> {\n const { apiUrl, apiKey } = opts\n if (!apiUrl || !apiKey) return false\n\n const payload: FleetHeartbeatPayload = buildFleetHeartbeatPayload({\n kitVersion: opts.kitVersion || SITE_KIT_VERSION,\n nextVersion: opts.nextVersion,\n modules: opts.modules,\n site: opts.site,\n source: opts.source,\n })\n\n try {\n const res = await sonorFetch(\n `${apiUrl.replace(/\\/$/, '')}${FLEET_HEARTBEAT_PATH}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n },\n // retries: 0 — the once-per-session guard already bounds volume, and a\n // missed heartbeat is harmless (the next page load or passive\n // x-sitekit-version capture re-registers the site).\n { apiKey, retries: 0 },\n )\n if (opts.debug) {\n // info, never error: a visitor's console must stay clean (Lighthouse).\n console.info(\n `[Sonor fleet] heartbeat ${res.status} v${payload.kit_version} [${payload.modules.join(',') || 'none'}]`,\n )\n }\n return res.ok\n } catch (err) {\n if (opts.debug) console.info('[Sonor fleet] heartbeat skipped (network)', err)\n return false\n }\n}\n","/**\n * @sonordev/site-kit/fleet — FleetHeartbeat\n *\n * A childless, effect-only client component that reports this site's build\n * fingerprint (kit version, Next.js version, active modules, host) to Sonor\n * exactly once per browser session. It exists so the platform can answer\n * \"which version / modules / key state is each site running\" without shelling\n * into every client repo.\n *\n * It is mounted as a deferred, CHILDLESS SIBLING — never a wrapper — by\n * SiteKitClientProviders, behind the same idle/first-interaction gate as\n * Analytics and Engage, so it never enters the critical hydration path (see\n * CLAUDE.md \"the page must server-render\"). It renders null and carries no\n * visitor data.\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { useDeferredActivation } from '../shared/defer'\nimport { SITE_KIT_VERSION } from '../shared/version'\nimport { detectNextVersion, sendFleetHeartbeat } from './heartbeat'\nimport type { FleetModule } from './contract'\n\n/** Session guard key — one heartbeat per session, re-sent when version/host changes. */\nconst SESSION_GUARD_KEY = '_sk_fleet_hb'\n\nexport interface FleetHeartbeatProps {\n /** Sonor API origin. Falls back to `window.__SITE_KIT_API_URL__` then api.sonor.io. */\n apiUrl?: string\n /** Project API key. Falls back to `window.__SITE_KIT_API_KEY__`. */\n apiKey?: string\n /** Host for the multi-site sub-dimension. Falls back to `__SITE_KIT_SITE__` then location.host. */\n site?: string | null\n /** Client-observable active modules (SiteKitClientProviders passes the enabled set). */\n modules?: FleetModule[]\n /** Installed Next.js version if known; otherwise best-effort runtime detection. */\n nextVersion?: string | null\n /**\n * Self-defer to idle / first interaction. Default true so standalone use is\n * safe. SiteKitClientProviders already gates the mount and passes false.\n */\n defer?: boolean\n /** Send at most once per browser session per (version, host). Default true. */\n oncePerSession?: boolean\n debug?: boolean\n}\n\nexport function FleetHeartbeat({\n apiUrl,\n apiKey,\n site,\n modules,\n nextVersion,\n defer = true,\n oncePerSession = true,\n debug = false,\n}: FleetHeartbeatProps) {\n const ready = useDeferredActivation(defer)\n const sentRef = useRef(false)\n\n useEffect(() => {\n if (!ready || sentRef.current) return\n if (typeof window === 'undefined') return\n\n const w = window as unknown as {\n __SITE_KIT_API_URL__?: string\n __SITE_KIT_API_KEY__?: string\n __SITE_KIT_SITE__?: string\n }\n const url = apiUrl || w.__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const key = apiKey || w.__SITE_KIT_API_KEY__\n if (!key) return // no key resolvable — nothing to authenticate the heartbeat\n\n const resolvedSite = site ?? w.__SITE_KIT_SITE__ ?? window.location.host ?? ''\n\n // Once-per-session-per-(version,host): keeps heartbeat volume to one POST\n // per visitor session while still re-reporting after an upgrade or on a\n // different sub-site. Storage-disabled browsers simply send once per load.\n if (oncePerSession) {\n const stamp = `${SITE_KIT_VERSION}:${resolvedSite}`\n try {\n if (sessionStorage.getItem(SESSION_GUARD_KEY) === stamp) {\n sentRef.current = true\n return\n }\n sessionStorage.setItem(SESSION_GUARD_KEY, stamp)\n } catch {\n /* storage unavailable — fall through and send this load */\n }\n }\n\n sentRef.current = true\n void sendFleetHeartbeat({\n apiUrl: url,\n apiKey: key,\n site: resolvedSite,\n modules,\n nextVersion: nextVersion ?? detectNextVersion(),\n source: 'client',\n debug,\n })\n }, [ready, apiUrl, apiKey, site, modules, nextVersion, oncePerSession, debug])\n\n return null\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/fleet/heartbeat.ts","../src/fleet/FleetHeartbeat.tsx"],"names":[],"mappings":"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","file":"chunk-E4TWVVSW.mjs","sourcesContent":["/**\n * @sonordev/site-kit/fleet — heartbeat sender (single source of truth for the POST)\n *\n * One place that turns fleet inputs into a validated payload and ships it to\n * `/api/public/fleet/heartbeat`. Used by BOTH the client component\n * (FleetHeartbeat) and any build-time caller, so the send path never forks.\n *\n * It routes through the canonical `sonorFetch` transport, which already stamps\n * the x-sitekit-version header, attaches x-api-key, and honors the auth\n * circuit breaker — a site on a stale/canceled key will not spam the API.\n */\n\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { SITE_KIT_VERSION } from '../shared/version'\nimport {\n buildFleetHeartbeatPayload,\n sanitizeFleetVersion,\n type FleetHeartbeatPayload,\n type FleetHeartbeatSource,\n type FleetModule,\n} from './contract'\n\n/** Canonical ingest path — resolved against the site's Sonor API origin. */\nexport const FLEET_HEARTBEAT_PATH = '/api/public/fleet/heartbeat'\n\nexport interface SendFleetHeartbeatOptions {\n /** Sonor API origin (e.g. https://api.sonor.io). Trailing slash tolerated. */\n apiUrl: string\n /** Project API key — scopes the request; the project is resolved server-side. */\n apiKey: string\n /** Client-observable active modules (validated/deduped by the contract). */\n modules?: FleetModule[] | string[]\n /** Normalized host for the multi-site sub-dimension (server re-normalizes). */\n site?: string | null\n /** Installed Next.js version, if the caller can resolve it. */\n nextVersion?: string | null\n /** 'client' (runtime boot) or 'build' (CI). Default 'client'. */\n source?: FleetHeartbeatSource\n /** Override the reported kit version. Defaults to the runtime SITE_KIT_VERSION. */\n kitVersion?: string\n /** Log one info line with the result. Never logs at error level. */\n debug?: boolean\n}\n\n/**\n * Best-effort runtime detection of the host Next.js version. Unreliable by\n * design — Next does not expose its version consistently across app/pages\n * router — so it returns null unless a site injects `__SITE_KIT_NEXT_VERSION__`\n * or `window.next.version` is present. Build-time callers should pass\n * `nextVersion` explicitly (resolvable from `next/package.json`).\n */\nexport function detectNextVersion(): string | null {\n if (typeof window === 'undefined') return null\n const w = window as unknown as {\n __SITE_KIT_NEXT_VERSION__?: string\n next?: { version?: string }\n }\n return sanitizeFleetVersion(w.__SITE_KIT_NEXT_VERSION__ ?? w.next?.version ?? null)\n}\n\n/**\n * Fire one heartbeat. Fire-and-forget by contract: it never throws — a\n * telemetry POST must never break a visitor's page or a site's build. Returns\n * true only when the POST was accepted (2xx).\n */\nexport async function sendFleetHeartbeat(opts: SendFleetHeartbeatOptions): Promise<boolean> {\n const { apiUrl, apiKey } = opts\n if (!apiUrl || !apiKey) return false\n\n const payload: FleetHeartbeatPayload = buildFleetHeartbeatPayload({\n kitVersion: opts.kitVersion || SITE_KIT_VERSION,\n nextVersion: opts.nextVersion,\n modules: opts.modules,\n site: opts.site,\n source: opts.source,\n })\n\n try {\n const res = await sonorFetch(\n `${apiUrl.replace(/\\/$/, '')}${FLEET_HEARTBEAT_PATH}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n },\n // retries: 0 — the once-per-session guard already bounds volume, and a\n // missed heartbeat is harmless (the next page load or passive\n // x-sitekit-version capture re-registers the site).\n { apiKey, retries: 0 },\n )\n if (opts.debug) {\n // info, never error: a visitor's console must stay clean (Lighthouse).\n console.info(\n `[Sonor fleet] heartbeat ${res.status} v${payload.kit_version} [${payload.modules.join(',') || 'none'}]`,\n )\n }\n return res.ok\n } catch (err) {\n if (opts.debug) console.info('[Sonor fleet] heartbeat skipped (network)', err)\n return false\n }\n}\n","/**\n * @sonordev/site-kit/fleet — FleetHeartbeat\n *\n * A childless, effect-only client component that reports this site's build\n * fingerprint (kit version, Next.js version, active modules, host) to Sonor\n * exactly once per browser session. It exists so the platform can answer\n * \"which version / modules / key state is each site running\" without shelling\n * into every client repo.\n *\n * It is mounted as a deferred, CHILDLESS SIBLING — never a wrapper — by\n * SiteKitClientProviders, behind the same idle/first-interaction gate as\n * Analytics and Engage, so it never enters the critical hydration path (see\n * CLAUDE.md \"the page must server-render\"). It renders null and carries no\n * visitor data.\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { useDeferredActivation } from '../shared/defer'\nimport { SITE_KIT_VERSION } from '../shared/version'\nimport { detectNextVersion, sendFleetHeartbeat } from './heartbeat'\nimport type { FleetModule } from './contract'\n\n/** Session guard key — one heartbeat per session, re-sent when version/host changes. */\nconst SESSION_GUARD_KEY = '_sk_fleet_hb'\n\nexport interface FleetHeartbeatProps {\n /** Sonor API origin. Falls back to `window.__SITE_KIT_API_URL__` then api.sonor.io. */\n apiUrl?: string\n /** Project API key. Falls back to `window.__SITE_KIT_API_KEY__`. */\n apiKey?: string\n /** Host for the multi-site sub-dimension. Falls back to `__SITE_KIT_SITE__` then location.host. */\n site?: string | null\n /** Client-observable active modules (SiteKitClientProviders passes the enabled set). */\n modules?: FleetModule[]\n /** Installed Next.js version if known; otherwise best-effort runtime detection. */\n nextVersion?: string | null\n /**\n * Self-defer to idle / first interaction. Default true so standalone use is\n * safe. SiteKitClientProviders already gates the mount and passes false.\n */\n defer?: boolean\n /** Send at most once per browser session per (version, host). Default true. */\n oncePerSession?: boolean\n debug?: boolean\n}\n\nexport function FleetHeartbeat({\n apiUrl,\n apiKey,\n site,\n modules,\n nextVersion,\n defer = true,\n oncePerSession = true,\n debug = false,\n}: FleetHeartbeatProps) {\n const ready = useDeferredActivation(defer)\n const sentRef = useRef(false)\n\n useEffect(() => {\n if (!ready || sentRef.current) return\n if (typeof window === 'undefined') return\n\n const w = window as unknown as {\n __SITE_KIT_API_URL__?: string\n __SITE_KIT_API_KEY__?: string\n __SITE_KIT_SITE__?: string\n }\n const url = apiUrl || w.__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const key = apiKey || w.__SITE_KIT_API_KEY__\n if (!key) return // no key resolvable — nothing to authenticate the heartbeat\n\n const resolvedSite = site ?? w.__SITE_KIT_SITE__ ?? window.location.host ?? ''\n\n // Once-per-session-per-(version,host): keeps heartbeat volume to one POST\n // per visitor session while still re-reporting after an upgrade or on a\n // different sub-site. Storage-disabled browsers simply send once per load.\n if (oncePerSession) {\n const stamp = `${SITE_KIT_VERSION}:${resolvedSite}`\n try {\n if (sessionStorage.getItem(SESSION_GUARD_KEY) === stamp) {\n sentRef.current = true\n return\n }\n sessionStorage.setItem(SESSION_GUARD_KEY, stamp)\n } catch {\n /* storage unavailable — fall through and send this load */\n }\n }\n\n sentRef.current = true\n void sendFleetHeartbeat({\n apiUrl: url,\n apiKey: key,\n site: resolvedSite,\n modules,\n nextVersion: nextVersion ?? detectNextVersion(),\n source: 'client',\n debug,\n })\n }, [ready, apiUrl, apiKey, site, modules, nextVersion, oncePerSession, debug])\n\n return null\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkLF3ID6WN_js = require('./chunk-LF3ID6WN.js');
|
|
5
|
+
var chunkGMSPDTEV_js = require('./chunk-GMSPDTEV.js');
|
|
5
6
|
var react = require('react');
|
|
6
7
|
var ReactMarkdown = require('react-markdown');
|
|
7
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -36,7 +37,7 @@ function InlineManagedForm({ slug, prefill, primaryColor, primaryRgb }) {
|
|
|
36
37
|
submit,
|
|
37
38
|
isSubmitting,
|
|
38
39
|
isComplete
|
|
39
|
-
} =
|
|
40
|
+
} = chunkLF3ID6WN_js.useForm(slug, { initialValues: prefill || {} });
|
|
40
41
|
const cardStyle = {
|
|
41
42
|
marginTop: 8,
|
|
42
43
|
padding: 12,
|
|
@@ -79,7 +80,7 @@ function InlineManagedForm({ slug, prefill, primaryColor, primaryRgb }) {
|
|
|
79
80
|
style: { display: "block", fontSize: 12.5, fontWeight: 600, marginBottom: 4, color: "var(--sk-text-secondary, #4b5563)" },
|
|
80
81
|
children: [
|
|
81
82
|
field.label,
|
|
82
|
-
field.is_required ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sk-error, #
|
|
83
|
+
field.is_required ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sk-error, #dc2626)" }, children: " *" }) : null
|
|
83
84
|
]
|
|
84
85
|
}
|
|
85
86
|
) : null;
|
|
@@ -88,7 +89,7 @@ function InlineManagedForm({ slug, prefill, primaryColor, primaryRgb }) {
|
|
|
88
89
|
id,
|
|
89
90
|
placeholder: field.placeholder || (field.hide_label ? field.label : void 0),
|
|
90
91
|
"aria-invalid": !!err,
|
|
91
|
-
style: { ...inputBase, ...err ? { borderColor: "var(--sk-error, #
|
|
92
|
+
style: { ...inputBase, ...err ? { borderColor: "var(--sk-error, #dc2626)" } : {} }
|
|
92
93
|
};
|
|
93
94
|
let control;
|
|
94
95
|
switch (field.field_type) {
|
|
@@ -161,7 +162,7 @@ function InlineManagedForm({ slug, prefill, primaryColor, primaryRgb }) {
|
|
|
161
162
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
|
|
162
163
|
field.field_type === "checkbox" ? null : labelEl,
|
|
163
164
|
control,
|
|
164
|
-
err ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "4px 0 0", fontSize: 11.5, color: "var(--sk-error, #
|
|
165
|
+
err ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "4px 0 0", fontSize: 11.5, color: "var(--sk-error, #dc2626)" }, children: err }) : null
|
|
165
166
|
] }, field.id || field.slug);
|
|
166
167
|
};
|
|
167
168
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -181,7 +182,7 @@ function InlineManagedForm({ slug, prefill, primaryColor, primaryRgb }) {
|
|
|
181
182
|
}
|
|
182
183
|
return renderField(field);
|
|
183
184
|
}),
|
|
184
|
-
submitError ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", style: { margin: "0 0 8px", fontSize: 12, color: "var(--sk-error, #
|
|
185
|
+
submitError ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", style: { margin: "0 0 8px", fontSize: 12, color: "var(--sk-error, #dc2626)" }, children: submitError }) : null,
|
|
185
186
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
186
187
|
"button",
|
|
187
188
|
{
|
|
@@ -388,9 +389,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
388
389
|
const { apiKey } = getApiConfig();
|
|
389
390
|
if (!apiKey) return;
|
|
390
391
|
let cancelled = false;
|
|
391
|
-
|
|
392
|
-
headers: { "x-api-key": apiKey }
|
|
393
|
-
}).then((res) => res.ok ? res.json() : null).then((data) => {
|
|
392
|
+
chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/api/public/seo/project-info`, {}, { apiKey, retries: 0 }).then((res) => res.ok ? res.json() : null).then((data) => {
|
|
394
393
|
if (cancelled || !data?.valid || !data?.project_id) return;
|
|
395
394
|
setResolvedProjectId(data.project_id);
|
|
396
395
|
}).catch(() => {
|
|
@@ -404,9 +403,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
404
403
|
const apiKey = ensureApiKey();
|
|
405
404
|
if (!apiKey) return;
|
|
406
405
|
try {
|
|
407
|
-
const response = await
|
|
408
|
-
headers: { "x-api-key": apiKey }
|
|
409
|
-
});
|
|
406
|
+
const response = await chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/config?projectId=${projectId}`, {}, { apiKey, retries: 0 });
|
|
410
407
|
if (response.ok) {
|
|
411
408
|
const { data } = await response.json();
|
|
412
409
|
setWidgetConfig(data ?? null);
|
|
@@ -422,9 +419,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
422
419
|
const apiKey = ensureApiKey();
|
|
423
420
|
if (!apiKey) return null;
|
|
424
421
|
try {
|
|
425
|
-
const response = await
|
|
426
|
-
headers: { "x-api-key": apiKey }
|
|
427
|
-
});
|
|
422
|
+
const response = await chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/availability?projectId=${projectId}`, {}, { apiKey, retries: 0 });
|
|
428
423
|
if (response.ok) {
|
|
429
424
|
const { data } = await response.json();
|
|
430
425
|
setAvailability(data);
|
|
@@ -441,16 +436,16 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
441
436
|
const apiKey = ensureApiKey();
|
|
442
437
|
if (!apiKey) return null;
|
|
443
438
|
try {
|
|
444
|
-
const response = await
|
|
439
|
+
const response = await chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/session`, {
|
|
445
440
|
method: "POST",
|
|
446
|
-
headers: { "Content-Type": "application/json"
|
|
441
|
+
headers: { "Content-Type": "application/json" },
|
|
447
442
|
body: JSON.stringify({
|
|
448
443
|
projectId,
|
|
449
444
|
visitorId,
|
|
450
445
|
sourceUrl: typeof window !== "undefined" ? window.location.href : "",
|
|
451
446
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : ""
|
|
452
447
|
})
|
|
453
|
-
});
|
|
448
|
+
}, { apiKey, retries: 0 });
|
|
454
449
|
if (response.ok) {
|
|
455
450
|
const { data } = await response.json();
|
|
456
451
|
const session = data.session ?? data;
|
|
@@ -502,14 +497,13 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
502
497
|
pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
|
|
503
498
|
...siteContext ? { siteContext } : {}
|
|
504
499
|
};
|
|
505
|
-
const res = await
|
|
500
|
+
const res = await chunkGMSPDTEV_js.sonorFetch(url, {
|
|
506
501
|
method: "POST",
|
|
507
502
|
headers: {
|
|
508
|
-
"Content-Type": "application/json"
|
|
509
|
-
"x-api-key": apiKey
|
|
503
|
+
"Content-Type": "application/json"
|
|
510
504
|
},
|
|
511
505
|
body: JSON.stringify(body)
|
|
512
|
-
});
|
|
506
|
+
}, { apiKey, retries: 0 });
|
|
513
507
|
const json = await res.json();
|
|
514
508
|
if (!res.ok) {
|
|
515
509
|
throw new Error(json?.error?.message || json?.message || `Signal API error: ${res.status}`);
|
|
@@ -614,9 +608,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
614
608
|
if (currentSessionId) {
|
|
615
609
|
const apiKey = ensureApiKey();
|
|
616
610
|
if (apiKey) {
|
|
617
|
-
|
|
618
|
-
headers: { "x-api-key": apiKey }
|
|
619
|
-
}).then((res) => res.ok ? res.json() : null).then((json) => {
|
|
611
|
+
chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/messages?sessionId=${currentSessionId}`, {}, { apiKey, retries: 0 }).then((res) => res.ok ? res.json() : null).then((json) => {
|
|
620
612
|
const data = json?.data ?? json;
|
|
621
613
|
if (Array.isArray(data) && data.length) {
|
|
622
614
|
setMessages((prev) => {
|
|
@@ -679,9 +671,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
679
671
|
try {
|
|
680
672
|
const apiKey = ensureApiKey();
|
|
681
673
|
if (!apiKey) return;
|
|
682
|
-
const response = await
|
|
683
|
-
headers: { "x-api-key": apiKey }
|
|
684
|
-
});
|
|
674
|
+
const response = await chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/messages?sessionId=${currentSessionId}`, {}, { apiKey, retries: 0 });
|
|
685
675
|
if (response.ok) {
|
|
686
676
|
const { data } = await response.json();
|
|
687
677
|
setMessages((prev) => {
|
|
@@ -834,11 +824,10 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
834
824
|
form.append("file", file);
|
|
835
825
|
form.append("sessionId", sessionId);
|
|
836
826
|
form.append("visitorId", visitorId);
|
|
837
|
-
const res = await
|
|
827
|
+
const res = await chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/upload`, {
|
|
838
828
|
method: "POST",
|
|
839
|
-
headers: { "x-api-key": apiKey },
|
|
840
829
|
body: form
|
|
841
|
-
});
|
|
830
|
+
}, { apiKey, retries: 0 });
|
|
842
831
|
if (!res.ok) throw new Error("Upload failed");
|
|
843
832
|
const json = await res.json();
|
|
844
833
|
const d = json?.data ?? json;
|
|
@@ -982,11 +971,11 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
982
971
|
if (!apiKey) return;
|
|
983
972
|
setCheckingHandoff(true);
|
|
984
973
|
try {
|
|
985
|
-
const res = await
|
|
974
|
+
const res = await chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/handoff`, {
|
|
986
975
|
method: "POST",
|
|
987
|
-
headers: { "Content-Type": "application/json"
|
|
976
|
+
headers: { "Content-Type": "application/json" },
|
|
988
977
|
body: JSON.stringify({ sessionId })
|
|
989
|
-
});
|
|
978
|
+
}, { apiKey, retries: 0 });
|
|
990
979
|
const json = await res.json();
|
|
991
980
|
const available = json?.data?.available === true;
|
|
992
981
|
setCheckingHandoff(false);
|
|
@@ -1021,9 +1010,9 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
1021
1010
|
setIsLoading(true);
|
|
1022
1011
|
setOfflineError(null);
|
|
1023
1012
|
try {
|
|
1024
|
-
const response = await
|
|
1013
|
+
const response = await chunkGMSPDTEV_js.sonorFetch(`${baseUrl}/engage/widget/offline-form`, {
|
|
1025
1014
|
method: "POST",
|
|
1026
|
-
headers: { "Content-Type": "application/json"
|
|
1015
|
+
headers: { "Content-Type": "application/json" },
|
|
1027
1016
|
body: JSON.stringify({
|
|
1028
1017
|
projectId,
|
|
1029
1018
|
visitorId,
|
|
@@ -1031,7 +1020,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
1031
1020
|
pageUrl: typeof window !== "undefined" ? window.location.href : "",
|
|
1032
1021
|
...widgetConfig?.offlineFormSlug && { formSlug: widgetConfig.offlineFormSlug }
|
|
1033
1022
|
})
|
|
1034
|
-
});
|
|
1023
|
+
}, { apiKey, retries: 0 });
|
|
1035
1024
|
if (response.ok) {
|
|
1036
1025
|
setOfflineSubmitted(true);
|
|
1037
1026
|
} else {
|
|
@@ -1454,7 +1443,7 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
1454
1443
|
{
|
|
1455
1444
|
type: "button",
|
|
1456
1445
|
onClick: retryFailedSend,
|
|
1457
|
-
style: { padding: "6px 12px", borderRadius: 6, border: "1px solid var(--sk-error, #
|
|
1446
|
+
style: { padding: "6px 12px", borderRadius: 6, border: "1px solid var(--sk-error, #dc2626)", backgroundColor: "var(--sk-error-bg, #fef2f2)", color: "var(--sk-error, #dc2626)", fontSize: 13, cursor: "pointer" },
|
|
1458
1447
|
children: "Retry send"
|
|
1459
1448
|
}
|
|
1460
1449
|
) }),
|
|
@@ -1622,5 +1611,5 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
|
|
|
1622
1611
|
}
|
|
1623
1612
|
|
|
1624
1613
|
exports.ChatWidget = ChatWidget;
|
|
1625
|
-
//# sourceMappingURL=chunk-
|
|
1626
|
-
//# sourceMappingURL=chunk-
|
|
1614
|
+
//# sourceMappingURL=chunk-E7M5MDGC.js.map
|
|
1615
|
+
//# sourceMappingURL=chunk-E7M5MDGC.js.map
|