@sonordev/site-kit 4.2.3 → 4.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/agent-manifest.json +1 -1
  2. package/dist/AnalyticsProvider-HVPZPHZI.mjs +10 -0
  3. package/dist/{AnalyticsProvider-NW3UZYL5.mjs.map → AnalyticsProvider-HVPZPHZI.mjs.map} +1 -1
  4. package/dist/AnalyticsProvider-LFSSF7MQ.js +31 -0
  5. package/dist/{AnalyticsProvider-VSTTYP4W.js.map → AnalyticsProvider-LFSSF7MQ.js.map} +1 -1
  6. package/dist/ChatWidget-7E4PLIYQ.mjs +11 -0
  7. package/dist/{ChatWidget-EWQ7LRD4.mjs.map → ChatWidget-7E4PLIYQ.mjs.map} +1 -1
  8. package/dist/ChatWidget-RFVIYV5C.js +20 -0
  9. package/dist/{ChatWidget-BJOE2OSI.js.map → ChatWidget-RFVIYV5C.js.map} +1 -1
  10. package/dist/EngageWidget-LPMSXVT6.js +18 -0
  11. package/dist/{EngageWidget-CZMNLFWI.js.map → EngageWidget-LPMSXVT6.js.map} +1 -1
  12. package/dist/EngageWidget-N7EQGSSL.mjs +9 -0
  13. package/dist/{EngageWidget-F427CI6Y.mjs.map → EngageWidget-N7EQGSSL.mjs.map} +1 -1
  14. package/dist/{FileField-5RVBU3Z4.mjs → FileField-AS6TUTXA.mjs} +5 -5
  15. package/dist/{FileField-5RVBU3Z4.mjs.map → FileField-AS6TUTXA.mjs.map} +1 -1
  16. package/dist/{FileField-Y4ZA7DST.js → FileField-Y7NOLT27.js} +6 -6
  17. package/dist/{FileField-Y4ZA7DST.js.map → FileField-Y7NOLT27.js.map} +1 -1
  18. package/dist/{FormSpotlight-CJPI2MRJ.mjs → FormSpotlight-I6FEUYAA.mjs} +3 -3
  19. package/dist/{FormSpotlight-CJPI2MRJ.mjs.map → FormSpotlight-I6FEUYAA.mjs.map} +1 -1
  20. package/dist/{FormSpotlight-MAEV6SZK.js → FormSpotlight-RMYOXT2T.js} +15 -15
  21. package/dist/{FormSpotlight-MAEV6SZK.js.map → FormSpotlight-RMYOXT2T.js.map} +1 -1
  22. package/dist/{FormStage-D42NAHSN.js → FormStage-44OWEWZM.js} +13 -13
  23. package/dist/{FormStage-D42NAHSN.js.map → FormStage-44OWEWZM.js.map} +1 -1
  24. package/dist/{FormStage-Z7WW3DNA.mjs → FormStage-G3MUJMTC.mjs} +3 -3
  25. package/dist/{FormStage-Z7WW3DNA.mjs.map → FormStage-G3MUJMTC.mjs.map} +1 -1
  26. package/dist/ManagedForm-LVBNVUZE.mjs +14 -0
  27. package/dist/{ManagedForm-A7BROQIN.mjs.map → ManagedForm-LVBNVUZE.mjs.map} +1 -1
  28. package/dist/ManagedForm-YC6WLYVJ.js +23 -0
  29. package/dist/{ManagedForm-Z3Z5Z6OL.js.map → ManagedForm-YC6WLYVJ.js.map} +1 -1
  30. package/dist/{SignalCore-NA6TJFVE.js → SignalCore-AW5VDA4Y.js} +11 -11
  31. package/dist/{SignalCore-NA6TJFVE.js.map → SignalCore-AW5VDA4Y.js.map} +1 -1
  32. package/dist/{SignalCore-77UH6PZ4.mjs → SignalCore-DYBIG4JP.mjs} +5 -5
  33. package/dist/{SignalCore-77UH6PZ4.mjs.map → SignalCore-DYBIG4JP.mjs.map} +1 -1
  34. package/dist/SitemapSync-2JJOGL7D.mjs +8 -0
  35. package/dist/{SitemapSync-EY33A6P4.mjs.map → SitemapSync-2JJOGL7D.mjs.map} +1 -1
  36. package/dist/SitemapSync-S54TSZLM.js +17 -0
  37. package/dist/{SitemapSync-62F6HVAW.js.map → SitemapSync-S54TSZLM.js.map} +1 -1
  38. package/dist/analytics/index.js +9 -9
  39. package/dist/analytics/index.mjs +4 -4
  40. package/dist/{chunk-XOJYGBYF.js → chunk-2MFLOK2I.js} +3 -3
  41. package/dist/{chunk-XOJYGBYF.js.map → chunk-2MFLOK2I.js.map} +1 -1
  42. package/dist/{chunk-3P4HJAZA.mjs → chunk-2MLIU6OJ.mjs} +4 -4
  43. package/dist/{chunk-3P4HJAZA.mjs.map → chunk-2MLIU6OJ.mjs.map} +1 -1
  44. package/dist/{chunk-QJK2X3UK.js → chunk-2XLWCYB3.js} +12 -12
  45. package/dist/{chunk-QJK2X3UK.js.map → chunk-2XLWCYB3.js.map} +1 -1
  46. package/dist/{chunk-ZASFY4NR.mjs → chunk-33OSUHPZ.mjs} +4 -4
  47. package/dist/{chunk-ZASFY4NR.mjs.map → chunk-33OSUHPZ.mjs.map} +1 -1
  48. package/dist/chunk-4JVFWTER.js +8 -0
  49. package/dist/{chunk-S5L73KZQ.js.map → chunk-4JVFWTER.js.map} +1 -1
  50. package/dist/{chunk-N5RTJNMN.js → chunk-5K2CX5LK.js} +6 -6
  51. package/dist/{chunk-N5RTJNMN.js.map → chunk-5K2CX5LK.js.map} +1 -1
  52. package/dist/{chunk-535HXGDU.mjs → chunk-6ZQFCZPW.mjs} +3 -3
  53. package/dist/{chunk-535HXGDU.mjs.map → chunk-6ZQFCZPW.mjs.map} +1 -1
  54. package/dist/{chunk-3DSGMX7P.js → chunk-A7O7IWL7.js} +3 -3
  55. package/dist/{chunk-3DSGMX7P.js.map → chunk-A7O7IWL7.js.map} +1 -1
  56. package/dist/{chunk-WCTOQFAN.js → chunk-ARFWE2EL.js} +14 -14
  57. package/dist/{chunk-WCTOQFAN.js.map → chunk-ARFWE2EL.js.map} +1 -1
  58. package/dist/{chunk-GJKO2TZN.js → chunk-BDDTZJKC.js} +4 -4
  59. package/dist/{chunk-GJKO2TZN.js.map → chunk-BDDTZJKC.js.map} +1 -1
  60. package/dist/{chunk-DZUOLOYS.mjs → chunk-BJW6YR6W.mjs} +3 -3
  61. package/dist/{chunk-DZUOLOYS.mjs.map → chunk-BJW6YR6W.mjs.map} +1 -1
  62. package/dist/{chunk-KL4MV6HK.mjs → chunk-C6CNCDIN.mjs} +3 -3
  63. package/dist/{chunk-KL4MV6HK.mjs.map → chunk-C6CNCDIN.mjs.map} +1 -1
  64. package/dist/{chunk-OHA43BNK.js → chunk-C6HDI464.js} +14 -14
  65. package/dist/{chunk-OHA43BNK.js.map → chunk-C6HDI464.js.map} +1 -1
  66. package/dist/{chunk-NEIUWAAL.js → chunk-CLD3IE6D.js} +5 -5
  67. package/dist/{chunk-NEIUWAAL.js.map → chunk-CLD3IE6D.js.map} +1 -1
  68. package/dist/{chunk-TKVADZFD.mjs → chunk-CPJA5XTO.mjs} +4 -4
  69. package/dist/{chunk-TKVADZFD.mjs.map → chunk-CPJA5XTO.mjs.map} +1 -1
  70. package/dist/{chunk-TFAYDIWM.mjs → chunk-E3F6OOVQ.mjs} +3 -3
  71. package/dist/{chunk-TFAYDIWM.mjs.map → chunk-E3F6OOVQ.mjs.map} +1 -1
  72. package/dist/chunk-EFMPOC6L.mjs +6 -0
  73. package/dist/{chunk-XCFCG46K.mjs.map → chunk-EFMPOC6L.mjs.map} +1 -1
  74. package/dist/{chunk-T6T5IQMN.mjs → chunk-FSSVIYQ7.mjs} +3 -3
  75. package/dist/{chunk-T6T5IQMN.mjs.map → chunk-FSSVIYQ7.mjs.map} +1 -1
  76. package/dist/{chunk-I7ORAWYT.mjs → chunk-HP7V2DI3.mjs} +3 -3
  77. package/dist/{chunk-I7ORAWYT.mjs.map → chunk-HP7V2DI3.mjs.map} +1 -1
  78. package/dist/{chunk-HVDKAR77.js → chunk-ICJ7EU4Z.js} +7 -7
  79. package/dist/{chunk-HVDKAR77.js.map → chunk-ICJ7EU4Z.js.map} +1 -1
  80. package/dist/{chunk-SAR473OC.js → chunk-JHOMOLZA.js} +12 -12
  81. package/dist/{chunk-SAR473OC.js.map → chunk-JHOMOLZA.js.map} +1 -1
  82. package/dist/{chunk-2XRGCDDG.js → chunk-KDWKSL7U.js} +9 -9
  83. package/dist/{chunk-2XRGCDDG.js.map → chunk-KDWKSL7U.js.map} +1 -1
  84. package/dist/{chunk-RDISSFEH.js → chunk-KPSESCYA.js} +15 -15
  85. package/dist/{chunk-RDISSFEH.js.map → chunk-KPSESCYA.js.map} +1 -1
  86. package/dist/{chunk-EHNUPEFY.mjs → chunk-L5GUV4M7.mjs} +7 -7
  87. package/dist/{chunk-EHNUPEFY.mjs.map → chunk-L5GUV4M7.mjs.map} +1 -1
  88. package/dist/{chunk-GDMOAGVS.js → chunk-LSNIDSLQ.js} +18 -18
  89. package/dist/{chunk-GDMOAGVS.js.map → chunk-LSNIDSLQ.js.map} +1 -1
  90. package/dist/{chunk-YWXZ4YLU.js → chunk-LUXCT2NU.js} +4 -4
  91. package/dist/{chunk-YWXZ4YLU.js.map → chunk-LUXCT2NU.js.map} +1 -1
  92. package/dist/{chunk-XA7RBHKT.js → chunk-NK6K4VHD.js} +4 -4
  93. package/dist/{chunk-XA7RBHKT.js.map → chunk-NK6K4VHD.js.map} +1 -1
  94. package/dist/{chunk-7BVZLSUJ.js → chunk-OIY5O3SE.js} +8 -8
  95. package/dist/{chunk-7BVZLSUJ.js.map → chunk-OIY5O3SE.js.map} +1 -1
  96. package/dist/{chunk-MP7ZYKMM.js → chunk-QQCOIGLN.js} +8 -8
  97. package/dist/{chunk-MP7ZYKMM.js.map → chunk-QQCOIGLN.js.map} +1 -1
  98. package/dist/{chunk-M2SEYO5J.js → chunk-RH5WIBIA.js} +5 -5
  99. package/dist/{chunk-M2SEYO5J.js.map → chunk-RH5WIBIA.js.map} +1 -1
  100. package/dist/{chunk-ZAVNGZJZ.js → chunk-SACGTFCK.js} +22 -6
  101. package/dist/chunk-SACGTFCK.js.map +1 -0
  102. package/dist/{chunk-HTLWSCUQ.mjs → chunk-SRJSR6YP.mjs} +22 -6
  103. package/dist/chunk-SRJSR6YP.mjs.map +1 -0
  104. package/dist/{chunk-PTZB4ES3.mjs → chunk-SSRQHRZB.mjs} +8 -8
  105. package/dist/{chunk-PTZB4ES3.mjs.map → chunk-SSRQHRZB.mjs.map} +1 -1
  106. package/dist/{chunk-XR3MDDQT.mjs → chunk-SYR7YSB2.mjs} +3 -3
  107. package/dist/{chunk-XR3MDDQT.mjs.map → chunk-SYR7YSB2.mjs.map} +1 -1
  108. package/dist/{chunk-BN4AL7XB.js → chunk-U7L7FW3K.js} +4 -4
  109. package/dist/{chunk-BN4AL7XB.js.map → chunk-U7L7FW3K.js.map} +1 -1
  110. package/dist/{chunk-6D3HZKTZ.mjs → chunk-UBSZ466T.mjs} +3 -3
  111. package/dist/{chunk-6D3HZKTZ.mjs.map → chunk-UBSZ466T.mjs.map} +1 -1
  112. package/dist/{chunk-RCRDDMUO.mjs → chunk-UHVII7W7.mjs} +3 -3
  113. package/dist/{chunk-RCRDDMUO.mjs.map → chunk-UHVII7W7.mjs.map} +1 -1
  114. package/dist/{chunk-UDNXM6RB.mjs → chunk-ULV3DZ27.mjs} +3 -3
  115. package/dist/{chunk-UDNXM6RB.mjs.map → chunk-ULV3DZ27.mjs.map} +1 -1
  116. package/dist/{chunk-INA4NW3Y.mjs → chunk-UVRB4SQU.mjs} +3 -3
  117. package/dist/{chunk-INA4NW3Y.mjs.map → chunk-UVRB4SQU.mjs.map} +1 -1
  118. package/dist/{chunk-J6HWSJT7.mjs → chunk-V3HJLXAI.mjs} +3 -3
  119. package/dist/{chunk-J6HWSJT7.mjs.map → chunk-V3HJLXAI.mjs.map} +1 -1
  120. package/dist/{chunk-T3HGONNE.mjs → chunk-WX6VKFHW.mjs} +4 -4
  121. package/dist/{chunk-T3HGONNE.mjs.map → chunk-WX6VKFHW.mjs.map} +1 -1
  122. package/dist/{chunk-XWFUQMU6.mjs → chunk-XKBADVXN.mjs} +3 -3
  123. package/dist/{chunk-XWFUQMU6.mjs.map → chunk-XKBADVXN.mjs.map} +1 -1
  124. package/dist/{chunk-FZAAQE4Y.mjs → chunk-XLD6K3BV.mjs} +4 -4
  125. package/dist/{chunk-FZAAQE4Y.mjs.map → chunk-XLD6K3BV.mjs.map} +1 -1
  126. package/dist/{chunk-RRR6Y6Y5.mjs → chunk-XWBQLPTZ.mjs} +4 -4
  127. package/dist/{chunk-RRR6Y6Y5.mjs.map → chunk-XWBQLPTZ.mjs.map} +1 -1
  128. package/dist/{chunk-SL6ZGJVN.mjs → chunk-YDOWCCE2.mjs} +4 -4
  129. package/dist/{chunk-SL6ZGJVN.mjs.map → chunk-YDOWCCE2.mjs.map} +1 -1
  130. package/dist/{chunk-S5UATBC7.js → chunk-YHGMM2XF.js} +14 -14
  131. package/dist/{chunk-S5UATBC7.js.map → chunk-YHGMM2XF.js.map} +1 -1
  132. package/dist/{chunk-JJDY5XXG.js → chunk-YZ6UYIXD.js} +3 -3
  133. package/dist/{chunk-JJDY5XXG.js.map → chunk-YZ6UYIXD.js.map} +1 -1
  134. package/dist/{chunk-MF6XLEX5.js → chunk-ZJNIM4GQ.js} +15 -15
  135. package/dist/{chunk-MF6XLEX5.js.map → chunk-ZJNIM4GQ.js.map} +1 -1
  136. package/dist/cli/index.js +36 -23
  137. package/dist/cli/index.js.map +1 -1
  138. package/dist/cli/index.mjs +29 -16
  139. package/dist/cli/index.mjs.map +1 -1
  140. package/dist/client/index.js +4 -4
  141. package/dist/client/index.mjs +3 -3
  142. package/dist/commerce/index.js +56 -56
  143. package/dist/commerce/index.mjs +5 -5
  144. package/dist/engage/index.js +10 -10
  145. package/dist/engage/index.mjs +7 -7
  146. package/dist/fleet/index.js +8 -8
  147. package/dist/fleet/index.mjs +4 -4
  148. package/dist/forms/index.js +16 -16
  149. package/dist/forms/index.mjs +9 -9
  150. package/dist/forms/server.js +10 -10
  151. package/dist/forms/server.mjs +8 -8
  152. package/dist/forms/static.js +7 -7
  153. package/dist/forms/static.mjs +6 -6
  154. package/dist/images/index.js +11 -11
  155. package/dist/images/index.mjs +4 -4
  156. package/dist/index.js +63 -63
  157. package/dist/index.mjs +9 -9
  158. package/dist/layout/client.js +8 -8
  159. package/dist/layout/client.mjs +7 -7
  160. package/dist/layout/index.js +10 -10
  161. package/dist/layout/index.mjs +8 -8
  162. package/dist/maps/index.js +5 -5
  163. package/dist/maps/index.mjs +3 -3
  164. package/dist/og/config.d.ts +11 -1
  165. package/dist/og/config.d.ts.map +1 -1
  166. package/dist/og/index.js +5 -5
  167. package/dist/og/index.mjs +1 -1
  168. package/dist/og/pages.d.ts.map +1 -1
  169. package/dist/og/template.d.ts.map +1 -1
  170. package/dist/search/index.js +4 -4
  171. package/dist/search/index.mjs +3 -3
  172. package/dist/seo/client.js +5 -5
  173. package/dist/seo/client.mjs +4 -4
  174. package/dist/seo/index.js +5 -5
  175. package/dist/seo/index.mjs +4 -4
  176. package/dist/server/index.js +3 -3
  177. package/dist/server/index.mjs +2 -2
  178. package/dist/shared/version.d.ts +1 -1
  179. package/dist/signal/index.js +11 -11
  180. package/dist/signal/index.mjs +2 -2
  181. package/dist/sync/index.js +16 -16
  182. package/dist/sync/index.mjs +4 -4
  183. package/package.json +1 -1
  184. package/dist/AnalyticsProvider-NW3UZYL5.mjs +0 -10
  185. package/dist/AnalyticsProvider-VSTTYP4W.js +0 -31
  186. package/dist/ChatWidget-BJOE2OSI.js +0 -20
  187. package/dist/ChatWidget-EWQ7LRD4.mjs +0 -11
  188. package/dist/EngageWidget-CZMNLFWI.js +0 -18
  189. package/dist/EngageWidget-F427CI6Y.mjs +0 -9
  190. package/dist/ManagedForm-A7BROQIN.mjs +0 -14
  191. package/dist/ManagedForm-Z3Z5Z6OL.js +0 -23
  192. package/dist/SitemapSync-62F6HVAW.js +0 -17
  193. package/dist/SitemapSync-EY33A6P4.mjs +0 -8
  194. package/dist/chunk-HTLWSCUQ.mjs.map +0 -1
  195. package/dist/chunk-S5L73KZQ.js +0 -8
  196. package/dist/chunk-XCFCG46K.mjs +0 -6
  197. package/dist/chunk-ZAVNGZJZ.js.map +0 -1
@@ -60,7 +60,7 @@ function useSignal() {
60
60
  return react.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
61
61
  }
62
62
  var LazySignalCore = dynamic__default.default(
63
- () => import('./SignalCore-NA6TJFVE.js').then((m) => ({ default: m.SignalCore })),
63
+ () => import('./SignalCore-AW5VDA4Y.js').then((m) => ({ default: m.SignalCore })),
64
64
  { ssr: false }
65
65
  );
66
66
  function SignalBridge({
@@ -172,5 +172,5 @@ exports.useSignalConfig = useSignalConfig;
172
172
  exports.useSignalEvent = useSignalEvent;
173
173
  exports.useSignalExperiment = useSignalExperiment;
174
174
  exports.useSignalOutcome = useSignalOutcome;
175
- //# sourceMappingURL=chunk-JJDY5XXG.js.map
176
- //# sourceMappingURL=chunk-JJDY5XXG.js.map
175
+ //# sourceMappingURL=chunk-YZ6UYIXD.js.map
176
+ //# sourceMappingURL=chunk-YZ6UYIXD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/signal/store.ts","../src/signal/SignalBridge.tsx"],"names":["useSyncExternalStore","dynamic","useState","useRef","useCallback","useMemo","useEffect","jsxs","Fragment","jsx"],"mappings":"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","file":"chunk-JJDY5XXG.js","sourcesContent":["'use client'\n\n/**\n * Signal store — module singleton behind useSignal().\n *\n * 4.0: SignalBridge no longer wraps page children in a React context; it\n * mounts as a childless sibling and publishes its API here. useSignal()\n * subscribes via useSyncExternalStore, so consumers work anywhere in the\n * tree — and BEFORE the bridge mounts, they get a buffering stub whose\n * trackEvent/trackOutcome queue calls that the bridge drains on publish.\n * getExperiment returns null pre-publish, identical to the pre-config\n * `loading` window consumers already handle.\n *\n * Behavior change vs 3.x (major): useSignal() no longer throws outside a\n * SignalBridge. With signal disabled it stays a bounded no-op stub — a\n * one-time debug warning fires instead of a crash.\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type {\n SignalContextValue,\n SignalEvent,\n SignalOutcome,\n} from './types'\n\nconst pendingEvents: Partial<SignalEvent>[] = []\nconst pendingOutcomes: SignalOutcome[] = []\nconst MAX_PENDING = 100\nlet warnedNoBridge = false\n\n/** Frozen pre-bridge stub — stable reference (useSyncExternalStore requirement). */\nconst STUB: SignalContextValue = Object.freeze({\n config: null,\n loading: true,\n error: null,\n trackEvent: (event: Partial<SignalEvent>) => {\n if (pendingEvents.length < MAX_PENDING) pendingEvents.push(event)\n else if (!warnedNoBridge) {\n warnedNoBridge = true\n console.warn('[site-kit] Signal events are queuing but no SignalBridge has mounted — is signal enabled on SiteKitLayout?')\n }\n },\n trackOutcome: (outcome: SignalOutcome) => {\n if (pendingOutcomes.length < MAX_PENDING) pendingOutcomes.push(outcome)\n },\n getExperiment: () => null,\n refreshConfig: async () => {},\n})\n\nlet current: SignalContextValue = STUB\nconst listeners = new Set<() => void>()\n\nfunction emit() {\n for (const l of listeners) l()\n}\n\n/** Bridge-side: publish the live API (called whenever its value changes). */\nexport function publishSignal(value: SignalContextValue): void {\n const firstPublish = current === STUB\n current = value\n if (firstPublish) {\n // Drain calls made before the bridge mounted. The bridge's own trackEvent\n // buffers again internally until SignalCore loads, so nothing is lost.\n pendingEvents.splice(0).forEach(e => value.trackEvent(e))\n pendingOutcomes.splice(0).forEach(o => value.trackOutcome(o))\n }\n emit()\n}\n\n/** Bridge-side: reset on unmount so a remount starts clean (tests, HMR). */\nexport function resetSignal(): void {\n current = STUB\n emit()\n}\n\nfunction subscribe(onChange: () => void) {\n listeners.add(onChange)\n return () => listeners.delete(onChange)\n}\n\nconst getSnapshot = () => current\nconst getServerSnapshot = () => STUB\n\n/**\n * Access Signal (experiments, behavioral events) from anywhere in the tree.\n * No provider required — see module docs for pre-mount buffering semantics.\n */\nexport function useSignal(): SignalContextValue {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)\n}\n","/**\n * @sonordev/site-kit/signal - SignalBridge\n *\n * Central coordination layer for Signal AI integration.\n *\n * Architecture (2026-07 perf release): SignalBridge is a tiny SSR-SAFE context shell. It\n * renders {children} immediately — children server-render and hydrate\n * normally, no ssr:false wrapper — and lazy-loads the heavy machinery\n * (SignalCore: config fetch, SSE streaming, experiment assignment, event\n * queue, behavior tracking) as a CHILDLESS sibling. The core registers its\n * imperative API into the shell on mount; `trackEvent`/`trackOutcome` calls\n * made before the core is ready are buffered and drained on registration.\n *\n * This removes the old failure mode where enabling `signal` de-opted the\n * whole route to client rendering (the same SSR bailout the analytics\n * sibling-mount fixed) — the #1 recommendation of the 2026-07 perf audit.\n *\n * The core is NOT idle-deferred: experiment variants must apply as early as\n * possible, so it starts loading on hydration.\n */\n\n'use client'\n\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport dynamic from 'next/dynamic'\nimport type { SignalCoreApi, SignalCoreState } from './SignalCore'\nimport type {\n SignalConfig,\n SignalContextValue,\n SignalBridgeProps,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// Heavy machinery — loaded client-side only, never wraps content.\nimport { publishSignal, resetSignal, useSignal } from './store'\n\nconst LazySignalCore = dynamic(\n () => import('./SignalCore').then(m => ({ default: m.SignalCore })),\n { ssr: false },\n)\n\n// ============================================\n// Context\n// ============================================\n\n// 4.0: the context is gone. useSignal() reads the module store, so consumers\n// work anywhere in the tree and SignalBridge mounts as a childless sibling.\nexport { useSignal } from './store'\n\n// ============================================\n// SignalBridge Component (shell)\n// ============================================\n\nexport function SignalBridge({\n enabled = true,\n realtime = true,\n experiments = true,\n behaviorTracking = true,\n visitorId: externalVisitorId,\n sessionId: externalSessionId,\n pageMetadataRef,\n children,\n}: SignalBridgeProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const coreRef = useRef<SignalCoreApi | null>(null)\n // Calls made before the core chunk loads are buffered here and drained on\n // registration — consumers can call trackEvent/trackOutcome from first render.\n const pendingEventsRef = useRef<Partial<SignalEvent>[]>([])\n const pendingOutcomesRef = useRef<SignalOutcome[]>([])\n\n const handleState = useCallback((state: SignalCoreState) => {\n setConfig(state.config)\n setLoading(state.loading)\n setError(state.error)\n }, [])\n\n const handleRegister = useCallback((api: SignalCoreApi | null) => {\n coreRef.current = api\n if (api) {\n pendingEventsRef.current.splice(0).forEach(event => api.trackEvent(event))\n pendingOutcomesRef.current.splice(0).forEach(outcome => api.trackOutcome(outcome))\n }\n }, [])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (coreRef.current) {\n coreRef.current.trackEvent(event)\n } else {\n pendingEventsRef.current.push(event)\n }\n }, [])\n\n const trackOutcome = useCallback((outcome: SignalOutcome) => {\n if (coreRef.current) {\n coreRef.current.trackOutcome(outcome)\n } else {\n pendingOutcomesRef.current.push(outcome)\n }\n }, [])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n // null before the core loads — identical to the pre-config-fetch behavior\n // consumers already handle via `loading`.\n return coreRef.current?.getExperiment(experimentId) ?? null\n }, [])\n\n const refreshConfig = useCallback(async () => {\n await coreRef.current?.refreshConfig()\n }, [])\n\n const contextValue = useMemo<SignalContextValue>(() => ({\n config,\n loading,\n error,\n trackEvent,\n trackOutcome,\n getExperiment,\n refreshConfig,\n }), [config, loading, error, trackEvent, trackOutcome, getExperiment, refreshConfig])\n\n // Publish to the module store (drains pre-mount buffered calls on first\n // publish); reset on unmount so tests/HMR start clean.\n useEffect(() => {\n publishSignal(contextValue)\n }, [contextValue])\n useEffect(() => () => resetSignal(), [])\n\n return (\n <>\n {children}\n {enabled && (\n <LazySignalCore\n enabled={enabled}\n realtime={realtime}\n experiments={experiments}\n behaviorTracking={behaviorTracking}\n externalVisitorId={externalVisitorId}\n externalSessionId={externalSessionId}\n pageMetadataRef={pageMetadataRef}\n onRegister={handleRegister}\n onState={handleState}\n />\n )}\n </>\n )\n}\n\n// ============================================\n// Convenience Hooks\n// ============================================\n\n/**\n * Hook to access Signal config\n */\nexport function useSignalConfig(): SignalConfig | null {\n const { config } = useSignal()\n return config\n}\n\n/**\n * Hook for tracking events\n */\nexport function useSignalEvent() {\n const { trackEvent } = useSignal()\n return trackEvent\n}\n\n/**\n * Hook for tracking outcomes/conversions\n */\nexport function useSignalOutcome() {\n const { trackOutcome } = useSignal()\n return { trackOutcome }\n}\n\n/**\n * Hook for experiment assignment\n */\nexport function useSignalExperiment(experimentId: string): {\n assignment: ExperimentAssignment | null\n variant: string | null\n isControl: boolean\n} {\n const { getExperiment, config } = useSignal()\n const assignment = getExperiment(experimentId)\n\n // Check if experiment is running\n const experiment = config?.experiments?.find(e => e.id === experimentId)\n const isRunning = experiment?.status === 'running'\n\n return {\n assignment: isRunning ? assignment : null,\n variant: isRunning && assignment ? assignment.variant_key : null,\n isControl: !assignment || assignment.variant_key === 'control',\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/signal/store.ts","../src/signal/SignalBridge.tsx"],"names":["useSyncExternalStore","dynamic","useState","useRef","useCallback","useMemo","useEffect","jsxs","Fragment","jsx"],"mappings":"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","file":"chunk-YZ6UYIXD.js","sourcesContent":["'use client'\n\n/**\n * Signal store — module singleton behind useSignal().\n *\n * 4.0: SignalBridge no longer wraps page children in a React context; it\n * mounts as a childless sibling and publishes its API here. useSignal()\n * subscribes via useSyncExternalStore, so consumers work anywhere in the\n * tree — and BEFORE the bridge mounts, they get a buffering stub whose\n * trackEvent/trackOutcome queue calls that the bridge drains on publish.\n * getExperiment returns null pre-publish, identical to the pre-config\n * `loading` window consumers already handle.\n *\n * Behavior change vs 3.x (major): useSignal() no longer throws outside a\n * SignalBridge. With signal disabled it stays a bounded no-op stub — a\n * one-time debug warning fires instead of a crash.\n */\n\nimport { useSyncExternalStore } from 'react'\nimport type {\n SignalContextValue,\n SignalEvent,\n SignalOutcome,\n} from './types'\n\nconst pendingEvents: Partial<SignalEvent>[] = []\nconst pendingOutcomes: SignalOutcome[] = []\nconst MAX_PENDING = 100\nlet warnedNoBridge = false\n\n/** Frozen pre-bridge stub — stable reference (useSyncExternalStore requirement). */\nconst STUB: SignalContextValue = Object.freeze({\n config: null,\n loading: true,\n error: null,\n trackEvent: (event: Partial<SignalEvent>) => {\n if (pendingEvents.length < MAX_PENDING) pendingEvents.push(event)\n else if (!warnedNoBridge) {\n warnedNoBridge = true\n console.warn('[site-kit] Signal events are queuing but no SignalBridge has mounted — is signal enabled on SiteKitLayout?')\n }\n },\n trackOutcome: (outcome: SignalOutcome) => {\n if (pendingOutcomes.length < MAX_PENDING) pendingOutcomes.push(outcome)\n },\n getExperiment: () => null,\n refreshConfig: async () => {},\n})\n\nlet current: SignalContextValue = STUB\nconst listeners = new Set<() => void>()\n\nfunction emit() {\n for (const l of listeners) l()\n}\n\n/** Bridge-side: publish the live API (called whenever its value changes). */\nexport function publishSignal(value: SignalContextValue): void {\n const firstPublish = current === STUB\n current = value\n if (firstPublish) {\n // Drain calls made before the bridge mounted. The bridge's own trackEvent\n // buffers again internally until SignalCore loads, so nothing is lost.\n pendingEvents.splice(0).forEach(e => value.trackEvent(e))\n pendingOutcomes.splice(0).forEach(o => value.trackOutcome(o))\n }\n emit()\n}\n\n/** Bridge-side: reset on unmount so a remount starts clean (tests, HMR). */\nexport function resetSignal(): void {\n current = STUB\n emit()\n}\n\nfunction subscribe(onChange: () => void) {\n listeners.add(onChange)\n return () => listeners.delete(onChange)\n}\n\nconst getSnapshot = () => current\nconst getServerSnapshot = () => STUB\n\n/**\n * Access Signal (experiments, behavioral events) from anywhere in the tree.\n * No provider required — see module docs for pre-mount buffering semantics.\n */\nexport function useSignal(): SignalContextValue {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)\n}\n","/**\n * @sonordev/site-kit/signal - SignalBridge\n *\n * Central coordination layer for Signal AI integration.\n *\n * Architecture (2026-07 perf release): SignalBridge is a tiny SSR-SAFE context shell. It\n * renders {children} immediately — children server-render and hydrate\n * normally, no ssr:false wrapper — and lazy-loads the heavy machinery\n * (SignalCore: config fetch, SSE streaming, experiment assignment, event\n * queue, behavior tracking) as a CHILDLESS sibling. The core registers its\n * imperative API into the shell on mount; `trackEvent`/`trackOutcome` calls\n * made before the core is ready are buffered and drained on registration.\n *\n * This removes the old failure mode where enabling `signal` de-opted the\n * whole route to client rendering (the same SSR bailout the analytics\n * sibling-mount fixed) — the #1 recommendation of the 2026-07 perf audit.\n *\n * The core is NOT idle-deferred: experiment variants must apply as early as\n * possible, so it starts loading on hydration.\n */\n\n'use client'\n\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport dynamic from 'next/dynamic'\nimport type { SignalCoreApi, SignalCoreState } from './SignalCore'\nimport type {\n SignalConfig,\n SignalContextValue,\n SignalBridgeProps,\n SignalEvent,\n SignalOutcome,\n ExperimentAssignment,\n} from './types'\n\n// Heavy machinery — loaded client-side only, never wraps content.\nimport { publishSignal, resetSignal, useSignal } from './store'\n\nconst LazySignalCore = dynamic(\n () => import('./SignalCore').then(m => ({ default: m.SignalCore })),\n { ssr: false },\n)\n\n// ============================================\n// Context\n// ============================================\n\n// 4.0: the context is gone. useSignal() reads the module store, so consumers\n// work anywhere in the tree and SignalBridge mounts as a childless sibling.\nexport { useSignal } from './store'\n\n// ============================================\n// SignalBridge Component (shell)\n// ============================================\n\nexport function SignalBridge({\n enabled = true,\n realtime = true,\n experiments = true,\n behaviorTracking = true,\n visitorId: externalVisitorId,\n sessionId: externalSessionId,\n pageMetadataRef,\n children,\n}: SignalBridgeProps) {\n const [config, setConfig] = useState<SignalConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const coreRef = useRef<SignalCoreApi | null>(null)\n // Calls made before the core chunk loads are buffered here and drained on\n // registration — consumers can call trackEvent/trackOutcome from first render.\n const pendingEventsRef = useRef<Partial<SignalEvent>[]>([])\n const pendingOutcomesRef = useRef<SignalOutcome[]>([])\n\n const handleState = useCallback((state: SignalCoreState) => {\n setConfig(state.config)\n setLoading(state.loading)\n setError(state.error)\n }, [])\n\n const handleRegister = useCallback((api: SignalCoreApi | null) => {\n coreRef.current = api\n if (api) {\n pendingEventsRef.current.splice(0).forEach(event => api.trackEvent(event))\n pendingOutcomesRef.current.splice(0).forEach(outcome => api.trackOutcome(outcome))\n }\n }, [])\n\n const trackEvent = useCallback((event: Partial<SignalEvent>) => {\n if (coreRef.current) {\n coreRef.current.trackEvent(event)\n } else {\n pendingEventsRef.current.push(event)\n }\n }, [])\n\n const trackOutcome = useCallback((outcome: SignalOutcome) => {\n if (coreRef.current) {\n coreRef.current.trackOutcome(outcome)\n } else {\n pendingOutcomesRef.current.push(outcome)\n }\n }, [])\n\n const getExperiment = useCallback((experimentId: string): ExperimentAssignment | null => {\n // null before the core loads — identical to the pre-config-fetch behavior\n // consumers already handle via `loading`.\n return coreRef.current?.getExperiment(experimentId) ?? null\n }, [])\n\n const refreshConfig = useCallback(async () => {\n await coreRef.current?.refreshConfig()\n }, [])\n\n const contextValue = useMemo<SignalContextValue>(() => ({\n config,\n loading,\n error,\n trackEvent,\n trackOutcome,\n getExperiment,\n refreshConfig,\n }), [config, loading, error, trackEvent, trackOutcome, getExperiment, refreshConfig])\n\n // Publish to the module store (drains pre-mount buffered calls on first\n // publish); reset on unmount so tests/HMR start clean.\n useEffect(() => {\n publishSignal(contextValue)\n }, [contextValue])\n useEffect(() => () => resetSignal(), [])\n\n return (\n <>\n {children}\n {enabled && (\n <LazySignalCore\n enabled={enabled}\n realtime={realtime}\n experiments={experiments}\n behaviorTracking={behaviorTracking}\n externalVisitorId={externalVisitorId}\n externalSessionId={externalSessionId}\n pageMetadataRef={pageMetadataRef}\n onRegister={handleRegister}\n onState={handleState}\n />\n )}\n </>\n )\n}\n\n// ============================================\n// Convenience Hooks\n// ============================================\n\n/**\n * Hook to access Signal config\n */\nexport function useSignalConfig(): SignalConfig | null {\n const { config } = useSignal()\n return config\n}\n\n/**\n * Hook for tracking events\n */\nexport function useSignalEvent() {\n const { trackEvent } = useSignal()\n return trackEvent\n}\n\n/**\n * Hook for tracking outcomes/conversions\n */\nexport function useSignalOutcome() {\n const { trackOutcome } = useSignal()\n return { trackOutcome }\n}\n\n/**\n * Hook for experiment assignment\n */\nexport function useSignalExperiment(experimentId: string): {\n assignment: ExperimentAssignment | null\n variant: string | null\n isControl: boolean\n} {\n const { getExperiment, config } = useSignal()\n const assignment = getExperiment(experimentId)\n\n // Check if experiment is running\n const experiment = config?.experiments?.find(e => e.id === experimentId)\n const isRunning = experiment?.status === 'running'\n\n return {\n assignment: isRunning ? assignment : null,\n variant: isRunning && assignment ? assignment.variant_key : null,\n isControl: !assignment || assignment.variant_key === 'control',\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkXA7RBHKT_js = require('./chunk-XA7RBHKT.js');
4
- var chunkS5L73KZQ_js = require('./chunk-S5L73KZQ.js');
3
+ var chunkNK6K4VHD_js = require('./chunk-NK6K4VHD.js');
4
+ var chunk4JVFWTER_js = require('./chunk-4JVFWTER.js');
5
5
 
6
6
  // src/shared/fetchWithRetry.ts
7
7
  function backoffDelay(attempt, response) {
@@ -50,7 +50,7 @@ var pausedKeys = (() => {
50
50
  var warnedThisPage = false;
51
51
  function isAuthPaused(credential) {
52
52
  if (typeof window === "undefined") return false;
53
- const id = chunkXA7RBHKT_js.credentialBreakerId(credential);
53
+ const id = chunkNK6K4VHD_js.credentialBreakerId(credential);
54
54
  const until = pausedKeys.get(id);
55
55
  if (!until) return false;
56
56
  if (Date.now() >= until) {
@@ -60,7 +60,7 @@ function isAuthPaused(credential) {
60
60
  return true;
61
61
  }
62
62
  function tripBreaker(credential) {
63
- pausedKeys.set(chunkXA7RBHKT_js.credentialBreakerId(credential), Date.now() + AUTH_BREAK_MS);
63
+ pausedKeys.set(chunkNK6K4VHD_js.credentialBreakerId(credential), Date.now() + AUTH_BREAK_MS);
64
64
  if (!warnedThisPage) {
65
65
  warnedThisPage = true;
66
66
  console.info(
@@ -70,13 +70,13 @@ function tripBreaker(credential) {
70
70
  }
71
71
  async function sonorFetch(url, init = {}, options = {}) {
72
72
  let credential = options.apiKey;
73
- if (credential !== void 0 || chunkXA7RBHKT_js.isTokenMode()) {
74
- credential = await chunkXA7RBHKT_js.getFreshCredential(options.apiKey);
73
+ if (credential !== void 0 || chunkNK6K4VHD_js.isTokenMode()) {
74
+ credential = await chunkNK6K4VHD_js.getFreshCredential(options.apiKey);
75
75
  }
76
76
  const headers = new Headers(init.headers || {});
77
- headers.set("x-sitekit-version", chunkS5L73KZQ_js.SITE_KIT_VERSION);
77
+ headers.set("x-sitekit-version", chunk4JVFWTER_js.SITE_KIT_VERSION);
78
78
  if (credential) {
79
- if (chunkXA7RBHKT_js.isTokenMode()) {
79
+ if (chunkNK6K4VHD_js.isTokenMode()) {
80
80
  headers.set("x-api-key", credential);
81
81
  headers.delete("authorization");
82
82
  } else if (!headers.has("x-api-key")) {
@@ -87,11 +87,11 @@ async function sonorFetch(url, init = {}, options = {}) {
87
87
  return new Response(null, { status: 401, statusText: "sonor-auth-paused" });
88
88
  }
89
89
  let response = await fetchWithRetry(url, { ...init, headers }, options);
90
- if ((response.status === 401 || response.status === 403) && typeof window !== "undefined" && chunkXA7RBHKT_js.isSiteToken(credential)) {
91
- const refreshed = await chunkXA7RBHKT_js.refreshSiteToken();
90
+ if ((response.status === 401 || response.status === 403) && typeof window !== "undefined" && chunkNK6K4VHD_js.isSiteToken(credential)) {
91
+ const refreshed = await chunkNK6K4VHD_js.refreshSiteToken();
92
92
  if (refreshed && refreshed !== credential) {
93
93
  const retryHeaders = new Headers(init.headers || {});
94
- retryHeaders.set("x-sitekit-version", chunkS5L73KZQ_js.SITE_KIT_VERSION);
94
+ retryHeaders.set("x-sitekit-version", chunk4JVFWTER_js.SITE_KIT_VERSION);
95
95
  retryHeaders.set("x-api-key", refreshed);
96
96
  retryHeaders.delete("authorization");
97
97
  credential = refreshed;
@@ -104,7 +104,7 @@ async function sonorFetch(url, init = {}, options = {}) {
104
104
  return response;
105
105
  }
106
106
  function sonorBeacon(url, payload, apiKey) {
107
- const credential = chunkXA7RBHKT_js.currentCredential(apiKey);
107
+ const credential = chunkNK6K4VHD_js.currentCredential(apiKey);
108
108
  const body = typeof payload === "string" ? payload : JSON.stringify(payload);
109
109
  try {
110
110
  void fetch(url, {
@@ -112,7 +112,7 @@ function sonorBeacon(url, payload, apiKey) {
112
112
  keepalive: true,
113
113
  headers: {
114
114
  "Content-Type": "application/json",
115
- "x-sitekit-version": chunkS5L73KZQ_js.SITE_KIT_VERSION,
115
+ "x-sitekit-version": chunk4JVFWTER_js.SITE_KIT_VERSION,
116
116
  ...credential ? { "x-api-key": credential } : {}
117
117
  },
118
118
  body
@@ -130,5 +130,5 @@ function sonorBeacon(url, payload, apiKey) {
130
130
 
131
131
  exports.sonorBeacon = sonorBeacon;
132
132
  exports.sonorFetch = sonorFetch;
133
- //# sourceMappingURL=chunk-MF6XLEX5.js.map
134
- //# sourceMappingURL=chunk-MF6XLEX5.js.map
133
+ //# sourceMappingURL=chunk-ZJNIM4GQ.js.map
134
+ //# sourceMappingURL=chunk-ZJNIM4GQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/fetchWithRetry.ts","../src/shared/sonorFetch.ts"],"names":["credentialBreakerId","isTokenMode","getFreshCredential","SITE_KIT_VERSION","isSiteToken","refreshSiteToken","currentCredential"],"mappings":"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","file":"chunk-MF6XLEX5.js","sourcesContent":["/**\n * @sonordev/site-kit shared - Resilient fetch\n *\n * Single source of truth for client-side resilient fetch (forms, SitemapSync).\n * Adds a per-attempt timeout and retries transient failures (network errors,\n * request timeouts, HTTP 429, and 5xx) with exponential backoff.\n *\n * A form submission must survive a brief API blip — a deploy, a cold start, a\n * dropped packet. A single un-retried fetch turning into \"Something went wrong\"\n * is how leads get lost. The explicit abort also matters on its own: a request\n * left to hang until the browser's own network timeout logs a console error\n * (net::ERR_TIMED_OUT) that fails Lighthouse best-practices; an aborted fetch\n * logs nothing.\n */\n\nexport interface FetchRetryOptions {\n /** Number of retries AFTER the first attempt (default 2 → up to 3 tries total). */\n retries?: number\n /** Per-attempt timeout in milliseconds (default 15000). */\n timeoutMs?: number\n}\n\nfunction backoffDelay(attempt: number, response?: Response): number {\n // Honor a Retry-After header on 429 responses when present.\n if (response?.status === 429) {\n const header = response.headers.get('retry-after')\n const seconds = header ? parseInt(header, 10) : NaN\n if (!Number.isNaN(seconds) && seconds > 0) return Math.min(seconds * 1000, 10000)\n }\n // Exponential backoff: 500ms, 1s, 2s, ... capped at 8s.\n return Math.min(8000, 500 * 2 ** attempt)\n}\n\n/**\n * fetch() with a timeout and automatic retries for transient failures.\n *\n * Non-transient responses (2xx, 3xx, and 4xx other than 429) are returned to\n * the caller as-is — only 429/5xx and thrown network/timeout errors are retried.\n * If every attempt fails with a thrown error, the last error is re-thrown.\n */\nexport async function fetchWithRetry(\n url: string,\n init: RequestInit,\n options: FetchRetryOptions = {},\n): Promise<Response> {\n const retries = options.retries ?? 2\n const timeoutMs = options.timeoutMs ?? 15000\n let lastError: unknown\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n const response = await fetch(url, { ...init, signal: controller.signal })\n clearTimeout(timer)\n\n if ((response.status === 429 || response.status >= 500) && attempt < retries) {\n await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt, response)))\n continue\n }\n return response\n } catch (error) {\n clearTimeout(timer)\n lastError = error\n // Network failure or timeout (AbortController) — retry while attempts remain.\n if (attempt < retries) {\n await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt)))\n continue\n }\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error('Network request failed after multiple attempts. Please try again.')\n}\n","/**\n * @sonordev/site-kit shared - Canonical client transport\n *\n * Single source of truth for how site-kit talks to Sonor from the browser.\n * Every client-side module (analytics, forms, commerce, engage, maps, images,\n * SitemapSync) routes through here instead of bare fetch(), which gives the\n * whole kit, in one place:\n *\n * - per-attempt timeout + retry with backoff (via fetchWithRetry) — a hung\n * request left to the browser's own network timeout logs a console error\n * (net::ERR_TIMED_OUT) that fails Lighthouse best-practices\n * - the x-sitekit-version header on every request, so the platform can see\n * which kit version each site actually runs from live traffic\n * - CREDENTIAL LIFECYCLE: sites on 3.2+ ship a short-lived minted token instead\n * of the raw key. This transport resolves the freshest token (refreshing a\n * stale seed transparently), and on a 401/403 for a token it refreshes once\n * and retries before giving up. A raw key (2.x kit, or the mint-failed\n * fallback) is a pure passthrough — legacy behavior is unchanged.\n * - an auth circuit breaker: after a 401/403 the credential is paused for a few\n * minutes and ONE friendly console.info is emitted — a site on a stale or\n * canceled key must not spam the API or the visitor's console. Keyed by the\n * project (from the token) so it survives token rotation.\n * - sonorBeacon for unload-time telemetry that keeps the credential in headers;\n * navigator.sendBeacon can't set headers and forced the key into the URL,\n * where server and CDN access logs capture it\n *\n * Non-idempotent endpoints (checkout, payment intents, uploads) must pass\n * { retries: 0 } — they still get the timeout, but never an automatic retry.\n */\nimport { fetchWithRetry, type FetchRetryOptions } from './fetchWithRetry'\nimport { SITE_KIT_VERSION } from './version'\nimport {\n credentialBreakerId,\n currentCredential,\n getFreshCredential,\n isSiteToken,\n isTokenMode,\n refreshSiteToken,\n} from './siteToken'\n\nexport interface SonorFetchOptions extends FetchRetryOptions {\n /** Project credential — the minted token (3.2+) or raw key. Sent as x-api-key. */\n apiKey?: string\n}\n\n/** How long a credential stays paused after an auth failure. */\nconst AUTH_BREAK_MS = 5 * 60_000\n\n// breaker id → epoch ms until which requests are paused. Shared on window for\n// the same reason as the token state (see siteToken.ts): duplicated module\n// copies must trip and observe ONE breaker, not one each. Never applies on the\n// server, so a per-module Map there is fine.\nconst BREAKER_STATE_KEY = '__SONOR_AUTH_BREAKER__'\nconst pausedKeys: Map<string, number> = (() => {\n if (typeof window === 'undefined') return new Map()\n const w = window as unknown as Record<string, Map<string, number> | undefined>\n return (w[BREAKER_STATE_KEY] ??= new Map())\n})()\nlet warnedThisPage = false\n\n/** True when a previous 401/403 has paused this credential (browser only). */\nexport function isAuthPaused(credential?: string): boolean {\n if (typeof window === 'undefined') return false\n const id = credentialBreakerId(credential)\n const until = pausedKeys.get(id)\n if (!until) return false\n if (Date.now() >= until) {\n pausedKeys.delete(id)\n return false\n }\n return true\n}\n\nfunction tripBreaker(credential?: string): void {\n pausedKeys.set(credentialBreakerId(credential), Date.now() + AUTH_BREAK_MS)\n if (!warnedThisPage) {\n warnedThisPage = true\n // info, not error: a visitor's console must stay clean (Lighthouse\n // errors-in-console), and copy never names env vars or key formats.\n console.info(\n \"[Sonor] This site couldn't authenticate with Sonor, so data features are paused for a few minutes. If this keeps happening, the site is likely running an outdated API key.\",\n )\n }\n}\n\nexport async function sonorFetch(\n url: string,\n init: RequestInit = {},\n options: SonorFetchOptions = {},\n): Promise<Response> {\n // Resolve the credential to send. In token mode this may transparently refresh\n // a stale seed before the first request; in raw-key mode it's a passthrough.\n let credential = options.apiKey\n if (credential !== undefined || isTokenMode()) {\n credential = await getFreshCredential(options.apiKey)\n }\n\n const headers = new Headers(init.headers || {})\n headers.set('x-sitekit-version', SITE_KIT_VERSION)\n if (credential) {\n if (isTokenMode()) {\n // Token mode: `credential` is the freshest token (refreshed just above if\n // the seed was stale). It MUST override any x-api-key a caller hand-set — a\n // stale build-time seed passed as a header would otherwise pin the request\n // and defeat refresh entirely. Also drop a caller-set Authorization:\n // extractApiKey() server-side prefers `Authorization: Bearer` over\n // x-api-key, so a stale Bearer seed would win even once we set a fresh\n // x-api-key. This is the single place the client credential is chosen — do\n // not re-attach it as a header at call sites.\n headers.set('x-api-key', credential)\n headers.delete('authorization')\n } else if (!headers.has('x-api-key')) {\n // Raw-key mode: legacy passthrough — respect a caller-supplied header.\n headers.set('x-api-key', credential)\n }\n }\n\n if (isAuthPaused(credential)) {\n // Synthetic response keeps every caller's !response.ok path working\n // without a network round trip while the breaker is open.\n return new Response(null, { status: 401, statusText: 'sonor-auth-paused' })\n }\n\n let response = await fetchWithRetry(url, { ...init, headers }, options)\n\n // A token can rotate or expire mid-session. On the first auth failure, try ONE\n // refresh + retry before tripping the breaker — only for token credentials\n // (raw keys have nothing to refresh).\n if (\n (response.status === 401 || response.status === 403) &&\n typeof window !== 'undefined' &&\n isSiteToken(credential)\n ) {\n const refreshed = await refreshSiteToken()\n if (refreshed && refreshed !== credential) {\n const retryHeaders = new Headers(init.headers || {})\n retryHeaders.set('x-sitekit-version', SITE_KIT_VERSION)\n retryHeaders.set('x-api-key', refreshed)\n // Same reason as the initial request: a caller-set stale Bearer would win\n // over our fresh x-api-key server-side, so strip it on the retry too.\n retryHeaders.delete('authorization')\n credential = refreshed\n response = await fetchWithRetry(url, { ...init, headers: retryHeaders }, options)\n }\n }\n\n if (\n (response.status === 401 || response.status === 403) &&\n typeof window !== 'undefined' &&\n credential\n ) {\n tripBreaker(credential)\n }\n\n return response\n}\n\n/**\n * Fire-and-forget telemetry that survives page unload.\n *\n * Uses fetch({ keepalive: true }) so auth travels in headers. Falls back to\n * navigator.sendBeacon (no auth headers possible — the server may reject it,\n * but we never put the key in the URL) only when keepalive fetch is missing.\n *\n * Cannot await a refresh at unload time, so it sends the freshest token already\n * held (currentCredential) rather than the possibly-stale seed the caller passed.\n */\nexport function sonorBeacon(url: string, payload: unknown, apiKey?: string): void {\n const credential = currentCredential(apiKey)\n const body = typeof payload === 'string' ? payload : JSON.stringify(payload)\n try {\n void fetch(url, {\n method: 'POST',\n keepalive: true,\n headers: {\n 'Content-Type': 'application/json',\n 'x-sitekit-version': SITE_KIT_VERSION,\n ...(credential ? { 'x-api-key': credential } : {}),\n },\n body,\n }).catch(() => {\n /* page is closing — best effort */\n })\n } catch {\n try {\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n navigator.sendBeacon(url, new Blob([body], { type: 'application/json' }))\n }\n } catch {\n /* nothing left to try */\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/fetchWithRetry.ts","../src/shared/sonorFetch.ts"],"names":["credentialBreakerId","isTokenMode","getFreshCredential","SITE_KIT_VERSION","isSiteToken","refreshSiteToken","currentCredential"],"mappings":"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","file":"chunk-ZJNIM4GQ.js","sourcesContent":["/**\n * @sonordev/site-kit shared - Resilient fetch\n *\n * Single source of truth for client-side resilient fetch (forms, SitemapSync).\n * Adds a per-attempt timeout and retries transient failures (network errors,\n * request timeouts, HTTP 429, and 5xx) with exponential backoff.\n *\n * A form submission must survive a brief API blip — a deploy, a cold start, a\n * dropped packet. A single un-retried fetch turning into \"Something went wrong\"\n * is how leads get lost. The explicit abort also matters on its own: a request\n * left to hang until the browser's own network timeout logs a console error\n * (net::ERR_TIMED_OUT) that fails Lighthouse best-practices; an aborted fetch\n * logs nothing.\n */\n\nexport interface FetchRetryOptions {\n /** Number of retries AFTER the first attempt (default 2 → up to 3 tries total). */\n retries?: number\n /** Per-attempt timeout in milliseconds (default 15000). */\n timeoutMs?: number\n}\n\nfunction backoffDelay(attempt: number, response?: Response): number {\n // Honor a Retry-After header on 429 responses when present.\n if (response?.status === 429) {\n const header = response.headers.get('retry-after')\n const seconds = header ? parseInt(header, 10) : NaN\n if (!Number.isNaN(seconds) && seconds > 0) return Math.min(seconds * 1000, 10000)\n }\n // Exponential backoff: 500ms, 1s, 2s, ... capped at 8s.\n return Math.min(8000, 500 * 2 ** attempt)\n}\n\n/**\n * fetch() with a timeout and automatic retries for transient failures.\n *\n * Non-transient responses (2xx, 3xx, and 4xx other than 429) are returned to\n * the caller as-is — only 429/5xx and thrown network/timeout errors are retried.\n * If every attempt fails with a thrown error, the last error is re-thrown.\n */\nexport async function fetchWithRetry(\n url: string,\n init: RequestInit,\n options: FetchRetryOptions = {},\n): Promise<Response> {\n const retries = options.retries ?? 2\n const timeoutMs = options.timeoutMs ?? 15000\n let lastError: unknown\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n const response = await fetch(url, { ...init, signal: controller.signal })\n clearTimeout(timer)\n\n if ((response.status === 429 || response.status >= 500) && attempt < retries) {\n await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt, response)))\n continue\n }\n return response\n } catch (error) {\n clearTimeout(timer)\n lastError = error\n // Network failure or timeout (AbortController) — retry while attempts remain.\n if (attempt < retries) {\n await new Promise((resolve) => setTimeout(resolve, backoffDelay(attempt)))\n continue\n }\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error('Network request failed after multiple attempts. Please try again.')\n}\n","/**\n * @sonordev/site-kit shared - Canonical client transport\n *\n * Single source of truth for how site-kit talks to Sonor from the browser.\n * Every client-side module (analytics, forms, commerce, engage, maps, images,\n * SitemapSync) routes through here instead of bare fetch(), which gives the\n * whole kit, in one place:\n *\n * - per-attempt timeout + retry with backoff (via fetchWithRetry) — a hung\n * request left to the browser's own network timeout logs a console error\n * (net::ERR_TIMED_OUT) that fails Lighthouse best-practices\n * - the x-sitekit-version header on every request, so the platform can see\n * which kit version each site actually runs from live traffic\n * - CREDENTIAL LIFECYCLE: sites on 3.2+ ship a short-lived minted token instead\n * of the raw key. This transport resolves the freshest token (refreshing a\n * stale seed transparently), and on a 401/403 for a token it refreshes once\n * and retries before giving up. A raw key (2.x kit, or the mint-failed\n * fallback) is a pure passthrough — legacy behavior is unchanged.\n * - an auth circuit breaker: after a 401/403 the credential is paused for a few\n * minutes and ONE friendly console.info is emitted — a site on a stale or\n * canceled key must not spam the API or the visitor's console. Keyed by the\n * project (from the token) so it survives token rotation.\n * - sonorBeacon for unload-time telemetry that keeps the credential in headers;\n * navigator.sendBeacon can't set headers and forced the key into the URL,\n * where server and CDN access logs capture it\n *\n * Non-idempotent endpoints (checkout, payment intents, uploads) must pass\n * { retries: 0 } — they still get the timeout, but never an automatic retry.\n */\nimport { fetchWithRetry, type FetchRetryOptions } from './fetchWithRetry'\nimport { SITE_KIT_VERSION } from './version'\nimport {\n credentialBreakerId,\n currentCredential,\n getFreshCredential,\n isSiteToken,\n isTokenMode,\n refreshSiteToken,\n} from './siteToken'\n\nexport interface SonorFetchOptions extends FetchRetryOptions {\n /** Project credential — the minted token (3.2+) or raw key. Sent as x-api-key. */\n apiKey?: string\n}\n\n/** How long a credential stays paused after an auth failure. */\nconst AUTH_BREAK_MS = 5 * 60_000\n\n// breaker id → epoch ms until which requests are paused. Shared on window for\n// the same reason as the token state (see siteToken.ts): duplicated module\n// copies must trip and observe ONE breaker, not one each. Never applies on the\n// server, so a per-module Map there is fine.\nconst BREAKER_STATE_KEY = '__SONOR_AUTH_BREAKER__'\nconst pausedKeys: Map<string, number> = (() => {\n if (typeof window === 'undefined') return new Map()\n const w = window as unknown as Record<string, Map<string, number> | undefined>\n return (w[BREAKER_STATE_KEY] ??= new Map())\n})()\nlet warnedThisPage = false\n\n/** True when a previous 401/403 has paused this credential (browser only). */\nexport function isAuthPaused(credential?: string): boolean {\n if (typeof window === 'undefined') return false\n const id = credentialBreakerId(credential)\n const until = pausedKeys.get(id)\n if (!until) return false\n if (Date.now() >= until) {\n pausedKeys.delete(id)\n return false\n }\n return true\n}\n\nfunction tripBreaker(credential?: string): void {\n pausedKeys.set(credentialBreakerId(credential), Date.now() + AUTH_BREAK_MS)\n if (!warnedThisPage) {\n warnedThisPage = true\n // info, not error: a visitor's console must stay clean (Lighthouse\n // errors-in-console), and copy never names env vars or key formats.\n console.info(\n \"[Sonor] This site couldn't authenticate with Sonor, so data features are paused for a few minutes. If this keeps happening, the site is likely running an outdated API key.\",\n )\n }\n}\n\nexport async function sonorFetch(\n url: string,\n init: RequestInit = {},\n options: SonorFetchOptions = {},\n): Promise<Response> {\n // Resolve the credential to send. In token mode this may transparently refresh\n // a stale seed before the first request; in raw-key mode it's a passthrough.\n let credential = options.apiKey\n if (credential !== undefined || isTokenMode()) {\n credential = await getFreshCredential(options.apiKey)\n }\n\n const headers = new Headers(init.headers || {})\n headers.set('x-sitekit-version', SITE_KIT_VERSION)\n if (credential) {\n if (isTokenMode()) {\n // Token mode: `credential` is the freshest token (refreshed just above if\n // the seed was stale). It MUST override any x-api-key a caller hand-set — a\n // stale build-time seed passed as a header would otherwise pin the request\n // and defeat refresh entirely. Also drop a caller-set Authorization:\n // extractApiKey() server-side prefers `Authorization: Bearer` over\n // x-api-key, so a stale Bearer seed would win even once we set a fresh\n // x-api-key. This is the single place the client credential is chosen — do\n // not re-attach it as a header at call sites.\n headers.set('x-api-key', credential)\n headers.delete('authorization')\n } else if (!headers.has('x-api-key')) {\n // Raw-key mode: legacy passthrough — respect a caller-supplied header.\n headers.set('x-api-key', credential)\n }\n }\n\n if (isAuthPaused(credential)) {\n // Synthetic response keeps every caller's !response.ok path working\n // without a network round trip while the breaker is open.\n return new Response(null, { status: 401, statusText: 'sonor-auth-paused' })\n }\n\n let response = await fetchWithRetry(url, { ...init, headers }, options)\n\n // A token can rotate or expire mid-session. On the first auth failure, try ONE\n // refresh + retry before tripping the breaker — only for token credentials\n // (raw keys have nothing to refresh).\n if (\n (response.status === 401 || response.status === 403) &&\n typeof window !== 'undefined' &&\n isSiteToken(credential)\n ) {\n const refreshed = await refreshSiteToken()\n if (refreshed && refreshed !== credential) {\n const retryHeaders = new Headers(init.headers || {})\n retryHeaders.set('x-sitekit-version', SITE_KIT_VERSION)\n retryHeaders.set('x-api-key', refreshed)\n // Same reason as the initial request: a caller-set stale Bearer would win\n // over our fresh x-api-key server-side, so strip it on the retry too.\n retryHeaders.delete('authorization')\n credential = refreshed\n response = await fetchWithRetry(url, { ...init, headers: retryHeaders }, options)\n }\n }\n\n if (\n (response.status === 401 || response.status === 403) &&\n typeof window !== 'undefined' &&\n credential\n ) {\n tripBreaker(credential)\n }\n\n return response\n}\n\n/**\n * Fire-and-forget telemetry that survives page unload.\n *\n * Uses fetch({ keepalive: true }) so auth travels in headers. Falls back to\n * navigator.sendBeacon (no auth headers possible — the server may reject it,\n * but we never put the key in the URL) only when keepalive fetch is missing.\n *\n * Cannot await a refresh at unload time, so it sends the freshest token already\n * held (currentCredential) rather than the possibly-stale seed the caller passed.\n */\nexport function sonorBeacon(url: string, payload: unknown, apiKey?: string): void {\n const credential = currentCredential(apiKey)\n const body = typeof payload === 'string' ? payload : JSON.stringify(payload)\n try {\n void fetch(url, {\n method: 'POST',\n keepalive: true,\n headers: {\n 'Content-Type': 'application/json',\n 'x-sitekit-version': SITE_KIT_VERSION,\n ...(credential ? { 'x-api-key': credential } : {}),\n },\n body,\n }).catch(() => {\n /* page is closing — best effort */\n })\n } catch {\n try {\n if (typeof navigator !== 'undefined' && navigator.sendBeacon) {\n navigator.sendBeacon(url, new Blob([body], { type: 'application/json' }))\n }\n } catch {\n /* nothing left to try */\n }\n }\n}\n"]}
package/dist/cli/index.js CHANGED
@@ -3,10 +3,10 @@
3
3
 
4
4
  var chunkJS75ORH7_js = require('../chunk-JS75ORH7.js');
5
5
  var chunkI7AZC5ZQ_js = require('../chunk-I7AZC5ZQ.js');
6
- var chunkZAVNGZJZ_js = require('../chunk-ZAVNGZJZ.js');
6
+ var chunkSACGTFCK_js = require('../chunk-SACGTFCK.js');
7
7
  var chunkNN2YE5WT_js = require('../chunk-NN2YE5WT.js');
8
8
  var chunkLOS5D6B3_js = require('../chunk-LOS5D6B3.js');
9
- var chunkS5L73KZQ_js = require('../chunk-S5L73KZQ.js');
9
+ var chunk4JVFWTER_js = require('../chunk-4JVFWTER.js');
10
10
  var chunkSNAQBZPT_js = require('../chunk-SNAQBZPT.js');
11
11
  var events = require('events');
12
12
  var childProcess = require('child_process');
@@ -13543,7 +13543,7 @@ function buildEnvelope(input, nowMs = Date.now()) {
13543
13543
  ok: exitCode === 0 /* OK */,
13544
13544
  command,
13545
13545
  schemaVersion: 1,
13546
- siteKitVersion: chunkS5L73KZQ_js.SITE_KIT_VERSION,
13546
+ siteKitVersion: chunk4JVFWTER_js.SITE_KIT_VERSION,
13547
13547
  exitCode,
13548
13548
  status: statusForCode(exitCode),
13549
13549
  summary,
@@ -27273,8 +27273,17 @@ function clampSubtitle(text, max = 100) {
27273
27273
  if (flat.length <= max) return flat;
27274
27274
  const sentence = flat.slice(0, max + 1).match(/^.*[.!?](?=\s|$)/)?.[0];
27275
27275
  if (sentence && sentence.length >= 30) return sentence.trim();
27276
- const cut = flat.slice(0, flat.lastIndexOf(" ", max) || max).trim();
27277
- return `${cut.replace(/[.,;:!?…]+$/, "")}\u2026`;
27276
+ return void 0;
27277
+ }
27278
+ function kickerIsRedundant(kicker, title) {
27279
+ if (!kicker) return false;
27280
+ const norm = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
27281
+ const k2 = norm(kicker);
27282
+ const t = norm(title);
27283
+ if (!k2) return true;
27284
+ if (t.includes(k2) || k2.includes(t)) return true;
27285
+ const titleWords = new Set(t.split(" "));
27286
+ return k2.split(" ").every((w) => titleWords.has(w));
27278
27287
  }
27279
27288
  function slugForPath(path27) {
27280
27289
  const trimmed = path27.replace(/^\/+|\/+$/g, "");
@@ -27283,18 +27292,22 @@ function slugForPath(path27) {
27283
27292
  }
27284
27293
  function pageCardConfig(base, route, brand) {
27285
27294
  const override = base.cards?.[route.path] ?? base.cards?.[slugForPath(route.path)];
27286
- const title = route.title ? stripBrandSuffix(route.title, brand) : titleFromPath(route.path);
27287
- const derived = {
27288
- ...base,
27289
- // `cards` is a build-time instruction, not part of a rendered card.
27290
- cards: void 0,
27291
- content: {
27292
- ...base.content,
27293
- kicker: kickerFromPath(route.path, base.content.kicker),
27294
- title,
27295
- subtitle: clampSubtitle(route.description) ?? base.content.subtitle
27296
- }
27297
- };
27295
+ const isHome = route.path === "/";
27296
+ const derived = isHome ? { ...base, cards: void 0 } : (() => {
27297
+ const title = route.title ? stripBrandSuffix(route.title, brand) : titleFromPath(route.path);
27298
+ const kicker = kickerFromPath(route.path, base.content.kicker);
27299
+ return {
27300
+ ...base,
27301
+ // `cards` is a build-time instruction, not part of a rendered card.
27302
+ cards: void 0,
27303
+ content: {
27304
+ ...base.content,
27305
+ kicker: kickerIsRedundant(kicker, title) ? void 0 : kicker,
27306
+ title,
27307
+ subtitle: clampSubtitle(route.description) ?? base.content.subtitle
27308
+ }
27309
+ };
27310
+ })();
27298
27311
  if (!override) return derived;
27299
27312
  return {
27300
27313
  ...derived,
@@ -27384,7 +27397,7 @@ async function renderCard(config2, outPath, cwd, chrome, tmpSuffix) {
27384
27397
  const tmpHtml = path10__default.default.join(cwd, `.sonor-og-${tmpSuffix}.html`);
27385
27398
  try {
27386
27399
  await fs3__default.default.mkdir(path10__default.default.dirname(outPath), { recursive: true });
27387
- await fs3__default.default.writeFile(tmpHtml, inlinePublicPaths(chunkZAVNGZJZ_js.buildOgHtml(config2), cwd));
27400
+ await fs3__default.default.writeFile(tmpHtml, inlinePublicPaths(chunkSACGTFCK_js.buildOgHtml(config2), cwd));
27388
27401
  const { stdout } = await execFileAsync5(
27389
27402
  chrome,
27390
27403
  [
@@ -27405,15 +27418,15 @@ async function renderCard(config2, outPath, cwd, chrome, tmpSuffix) {
27405
27418
  }
27406
27419
  }
27407
27420
  function parseReport(dom) {
27408
- const raw = dom.match(new RegExp(`${chunkZAVNGZJZ_js.OG_REPORT_ATTR}="([^"]*)"`))?.[1];
27421
+ const raw = dom.match(new RegExp(`${chunkSACGTFCK_js.OG_REPORT_ATTR}="([^"]*)"`))?.[1];
27409
27422
  if (!raw) {
27410
- return { fits: true, titlePx: chunkZAVNGZJZ_js.TITLE_MAX_PX, issues: ["card rendered but could not be measured (fitter did not run)"] };
27423
+ return { fits: true, titlePx: chunkSACGTFCK_js.TITLE_MAX_PX, issues: ["card rendered but could not be measured (fitter did not run)"] };
27411
27424
  }
27412
27425
  try {
27413
27426
  const decoded = raw.replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
27414
27427
  return JSON.parse(decoded);
27415
27428
  } catch {
27416
- return { fits: true, titlePx: chunkZAVNGZJZ_js.TITLE_MAX_PX, issues: ["card rendered but the fit report was unreadable"] };
27429
+ return { fits: true, titlePx: chunkSACGTFCK_js.TITLE_MAX_PX, issues: ["card rendered but the fit report was unreadable"] };
27417
27430
  }
27418
27431
  }
27419
27432
  async function compressCard(pngPath, cwd) {
@@ -27485,7 +27498,7 @@ async function resolveRouteCopy(paths) {
27485
27498
  }
27486
27499
  function reportCard(label, report) {
27487
27500
  if (report.fits && !report.issues.length) {
27488
- const shrunk = report.titlePx < chunkZAVNGZJZ_js.TITLE_MAX_PX ? source_default.gray(` (title fitted to ${report.titlePx}px)`) : "";
27501
+ const shrunk = report.titlePx < chunkSACGTFCK_js.TITLE_MAX_PX ? source_default.gray(` (title fitted to ${report.titlePx}px)`) : "";
27489
27502
  console.log(` ${source_default.green("\u2713")} ${label}${shrunk}`);
27490
27503
  return true;
27491
27504
  }
@@ -32391,7 +32404,7 @@ async function geoCommand(options) {
32391
32404
  (0, import_dotenv.config)({ path: ".env.local", quiet: true });
32392
32405
  (0, import_dotenv.config)({ path: ".env", quiet: true });
32393
32406
  var program2 = new Command();
32394
- program2.name("sonor-setup").description("Setup + verification toolchain for @sonordev/site-kit").version(chunkS5L73KZQ_js.SITE_KIT_VERSION);
32407
+ program2.name("sonor-setup").description("Setup + verification toolchain for @sonordev/site-kit").version(chunk4JVFWTER_js.SITE_KIT_VERSION);
32395
32408
  withAgentFlags(
32396
32409
  program2.command("verify").description("Verify the integration actually works (health + key + SSR) \u2014 exit 0 = done").option("--url <url>", "Verify a running/deployed URL server-renders (recommended for agents)").option("--offline", "Skip the network key-validity ping").option("--strict", "Treat warnings as failures")
32397
32410
  ).action(verifyCommand);