@sonordev/site-kit 3.3.1 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/agent-manifest.json +13 -1
- package/dist/AnalyticsProvider-35EDQA5V.js +31 -0
- package/dist/{AnalyticsProvider-PLGTU56K.js.map → AnalyticsProvider-35EDQA5V.js.map} +1 -1
- package/dist/AnalyticsProvider-V5CWTWWO.mjs +10 -0
- package/dist/{AnalyticsProvider-3MZ3O5OB.mjs.map → AnalyticsProvider-V5CWTWWO.mjs.map} +1 -1
- package/dist/ChatWidget-2OK6DD66.js +19 -0
- package/dist/{ChatWidget-FQARJMGU.js.map → ChatWidget-2OK6DD66.js.map} +1 -1
- package/dist/ChatWidget-WNT6VNJK.mjs +10 -0
- package/dist/{ChatWidget-7JHVRNVE.mjs.map → ChatWidget-WNT6VNJK.mjs.map} +1 -1
- package/dist/EngageWidget-7RZIC426.js +18 -0
- package/dist/{EngageWidget-DQ62NQPU.js.map → EngageWidget-7RZIC426.js.map} +1 -1
- package/dist/EngageWidget-GWME22IP.mjs +9 -0
- package/dist/{EngageWidget-VXQOZOYA.mjs.map → EngageWidget-GWME22IP.mjs.map} +1 -1
- package/dist/{SignalCore-3SG3LFQL.js → SignalCore-DK4HQBPY.js} +62 -43
- package/dist/SignalCore-DK4HQBPY.js.map +1 -0
- package/dist/{SignalCore-BKG66B4C.mjs → SignalCore-TW4YA3BW.mjs} +56 -37
- package/dist/SignalCore-TW4YA3BW.mjs.map +1 -0
- package/dist/SitemapSync-7PXQMF5A.mjs +8 -0
- package/dist/{SitemapSync-IO2VOR23.mjs.map → SitemapSync-7PXQMF5A.mjs.map} +1 -1
- package/dist/SitemapSync-O3J2DPV7.js +17 -0
- package/dist/{SitemapSync-DWX7I6MX.js.map → SitemapSync-O3J2DPV7.js.map} +1 -1
- package/dist/analytics/index.js +14 -12
- package/dist/analytics/index.mjs +7 -5
- package/dist/blog/index.d.mts +3 -3
- package/dist/blog/index.d.ts +3 -3
- package/dist/blog/index.js +11 -15
- package/dist/blog/index.js.map +1 -1
- package/dist/blog/index.mjs +2 -2
- package/dist/blog/index.mjs.map +1 -1
- package/dist/blog/server-ui.d.mts +1 -1
- package/dist/blog/server-ui.d.ts +1 -1
- package/dist/blog/server-ui.js +198 -9
- package/dist/blog/server-ui.js.map +1 -1
- package/dist/blog/server-ui.mjs +198 -2
- package/dist/blog/server-ui.mjs.map +1 -1
- package/dist/blog/server.d.mts +27 -8
- package/dist/blog/server.d.ts +27 -8
- package/dist/blog/server.js +45 -43
- package/dist/blog/server.mjs +3 -1
- package/dist/{chunk-QW3T6WH2.mjs → chunk-2NA5CAK5.mjs} +3 -3
- package/dist/{chunk-QW3T6WH2.mjs.map → chunk-2NA5CAK5.mjs.map} +1 -1
- package/dist/{chunk-WN5A3KSY.mjs → chunk-34IUDOBC.mjs} +2 -2
- package/dist/{chunk-WN5A3KSY.mjs.map → chunk-34IUDOBC.mjs.map} +1 -1
- package/dist/{chunk-3WRE7ZDC.js → chunk-3KEZ2YHQ.js} +8 -8
- package/dist/{chunk-3WRE7ZDC.js.map → chunk-3KEZ2YHQ.js.map} +1 -1
- package/dist/{chunk-NQ3K4NWX.mjs → chunk-5WQHWBCW.mjs} +11 -30
- package/dist/chunk-5WQHWBCW.mjs.map +1 -0
- package/dist/chunk-6EDVCUAG.mjs +29 -0
- package/dist/chunk-6EDVCUAG.mjs.map +1 -0
- package/dist/{chunk-ZFF3BKNE.mjs → chunk-6JVDIW5L.mjs} +4 -4
- package/dist/{chunk-ZFF3BKNE.mjs.map → chunk-6JVDIW5L.mjs.map} +1 -1
- package/dist/{chunk-7TX5BKVA.js → chunk-6T4NVCAT.js} +2 -2
- package/dist/{chunk-7TX5BKVA.js.map → chunk-6T4NVCAT.js.map} +1 -1
- package/dist/{chunk-OC64AHKN.mjs → chunk-7FZWMAI2.mjs} +3 -3
- package/dist/{chunk-OC64AHKN.mjs.map → chunk-7FZWMAI2.mjs.map} +1 -1
- package/dist/{chunk-EE6SFAZP.mjs → chunk-AX4AROLH.mjs} +5 -14
- package/dist/chunk-AX4AROLH.mjs.map +1 -0
- package/dist/chunk-BNJH2RFU.mjs +139 -0
- package/dist/chunk-BNJH2RFU.mjs.map +1 -0
- package/dist/{chunk-WZHWWOUC.js → chunk-BX6FFL2Y.js} +6 -16
- package/dist/chunk-BX6FFL2Y.js.map +1 -0
- package/dist/chunk-CGCYZJYX.mjs +41 -0
- package/dist/chunk-CGCYZJYX.mjs.map +1 -0
- package/dist/{chunk-PIV54R2O.js → chunk-CTPE3G5W.js} +5 -5
- package/dist/{chunk-PIV54R2O.js.map → chunk-CTPE3G5W.js.map} +1 -1
- package/dist/chunk-CXDIWBIQ.js +78 -0
- package/dist/chunk-CXDIWBIQ.js.map +1 -0
- package/dist/chunk-DWVF7SEK.mjs +35 -0
- package/dist/chunk-DWVF7SEK.mjs.map +1 -0
- package/dist/{chunk-C4JAMON3.js → chunk-EH7QQU6P.js} +15 -15
- package/dist/{chunk-C4JAMON3.js.map → chunk-EH7QQU6P.js.map} +1 -1
- package/dist/chunk-EU2UGO25.js +52 -0
- package/dist/chunk-EU2UGO25.js.map +1 -0
- package/dist/{chunk-X4OPM3SK.mjs → chunk-GU5OTUQS.mjs} +5 -14
- package/dist/chunk-GU5OTUQS.mjs.map +1 -0
- package/dist/{chunk-SH4VZDVX.mjs → chunk-GUXB3QH7.mjs} +38 -67
- package/dist/chunk-GUXB3QH7.mjs.map +1 -0
- package/dist/{chunk-JD6LV6JZ.mjs → chunk-HRJ65XKY.mjs} +3 -3
- package/dist/{chunk-JD6LV6JZ.mjs.map → chunk-HRJ65XKY.mjs.map} +1 -1
- package/dist/chunk-IBMOX3YE.mjs +48 -0
- package/dist/chunk-IBMOX3YE.mjs.map +1 -0
- package/dist/{chunk-TXEOLHMC.js → chunk-IMDSDDRU.js} +4 -4
- package/dist/{chunk-TXEOLHMC.js.map → chunk-IMDSDDRU.js.map} +1 -1
- package/dist/{chunk-25YPXQBA.mjs → chunk-INGAARGC.mjs} +8 -25
- package/dist/chunk-INGAARGC.mjs.map +1 -0
- package/dist/{chunk-3AG6O3IA.mjs → chunk-LZSHZVBE.mjs} +49 -5
- package/dist/chunk-LZSHZVBE.mjs.map +1 -0
- package/dist/chunk-MJDYY6S3.mjs +76 -0
- package/dist/chunk-MJDYY6S3.mjs.map +1 -0
- package/dist/{chunk-BMKZHXWQ.js → chunk-MMON6EVI.js} +3 -194
- package/dist/chunk-MMON6EVI.js.map +1 -0
- package/dist/chunk-NB4MK2Q5.js +18 -0
- package/dist/chunk-NB4MK2Q5.js.map +1 -0
- package/dist/{chunk-DIXWP4BO.mjs → chunk-NBI5AV6U.mjs} +3 -3
- package/dist/{chunk-DIXWP4BO.mjs.map → chunk-NBI5AV6U.mjs.map} +1 -1
- package/dist/chunk-NI7OY4FW.mjs +16 -0
- package/dist/chunk-NI7OY4FW.mjs.map +1 -0
- package/dist/chunk-NME3SQCB.js +8 -0
- package/dist/{chunk-3X2YPJU5.js.map → chunk-NME3SQCB.js.map} +1 -1
- package/dist/{chunk-4JMXBIUC.js → chunk-PE2A3ON5.js} +16 -35
- package/dist/chunk-PE2A3ON5.js.map +1 -0
- package/dist/{chunk-BOWR5QEV.js → chunk-PWIBFSXK.js} +14 -14
- package/dist/{chunk-BOWR5QEV.js.map → chunk-PWIBFSXK.js.map} +1 -1
- package/dist/{chunk-4ROFY6PM.js → chunk-Q2SPOBHU.js} +61 -17
- package/dist/chunk-Q2SPOBHU.js.map +1 -0
- package/dist/chunk-QGPYFC6G.mjs +6 -0
- package/dist/{chunk-K6YGF2KJ.mjs.map → chunk-QGPYFC6G.mjs.map} +1 -1
- package/dist/{chunk-FSYXHIAI.js → chunk-SQGDDITI.js} +14 -14
- package/dist/{chunk-FSYXHIAI.js.map → chunk-SQGDDITI.js.map} +1 -1
- package/dist/{chunk-S2N3NSC7.mjs → chunk-STTSIODQ.mjs} +5 -5
- package/dist/{chunk-S2N3NSC7.mjs.map → chunk-STTSIODQ.mjs.map} +1 -1
- package/dist/{chunk-QRIGY6EM.js → chunk-T3RPPS25.js} +7 -7
- package/dist/{chunk-QRIGY6EM.js.map → chunk-T3RPPS25.js.map} +1 -1
- package/dist/{chunk-DNW7FTJD.js → chunk-TBMFLLRV.js} +9 -9
- package/dist/{chunk-DNW7FTJD.js.map → chunk-TBMFLLRV.js.map} +1 -1
- package/dist/{chunk-YFYMOQAX.js → chunk-TJS6FPR7.js} +14 -31
- package/dist/chunk-TJS6FPR7.js.map +1 -0
- package/dist/chunk-TPL2IHFI.js +43 -0
- package/dist/chunk-TPL2IHFI.js.map +1 -0
- package/dist/chunk-TRTT4PND.js +38 -0
- package/dist/chunk-TRTT4PND.js.map +1 -0
- package/dist/{chunk-QFWBAGBT.mjs → chunk-UFOOVODL.mjs} +3 -3
- package/dist/{chunk-QFWBAGBT.mjs.map → chunk-UFOOVODL.mjs.map} +1 -1
- package/dist/chunk-UXEB6UAR.js +147 -0
- package/dist/chunk-UXEB6UAR.js.map +1 -0
- package/dist/{chunk-MLD3EGM2.mjs → chunk-V37Z65NF.mjs} +3 -3
- package/dist/{chunk-MLD3EGM2.mjs.map → chunk-V37Z65NF.mjs.map} +1 -1
- package/dist/chunk-VJMPIRSD.js +31 -0
- package/dist/chunk-VJMPIRSD.js.map +1 -0
- package/dist/chunk-VX3WK77I.mjs +126 -0
- package/dist/chunk-VX3WK77I.mjs.map +1 -0
- package/dist/{chunk-AB2VYIYU.mjs → chunk-WTR7QJ32.mjs} +4 -194
- package/dist/chunk-WTR7QJ32.mjs.map +1 -0
- package/dist/{chunk-IB4FRJDV.js → chunk-XAWB2HFQ.js} +37 -67
- package/dist/chunk-XAWB2HFQ.js.map +1 -0
- package/dist/{chunk-3BNFUMLL.js → chunk-XB57AM6T.js} +5 -14
- package/dist/chunk-XB57AM6T.js.map +1 -0
- package/dist/chunk-XY4NJJEX.js +129 -0
- package/dist/chunk-XY4NJJEX.js.map +1 -0
- package/dist/{chunk-FMQHK6MM.js → chunk-Y4U3OCKH.js} +3 -3
- package/dist/{chunk-FMQHK6MM.js.map → chunk-Y4U3OCKH.js.map} +1 -1
- package/dist/{chunk-ZYIONE7A.mjs → chunk-YKPAFEJ4.mjs} +4 -4
- package/dist/{chunk-ZYIONE7A.mjs.map → chunk-YKPAFEJ4.mjs.map} +1 -1
- package/dist/{chunk-7OROUYZH.mjs → chunk-YSDJ7HI3.mjs} +4 -4
- package/dist/{chunk-7OROUYZH.mjs.map → chunk-YSDJ7HI3.mjs.map} +1 -1
- package/dist/{chunk-PCDAVHVX.js → chunk-ZY3G7JGT.js} +8 -8
- package/dist/{chunk-PCDAVHVX.js.map → chunk-ZY3G7JGT.js.map} +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.mjs +1 -1
- package/dist/client/index.d.mts +15 -1
- package/dist/client/index.d.ts +15 -1
- package/dist/client/index.js +21 -6
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +19 -1
- package/dist/client/index.mjs.map +1 -1
- package/dist/commerce/index.js +53 -51
- package/dist/commerce/index.mjs +8 -6
- package/dist/engage/index.js +11 -9
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +8 -6
- package/dist/engage/index.mjs.map +1 -1
- package/dist/fleet/index.js +8 -7
- package/dist/fleet/index.mjs +4 -3
- package/dist/forms/index.js +14 -12
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +6 -4
- package/dist/forms/index.mjs.map +1 -1
- package/dist/images/index.js +11 -10
- package/dist/images/index.mjs +4 -3
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +75 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13 -10
- package/dist/index.mjs.map +1 -1
- package/dist/landing/index.d.mts +21 -0
- package/dist/landing/index.d.ts +21 -0
- package/dist/landing/index.js +21 -0
- package/dist/landing/index.js.map +1 -0
- package/dist/landing/index.mjs +4 -0
- package/dist/landing/index.mjs.map +1 -0
- package/dist/layout/client.js +11 -8
- package/dist/layout/client.mjs +10 -7
- package/dist/layout/index.js +13 -54
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/index.mjs +11 -52
- package/dist/layout/index.mjs.map +1 -1
- package/dist/llms/index.js +12 -12
- package/dist/llms/index.mjs +2 -2
- package/dist/maps/index.js +5 -4
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/index.mjs +3 -2
- package/dist/maps/index.mjs.map +1 -1
- package/dist/metadata-D_GiY8LJ.d.mts +36 -0
- package/dist/metadata-D_GiY8LJ.d.ts +36 -0
- package/dist/middleware/index.js +2 -8
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +2 -8
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/seo/client.js +5 -4
- package/dist/seo/client.mjs +4 -3
- package/dist/seo/index.js +5 -4
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +4 -3
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-pages/contract.js +6 -5
- package/dist/seo-pages/contract.js.map +1 -1
- package/dist/seo-pages/contract.mjs +2 -1
- package/dist/seo-pages/contract.mjs.map +1 -1
- package/dist/server/index.d.mts +34 -1
- package/dist/server/index.d.ts +34 -1
- package/dist/server/index.js +6 -0
- package/dist/server/index.mjs +2 -0
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sitemap/index.js +2 -2
- package/dist/sitemap/index.mjs +1 -1
- package/dist/sites/contract.d.mts +36 -12
- package/dist/sites/contract.d.ts +36 -12
- package/dist/sites/contract.js +12 -11
- package/dist/sites/contract.mjs +2 -1
- package/dist/sync/index.js +16 -15
- package/dist/sync/index.mjs +4 -3
- package/dist/{types-DYOumpUT.d.mts → types-8IcjVMDa.d.mts} +1 -1
- package/dist/{types-DYOumpUT.d.ts → types-8IcjVMDa.d.ts} +1 -1
- package/package.json +11 -1
- package/dist/AnalyticsProvider-3MZ3O5OB.mjs +0 -8
- package/dist/AnalyticsProvider-PLGTU56K.js +0 -29
- package/dist/ChatWidget-7JHVRNVE.mjs +0 -8
- package/dist/ChatWidget-FQARJMGU.js +0 -17
- package/dist/EngageWidget-DQ62NQPU.js +0 -16
- package/dist/EngageWidget-VXQOZOYA.mjs +0 -7
- package/dist/SignalCore-3SG3LFQL.js.map +0 -1
- package/dist/SignalCore-BKG66B4C.mjs.map +0 -1
- package/dist/SitemapSync-DWX7I6MX.js +0 -16
- package/dist/SitemapSync-IO2VOR23.mjs +0 -7
- package/dist/chunk-25YPXQBA.mjs.map +0 -1
- package/dist/chunk-3AG6O3IA.mjs.map +0 -1
- package/dist/chunk-3BNFUMLL.js.map +0 -1
- package/dist/chunk-3X2YPJU5.js +0 -8
- package/dist/chunk-4JMXBIUC.js.map +0 -1
- package/dist/chunk-4ROFY6PM.js.map +0 -1
- package/dist/chunk-AB2VYIYU.mjs.map +0 -1
- package/dist/chunk-BMKZHXWQ.js.map +0 -1
- package/dist/chunk-EE6SFAZP.mjs.map +0 -1
- package/dist/chunk-GUU3AEFM.mjs +0 -259
- package/dist/chunk-GUU3AEFM.mjs.map +0 -1
- package/dist/chunk-IB4FRJDV.js.map +0 -1
- package/dist/chunk-K6YGF2KJ.mjs +0 -6
- package/dist/chunk-KPKZBIAQ.js +0 -264
- package/dist/chunk-KPKZBIAQ.js.map +0 -1
- package/dist/chunk-NQ3K4NWX.mjs.map +0 -1
- package/dist/chunk-SH4VZDVX.mjs.map +0 -1
- package/dist/chunk-WZHWWOUC.js.map +0 -1
- package/dist/chunk-X4OPM3SK.mjs.map +0 -1
- package/dist/chunk-YFYMOQAX.js.map +0 -1
package/README.md
CHANGED
|
@@ -152,8 +152,8 @@ import { AnalyticsProvider, useAnalytics, WebVitals } from '@sonordev/site-kit/a
|
|
|
152
152
|
// Forms
|
|
153
153
|
import { ManagedForm, useForm, formsApi, field } from '@sonordev/site-kit/forms'
|
|
154
154
|
|
|
155
|
-
// Blog
|
|
156
|
-
import { BlogPost, BlogList, ClusterLandingPage } from '@sonordev/site-kit/blog'
|
|
155
|
+
// Blog (server components — keeps server-only data helpers out of client bundles)
|
|
156
|
+
import { BlogPost, BlogList, ClusterLandingPage } from '@sonordev/site-kit/blog/server-ui'
|
|
157
157
|
import { getBlogPost, generateBlogStaticParams } from '@sonordev/site-kit/blog/server'
|
|
158
158
|
|
|
159
159
|
// Commerce
|
package/agent-manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"package": "@sonordev/site-kit",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.5.0",
|
|
5
5
|
"description": "Machine-readable manifest for coding agents integrating a site with Sonor. See AGENTS.md (shipped) and docs/SITE-KIT-AGENT-NATIVE.md.",
|
|
6
6
|
"env": {
|
|
7
7
|
"required": [
|
|
@@ -277,6 +277,13 @@
|
|
|
277
277
|
"side": "server",
|
|
278
278
|
"purpose": "Project info resolved by API key."
|
|
279
279
|
},
|
|
280
|
+
{
|
|
281
|
+
"name": "landing",
|
|
282
|
+
"import": "@sonordev/site-kit/landing",
|
|
283
|
+
"side": "mixed",
|
|
284
|
+
"purpose": "Paid-ad landing pages: wrap the route in <LandingPage campaign=\"...\"> and export landingPageMetadata() — noindex by default, excluded from SEO/sitemap, campaign-stamped analytics reporting under Analytics > Landing Pages.",
|
|
285
|
+
"caution": "Also exclude the route from sitemap.xml/app sitemap. landingPageMetadata() is the reliable noindex; the component's hoisted meta is belt-and-braces only."
|
|
286
|
+
},
|
|
280
287
|
{
|
|
281
288
|
"name": "layout",
|
|
282
289
|
"import": "@sonordev/site-kit/layout",
|
|
@@ -342,6 +349,11 @@
|
|
|
342
349
|
"id": "env.single-var",
|
|
343
350
|
"title": "The one env var",
|
|
344
351
|
"code": "# .env.local — the only variable a site needs\nSONOR_API_KEY=sonor_1a2b3c4d_... # server-side only, no NEXT_PUBLIC_ prefix"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"id": "landing.campaign-page",
|
|
355
|
+
"title": "Paid-ad landing page — noindex, campaign-stamped, SEO-excluded",
|
|
356
|
+
"code": "import { LandingPage, landingPageMetadata } from '@sonordev/site-kit/landing'\n\nexport const metadata = landingPageMetadata({\n title: 'Spring HVAC Tune-Up | Acme Heating',\n description: 'Book your $99 spring tune-up.',\n})\n\nexport default function SpringHvacLandingPage() {\n return (\n <LandingPage campaign=\"spring-hvac-2026\">\n {/* page content: hero, offer, ManagedForm, tel: CTA */}\n </LandingPage>\n )\n}\n\n// Also: keep this route OUT of sitemap.xml (app/sitemap.ts) — landing pages\n// are campaign surfaces, not SEO pages."
|
|
345
357
|
}
|
|
346
358
|
],
|
|
347
359
|
"failureModes": [
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkQ2SPOBHU_js = require('./chunk-Q2SPOBHU.js');
|
|
4
|
+
require('./chunk-HMFFAUCD.js');
|
|
5
|
+
require('./chunk-XB57AM6T.js');
|
|
6
|
+
require('./chunk-VJMPIRSD.js');
|
|
7
|
+
require('./chunk-XY4NJJEX.js');
|
|
8
|
+
require('./chunk-UXEB6UAR.js');
|
|
9
|
+
require('./chunk-NME3SQCB.js');
|
|
10
|
+
require('./chunk-ZSMWDLMK.js');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
Object.defineProperty(exports, "AnalyticsProvider", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return chunkQ2SPOBHU_js.AnalyticsProvider; }
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "useAnalytics", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return chunkQ2SPOBHU_js.useAnalytics; }
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(exports, "useAnalyticsOptional", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return chunkQ2SPOBHU_js.useAnalyticsOptional; }
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(exports, "useTrackEvent", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return chunkQ2SPOBHU_js.useTrackEvent; }
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=AnalyticsProvider-35EDQA5V.js.map
|
|
31
|
+
//# sourceMappingURL=AnalyticsProvider-35EDQA5V.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"AnalyticsProvider-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"AnalyticsProvider-35EDQA5V.js"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { AnalyticsProvider, useAnalytics, useAnalyticsOptional, useTrackEvent } from './chunk-LZSHZVBE.mjs';
|
|
2
|
+
import './chunk-3DPXOZAU.mjs';
|
|
3
|
+
import './chunk-AX4AROLH.mjs';
|
|
4
|
+
import './chunk-6EDVCUAG.mjs';
|
|
5
|
+
import './chunk-VX3WK77I.mjs';
|
|
6
|
+
import './chunk-BNJH2RFU.mjs';
|
|
7
|
+
import './chunk-QGPYFC6G.mjs';
|
|
8
|
+
import './chunk-4XPGGLVP.mjs';
|
|
9
|
+
//# sourceMappingURL=AnalyticsProvider-V5CWTWWO.mjs.map
|
|
10
|
+
//# sourceMappingURL=AnalyticsProvider-V5CWTWWO.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"AnalyticsProvider-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"AnalyticsProvider-V5CWTWWO.mjs"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkEH7QQU6P_js = require('./chunk-EH7QQU6P.js');
|
|
4
|
+
require('./chunk-TJS6FPR7.js');
|
|
5
|
+
require('./chunk-V6NVBFEP.js');
|
|
6
|
+
require('./chunk-VJMPIRSD.js');
|
|
7
|
+
require('./chunk-XY4NJJEX.js');
|
|
8
|
+
require('./chunk-UXEB6UAR.js');
|
|
9
|
+
require('./chunk-NME3SQCB.js');
|
|
10
|
+
require('./chunk-ZSMWDLMK.js');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
Object.defineProperty(exports, "ChatWidget", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return chunkEH7QQU6P_js.ChatWidget; }
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=ChatWidget-2OK6DD66.js.map
|
|
19
|
+
//# sourceMappingURL=ChatWidget-2OK6DD66.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"ChatWidget-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"ChatWidget-2OK6DD66.js"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { ChatWidget } from './chunk-YKPAFEJ4.mjs';
|
|
2
|
+
import './chunk-INGAARGC.mjs';
|
|
3
|
+
import './chunk-X3S6KXAP.mjs';
|
|
4
|
+
import './chunk-6EDVCUAG.mjs';
|
|
5
|
+
import './chunk-VX3WK77I.mjs';
|
|
6
|
+
import './chunk-BNJH2RFU.mjs';
|
|
7
|
+
import './chunk-QGPYFC6G.mjs';
|
|
8
|
+
import './chunk-4XPGGLVP.mjs';
|
|
9
|
+
//# sourceMappingURL=ChatWidget-WNT6VNJK.mjs.map
|
|
10
|
+
//# sourceMappingURL=ChatWidget-WNT6VNJK.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"ChatWidget-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"ChatWidget-WNT6VNJK.mjs"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk3KEZ2YHQ_js = require('./chunk-3KEZ2YHQ.js');
|
|
4
|
+
require('./chunk-XB57AM6T.js');
|
|
5
|
+
require('./chunk-VJMPIRSD.js');
|
|
6
|
+
require('./chunk-XY4NJJEX.js');
|
|
7
|
+
require('./chunk-UXEB6UAR.js');
|
|
8
|
+
require('./chunk-NME3SQCB.js');
|
|
9
|
+
require('./chunk-ZSMWDLMK.js');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, "EngageWidget", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return chunk3KEZ2YHQ_js.EngageWidget; }
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=EngageWidget-7RZIC426.js.map
|
|
18
|
+
//# sourceMappingURL=EngageWidget-7RZIC426.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"EngageWidget-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"EngageWidget-7RZIC426.js"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { EngageWidget } from './chunk-STTSIODQ.mjs';
|
|
2
|
+
import './chunk-AX4AROLH.mjs';
|
|
3
|
+
import './chunk-6EDVCUAG.mjs';
|
|
4
|
+
import './chunk-VX3WK77I.mjs';
|
|
5
|
+
import './chunk-BNJH2RFU.mjs';
|
|
6
|
+
import './chunk-QGPYFC6G.mjs';
|
|
7
|
+
import './chunk-4XPGGLVP.mjs';
|
|
8
|
+
//# sourceMappingURL=EngageWidget-GWME22IP.mjs.map
|
|
9
|
+
//# sourceMappingURL=EngageWidget-GWME22IP.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"EngageWidget-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"EngageWidget-GWME22IP.mjs"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
require('./chunk-
|
|
4
|
+
var chunkXB57AM6T_js = require('./chunk-XB57AM6T.js');
|
|
5
|
+
require('./chunk-VJMPIRSD.js');
|
|
6
|
+
var chunkXY4NJJEX_js = require('./chunk-XY4NJJEX.js');
|
|
7
|
+
var chunkUXEB6UAR_js = require('./chunk-UXEB6UAR.js');
|
|
8
|
+
require('./chunk-NME3SQCB.js');
|
|
7
9
|
require('./chunk-ZSMWDLMK.js');
|
|
8
10
|
var react = require('react');
|
|
9
11
|
|
|
@@ -63,8 +65,8 @@ function SignalCore({
|
|
|
63
65
|
const scrollDepthRef = react.useRef(0);
|
|
64
66
|
const clickCountRef = react.useRef(0);
|
|
65
67
|
const { apiUrl, apiKey } = getApiConfig();
|
|
66
|
-
const resolvedVisitorId = externalVisitorId ||
|
|
67
|
-
const resolvedSessionId = externalSessionId ||
|
|
68
|
+
const resolvedVisitorId = externalVisitorId || chunkXB57AM6T_js.getOrCreateVisitorId();
|
|
69
|
+
const resolvedSessionId = externalSessionId || chunkXB57AM6T_js.getOrCreateSessionId();
|
|
68
70
|
react.useEffect(() => {
|
|
69
71
|
onState({ config, loading, error });
|
|
70
72
|
}, [config, loading, error, onState]);
|
|
@@ -82,7 +84,7 @@ function SignalCore({
|
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
try {
|
|
85
|
-
const response = await
|
|
87
|
+
const response = await chunkXY4NJJEX_js.sonorFetch(
|
|
86
88
|
`${apiUrl}/api/public/signal/experiment/${experimentId}`,
|
|
87
89
|
{
|
|
88
90
|
headers: {
|
|
@@ -110,7 +112,7 @@ function SignalCore({
|
|
|
110
112
|
return;
|
|
111
113
|
}
|
|
112
114
|
try {
|
|
113
|
-
const response = await
|
|
115
|
+
const response = await chunkXY4NJJEX_js.sonorFetch(
|
|
114
116
|
`${apiUrl}/api/public/signal/config`,
|
|
115
117
|
{
|
|
116
118
|
headers: {
|
|
@@ -143,48 +145,65 @@ function SignalCore({
|
|
|
143
145
|
if (!apiKey || !enabled || !realtime) return;
|
|
144
146
|
if (eventSourceRef.current) {
|
|
145
147
|
eventSourceRef.current.close();
|
|
148
|
+
eventSourceRef.current = null;
|
|
146
149
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
setConfig((prev) => {
|
|
153
|
-
if (prev?.version !== version) {
|
|
154
|
-
if (isDebug()) console.log("[Signal] Config updated to version:", version);
|
|
155
|
-
return newConfig;
|
|
156
|
-
}
|
|
157
|
-
return prev;
|
|
158
|
-
});
|
|
159
|
-
} catch (err) {
|
|
160
|
-
if (isDebug()) console.error("[Signal] SSE parse error:", err);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
eventSource.addEventListener("experiment_update", (e) => {
|
|
164
|
-
try {
|
|
165
|
-
const { experiment_id, action } = JSON.parse(e.data);
|
|
166
|
-
if (action === "started" || action === "updated") {
|
|
167
|
-
loadExperimentAssignment(experiment_id);
|
|
168
|
-
} else if (action === "stopped") {
|
|
169
|
-
assignmentsRef.current.delete(experiment_id);
|
|
150
|
+
void (async () => {
|
|
151
|
+
const credential = await chunkUXEB6UAR_js.getFreshCredential(apiKey);
|
|
152
|
+
if (!credential || !chunkUXEB6UAR_js.isSiteToken(credential)) {
|
|
153
|
+
if (isDebug()) {
|
|
154
|
+
console.warn("[Signal] Realtime stream disabled: requires site-token mode (raw keys never go in URLs)");
|
|
170
155
|
}
|
|
171
|
-
|
|
172
|
-
if (isDebug()) console.error("[Signal] Experiment update error:", err);
|
|
156
|
+
return;
|
|
173
157
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
158
|
+
if (eventSourceRef.current) return;
|
|
159
|
+
const url = `${apiUrl}/api/public/signal/stream?token=${encodeURIComponent(credential)}`;
|
|
160
|
+
connectEventSource(url);
|
|
161
|
+
})();
|
|
162
|
+
function connectEventSource(url) {
|
|
163
|
+
const eventSource = new EventSource(url);
|
|
164
|
+
eventSource.addEventListener("config_update", (e) => {
|
|
165
|
+
try {
|
|
166
|
+
const { config: newConfig, version } = JSON.parse(e.data);
|
|
167
|
+
setConfig((prev) => {
|
|
168
|
+
if (prev?.version !== version) {
|
|
169
|
+
if (isDebug()) console.log("[Signal] Config updated to version:", version);
|
|
170
|
+
return newConfig;
|
|
171
|
+
}
|
|
172
|
+
return prev;
|
|
173
|
+
});
|
|
174
|
+
} catch (err) {
|
|
175
|
+
if (isDebug()) console.error("[Signal] SSE parse error:", err);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
eventSource.addEventListener("experiment_update", (e) => {
|
|
179
|
+
try {
|
|
180
|
+
const { experiment_id, action } = JSON.parse(e.data);
|
|
181
|
+
if (action === "started" || action === "updated") {
|
|
182
|
+
loadExperimentAssignment(experiment_id);
|
|
183
|
+
} else if (action === "stopped") {
|
|
184
|
+
assignmentsRef.current.delete(experiment_id);
|
|
185
|
+
}
|
|
186
|
+
} catch (err) {
|
|
187
|
+
if (isDebug()) console.error("[Signal] Experiment update error:", err);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
eventSource.onerror = () => {
|
|
191
|
+
if (isDebug()) console.warn("[Signal] SSE connection error, reconnecting...");
|
|
192
|
+
eventSource.close();
|
|
193
|
+
if (eventSourceRef.current === eventSource) {
|
|
194
|
+
eventSourceRef.current = null;
|
|
195
|
+
}
|
|
196
|
+
setTimeout(connectSSE, 5e3);
|
|
197
|
+
};
|
|
198
|
+
eventSourceRef.current = eventSource;
|
|
199
|
+
}
|
|
181
200
|
}, [apiUrl, apiKey, enabled, realtime, loadExperimentAssignment]);
|
|
182
201
|
const flushEvents = react.useCallback(async () => {
|
|
183
202
|
if (eventQueueRef.current.length === 0) return;
|
|
184
203
|
const events = [...eventQueueRef.current];
|
|
185
204
|
eventQueueRef.current = [];
|
|
186
205
|
try {
|
|
187
|
-
await
|
|
206
|
+
await chunkXY4NJJEX_js.sonorFetch(
|
|
188
207
|
`${apiUrl}/api/public/signal/events`,
|
|
189
208
|
{
|
|
190
209
|
method: "POST",
|
|
@@ -234,7 +253,7 @@ function SignalCore({
|
|
|
234
253
|
const trackOutcome = react.useCallback(async (outcome) => {
|
|
235
254
|
if (!enabled || !apiKey) return;
|
|
236
255
|
try {
|
|
237
|
-
await
|
|
256
|
+
await chunkXY4NJJEX_js.sonorFetch(
|
|
238
257
|
`${apiUrl}/api/public/signal/outcome`,
|
|
239
258
|
{
|
|
240
259
|
method: "POST",
|
|
@@ -309,5 +328,5 @@ function SignalCore({
|
|
|
309
328
|
}
|
|
310
329
|
|
|
311
330
|
exports.SignalCore = SignalCore;
|
|
312
|
-
//# sourceMappingURL=SignalCore-
|
|
313
|
-
//# sourceMappingURL=SignalCore-
|
|
331
|
+
//# sourceMappingURL=SignalCore-DK4HQBPY.js.map
|
|
332
|
+
//# sourceMappingURL=SignalCore-DK4HQBPY.js.map
|
|
@@ -0,0 +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-DK4HQBPY.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,7 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-
|
|
3
|
-
import
|
|
4
|
-
import './chunk-
|
|
2
|
+
import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-AX4AROLH.mjs';
|
|
3
|
+
import './chunk-6EDVCUAG.mjs';
|
|
4
|
+
import { sonorFetch } from './chunk-VX3WK77I.mjs';
|
|
5
|
+
import { getFreshCredential, isSiteToken } from './chunk-BNJH2RFU.mjs';
|
|
6
|
+
import './chunk-QGPYFC6G.mjs';
|
|
5
7
|
import './chunk-4XPGGLVP.mjs';
|
|
6
8
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
7
9
|
|
|
@@ -141,41 +143,58 @@ function SignalCore({
|
|
|
141
143
|
if (!apiKey || !enabled || !realtime) return;
|
|
142
144
|
if (eventSourceRef.current) {
|
|
143
145
|
eventSourceRef.current.close();
|
|
146
|
+
eventSourceRef.current = null;
|
|
144
147
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
setConfig((prev) => {
|
|
151
|
-
if (prev?.version !== version) {
|
|
152
|
-
if (isDebug()) console.log("[Signal] Config updated to version:", version);
|
|
153
|
-
return newConfig;
|
|
154
|
-
}
|
|
155
|
-
return prev;
|
|
156
|
-
});
|
|
157
|
-
} catch (err) {
|
|
158
|
-
if (isDebug()) console.error("[Signal] SSE parse error:", err);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
eventSource.addEventListener("experiment_update", (e) => {
|
|
162
|
-
try {
|
|
163
|
-
const { experiment_id, action } = JSON.parse(e.data);
|
|
164
|
-
if (action === "started" || action === "updated") {
|
|
165
|
-
loadExperimentAssignment(experiment_id);
|
|
166
|
-
} else if (action === "stopped") {
|
|
167
|
-
assignmentsRef.current.delete(experiment_id);
|
|
148
|
+
void (async () => {
|
|
149
|
+
const credential = await getFreshCredential(apiKey);
|
|
150
|
+
if (!credential || !isSiteToken(credential)) {
|
|
151
|
+
if (isDebug()) {
|
|
152
|
+
console.warn("[Signal] Realtime stream disabled: requires site-token mode (raw keys never go in URLs)");
|
|
168
153
|
}
|
|
169
|
-
|
|
170
|
-
if (isDebug()) console.error("[Signal] Experiment update error:", err);
|
|
154
|
+
return;
|
|
171
155
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
156
|
+
if (eventSourceRef.current) return;
|
|
157
|
+
const url = `${apiUrl}/api/public/signal/stream?token=${encodeURIComponent(credential)}`;
|
|
158
|
+
connectEventSource(url);
|
|
159
|
+
})();
|
|
160
|
+
function connectEventSource(url) {
|
|
161
|
+
const eventSource = new EventSource(url);
|
|
162
|
+
eventSource.addEventListener("config_update", (e) => {
|
|
163
|
+
try {
|
|
164
|
+
const { config: newConfig, version } = JSON.parse(e.data);
|
|
165
|
+
setConfig((prev) => {
|
|
166
|
+
if (prev?.version !== version) {
|
|
167
|
+
if (isDebug()) console.log("[Signal] Config updated to version:", version);
|
|
168
|
+
return newConfig;
|
|
169
|
+
}
|
|
170
|
+
return prev;
|
|
171
|
+
});
|
|
172
|
+
} catch (err) {
|
|
173
|
+
if (isDebug()) console.error("[Signal] SSE parse error:", err);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
eventSource.addEventListener("experiment_update", (e) => {
|
|
177
|
+
try {
|
|
178
|
+
const { experiment_id, action } = JSON.parse(e.data);
|
|
179
|
+
if (action === "started" || action === "updated") {
|
|
180
|
+
loadExperimentAssignment(experiment_id);
|
|
181
|
+
} else if (action === "stopped") {
|
|
182
|
+
assignmentsRef.current.delete(experiment_id);
|
|
183
|
+
}
|
|
184
|
+
} catch (err) {
|
|
185
|
+
if (isDebug()) console.error("[Signal] Experiment update error:", err);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
eventSource.onerror = () => {
|
|
189
|
+
if (isDebug()) console.warn("[Signal] SSE connection error, reconnecting...");
|
|
190
|
+
eventSource.close();
|
|
191
|
+
if (eventSourceRef.current === eventSource) {
|
|
192
|
+
eventSourceRef.current = null;
|
|
193
|
+
}
|
|
194
|
+
setTimeout(connectSSE, 5e3);
|
|
195
|
+
};
|
|
196
|
+
eventSourceRef.current = eventSource;
|
|
197
|
+
}
|
|
179
198
|
}, [apiUrl, apiKey, enabled, realtime, loadExperimentAssignment]);
|
|
180
199
|
const flushEvents = useCallback(async () => {
|
|
181
200
|
if (eventQueueRef.current.length === 0) return;
|
|
@@ -307,5 +326,5 @@ function SignalCore({
|
|
|
307
326
|
}
|
|
308
327
|
|
|
309
328
|
export { SignalCore };
|
|
310
|
-
//# sourceMappingURL=SignalCore-
|
|
311
|
-
//# sourceMappingURL=SignalCore-
|
|
329
|
+
//# sourceMappingURL=SignalCore-TW4YA3BW.mjs.map
|
|
330
|
+
//# sourceMappingURL=SignalCore-TW4YA3BW.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/signal/SignalCore.tsx"],"names":[],"mappings":"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","file":"SignalCore-TW4YA3BW.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-2NA5CAK5.mjs';
|
|
2
|
+
import './chunk-QJU6HBSK.mjs';
|
|
3
|
+
import './chunk-VX3WK77I.mjs';
|
|
4
|
+
import './chunk-BNJH2RFU.mjs';
|
|
5
|
+
import './chunk-QGPYFC6G.mjs';
|
|
6
|
+
import './chunk-4XPGGLVP.mjs';
|
|
7
|
+
//# sourceMappingURL=SitemapSync-7PXQMF5A.mjs.map
|
|
8
|
+
//# sourceMappingURL=SitemapSync-7PXQMF5A.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"SitemapSync-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"SitemapSync-7PXQMF5A.mjs"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkCTPE3G5W_js = require('./chunk-CTPE3G5W.js');
|
|
4
|
+
require('./chunk-JEOKDUPQ.js');
|
|
5
|
+
require('./chunk-XY4NJJEX.js');
|
|
6
|
+
require('./chunk-UXEB6UAR.js');
|
|
7
|
+
require('./chunk-NME3SQCB.js');
|
|
8
|
+
require('./chunk-ZSMWDLMK.js');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Object.defineProperty(exports, "SitemapSync", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkCTPE3G5W_js.SitemapSync; }
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=SitemapSync-O3J2DPV7.js.map
|
|
17
|
+
//# sourceMappingURL=SitemapSync-O3J2DPV7.js.map
|