@sonordev/site-kit 5.7.0 → 5.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (752) hide show
  1. package/README.md +3 -3
  2. package/agent-manifest.json +14 -2
  3. package/dist/AnalyticsProvider-ERNSZ4DH.mjs +12 -0
  4. package/dist/{AnalyticsProvider-EWF7JN2X.mjs.map → AnalyticsProvider-ERNSZ4DH.mjs.map} +1 -1
  5. package/dist/AnalyticsProvider-HE6V5UJD.js +33 -0
  6. package/dist/{AnalyticsProvider-GJFG7YXA.js.map → AnalyticsProvider-HE6V5UJD.js.map} +1 -1
  7. package/dist/{BlogViewTracker-CKYG6MYU.mjs → BlogViewTracker-2NQ5LBVR.mjs} +13 -10
  8. package/dist/BlogViewTracker-2NQ5LBVR.mjs.map +1 -0
  9. package/dist/{BlogViewTracker-2D3IJPJK.js → BlogViewTracker-4OGWSC2Q.js} +14 -11
  10. package/dist/BlogViewTracker-4OGWSC2Q.js.map +1 -0
  11. package/dist/ChatWidget-67CHHONZ.js +24 -0
  12. package/dist/{ChatWidget-AWP6GBVW.js.map → ChatWidget-67CHHONZ.js.map} +1 -1
  13. package/dist/ChatWidget-T4RICLLT.mjs +15 -0
  14. package/dist/{ChatWidget-Z5QXDZP3.mjs.map → ChatWidget-T4RICLLT.mjs.map} +1 -1
  15. package/dist/EngageWidget-TDW2ZI3Q.js +21 -0
  16. package/dist/{EngageWidget-VT4DYXVO.js.map → EngageWidget-TDW2ZI3Q.js.map} +1 -1
  17. package/dist/EngageWidget-WXEQTV4X.mjs +12 -0
  18. package/dist/{EngageWidget-BKEY5TPO.mjs.map → EngageWidget-WXEQTV4X.mjs.map} +1 -1
  19. package/dist/{FileField-62ZWZMQK.js → FileField-DEVOXJSO.js} +6 -6
  20. package/dist/{FileField-62ZWZMQK.js.map → FileField-DEVOXJSO.js.map} +1 -1
  21. package/dist/{FileField-JJN5QKDL.mjs → FileField-Y5YM365S.mjs} +5 -5
  22. package/dist/{FileField-JJN5QKDL.mjs.map → FileField-Y5YM365S.mjs.map} +1 -1
  23. package/dist/{FormSpotlight-URS4XRS7.js → FormSpotlight-4Q5FM3YS.js} +25 -21
  24. package/dist/FormSpotlight-4Q5FM3YS.js.map +1 -0
  25. package/dist/{FormSpotlight-OTFB6QM5.mjs → FormSpotlight-T3ASGUYB.mjs} +11 -7
  26. package/dist/FormSpotlight-T3ASGUYB.mjs.map +1 -0
  27. package/dist/{FormStage-FVKMIV73.js → FormStage-PSAIPZBS.js} +20 -15
  28. package/dist/FormStage-PSAIPZBS.js.map +1 -0
  29. package/dist/{FormStage-VPGOCMAV.mjs → FormStage-U5V4MI5Q.mjs} +9 -4
  30. package/dist/FormStage-U5V4MI5Q.mjs.map +1 -0
  31. package/dist/ManagedForm-EAZOMNSL.mjs +16 -0
  32. package/dist/{ManagedForm-CXVDJMHN.mjs.map → ManagedForm-EAZOMNSL.mjs.map} +1 -1
  33. package/dist/ManagedForm-R6DJXU34.js +25 -0
  34. package/dist/{ManagedForm-FGNTDGED.js.map → ManagedForm-R6DJXU34.js.map} +1 -1
  35. package/dist/{ManagedNewsletterForm-SQYB4BZU.mjs → ManagedNewsletterForm-5RY3TWPQ.mjs} +9 -7
  36. package/dist/ManagedNewsletterForm-5RY3TWPQ.mjs.map +1 -0
  37. package/dist/{ManagedNewsletterForm-3O5L44AZ.js → ManagedNewsletterForm-VX6GMZXJ.js} +10 -8
  38. package/dist/ManagedNewsletterForm-VX6GMZXJ.js.map +1 -0
  39. package/dist/{SignalCore-RFBOBNLQ.js → SignalCore-MWHF2WG4.js} +14 -20
  40. package/dist/SignalCore-MWHF2WG4.js.map +1 -0
  41. package/dist/{SignalCore-M2PKKIGH.mjs → SignalCore-ZT6EQGV3.mjs} +8 -14
  42. package/dist/SignalCore-ZT6EQGV3.mjs.map +1 -0
  43. package/dist/SitemapSync-OG4TQLDB.mjs +9 -0
  44. package/dist/{SitemapSync-4OVMIIGC.mjs.map → SitemapSync-OG4TQLDB.mjs.map} +1 -1
  45. package/dist/SitemapSync-Z62BGZMV.js +18 -0
  46. package/dist/{SitemapSync-RK3SQ4M2.js.map → SitemapSync-Z62BGZMV.js.map} +1 -1
  47. package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
  48. package/dist/analytics/index.js +10 -9
  49. package/dist/analytics/index.mjs +5 -4
  50. package/dist/api-D745LGGU.mjs +0 -1
  51. package/dist/api-XR5APCH3.js +0 -1
  52. package/dist/blog/BlogLayout.d.ts +3 -1
  53. package/dist/blog/BlogLayout.d.ts.map +1 -1
  54. package/dist/blog/BlogList.d.ts +7 -1
  55. package/dist/blog/BlogList.d.ts.map +1 -1
  56. package/dist/blog/BlogPost.d.ts +20 -1
  57. package/dist/blog/BlogPost.d.ts.map +1 -1
  58. package/dist/blog/BlogSidebar.d.ts +3 -1
  59. package/dist/blog/BlogSidebar.d.ts.map +1 -1
  60. package/dist/blog/BlogViewTracker.d.ts +8 -2
  61. package/dist/blog/BlogViewTracker.d.ts.map +1 -1
  62. package/dist/blog/ClusterLandingPage.d.ts +3 -1
  63. package/dist/blog/ClusterLandingPage.d.ts.map +1 -1
  64. package/dist/blog/ClusterNavigation.d.ts +5 -2
  65. package/dist/blog/ClusterNavigation.d.ts.map +1 -1
  66. package/dist/blog/RelatedPosts.d.ts +3 -1
  67. package/dist/blog/RelatedPosts.d.ts.map +1 -1
  68. package/dist/blog/index.d.ts +1 -1
  69. package/dist/blog/index.d.ts.map +1 -1
  70. package/dist/blog/index.js +40 -31
  71. package/dist/blog/index.js.map +1 -1
  72. package/dist/blog/index.mjs +11 -6
  73. package/dist/blog/index.mjs.map +1 -1
  74. package/dist/blog/processBlogHtml.d.ts +19 -2
  75. package/dist/blog/processBlogHtml.d.ts.map +1 -1
  76. package/dist/blog/public-reads.d.ts +27 -0
  77. package/dist/blog/public-reads.d.ts.map +1 -0
  78. package/dist/blog/server-core.d.ts +76 -10
  79. package/dist/blog/server-core.d.ts.map +1 -1
  80. package/dist/blog/server-ui.js +29 -23
  81. package/dist/blog/server-ui.js.map +1 -1
  82. package/dist/blog/server-ui.mjs +12 -6
  83. package/dist/blog/server-ui.mjs.map +1 -1
  84. package/dist/blog/server.d.ts +76 -10
  85. package/dist/blog/server.d.ts.map +1 -1
  86. package/dist/blog/server.js +54 -47
  87. package/dist/blog/server.mjs +5 -2
  88. package/dist/brand/extract-brand-profile.d.ts +36 -2
  89. package/dist/brand/extract-brand-profile.d.ts.map +1 -1
  90. package/dist/{chunk-MW2M6O7A.mjs → chunk-26EKSVXM.mjs} +4 -4
  91. package/dist/{chunk-MW2M6O7A.mjs.map → chunk-26EKSVXM.mjs.map} +1 -1
  92. package/dist/{chunk-D553G64G.js → chunk-2HPQTRUB.js} +13 -13
  93. package/dist/{chunk-D553G64G.js.map → chunk-2HPQTRUB.js.map} +1 -1
  94. package/dist/{chunk-BFJOZ3MU.mjs → chunk-3EY5E35M.mjs} +36 -71
  95. package/dist/chunk-3EY5E35M.mjs.map +1 -0
  96. package/dist/{chunk-BUJWXSYZ.mjs → chunk-3TQUARVN.mjs} +4 -4
  97. package/dist/{chunk-BUJWXSYZ.mjs.map → chunk-3TQUARVN.mjs.map} +1 -1
  98. package/dist/{chunk-OYOO2OO5.js → chunk-3VRWKKTD.js} +10 -10
  99. package/dist/{chunk-OYOO2OO5.js.map → chunk-3VRWKKTD.js.map} +1 -1
  100. package/dist/{chunk-BFM5PEFV.js → chunk-43I7U5AI.js} +56 -177
  101. package/dist/chunk-43I7U5AI.js.map +1 -0
  102. package/dist/{chunk-ILNCUSXW.mjs → chunk-4L7OHRWB.mjs} +12 -9
  103. package/dist/chunk-4L7OHRWB.mjs.map +1 -0
  104. package/dist/chunk-4LYW6PMU.mjs +72 -0
  105. package/dist/chunk-4LYW6PMU.mjs.map +1 -0
  106. package/dist/chunk-4TLFZ6NR.mjs +16 -0
  107. package/dist/chunk-4TLFZ6NR.mjs.map +1 -0
  108. package/dist/{chunk-JQ7M6CVL.mjs → chunk-4VSDMNQU.mjs} +3 -3
  109. package/dist/{chunk-JQ7M6CVL.mjs.map → chunk-4VSDMNQU.mjs.map} +1 -1
  110. package/dist/{chunk-4B4S56WJ.mjs → chunk-5B4J3IBX.mjs} +75 -21
  111. package/dist/chunk-5B4J3IBX.mjs.map +1 -0
  112. package/dist/{chunk-M5GY2AI3.mjs → chunk-5K6B4LWV.mjs} +4 -10
  113. package/dist/chunk-5K6B4LWV.mjs.map +1 -0
  114. package/dist/chunk-5SANRSX3.mjs +17 -0
  115. package/dist/chunk-5SANRSX3.mjs.map +1 -0
  116. package/dist/chunk-5XFFUP6D.js +100 -0
  117. package/dist/chunk-5XFFUP6D.js.map +1 -0
  118. package/dist/chunk-5YA6SI4Z.mjs +0 -1
  119. package/dist/{chunk-TDJKGN5Q.mjs → chunk-62Y4W4LR.mjs} +216 -103
  120. package/dist/chunk-62Y4W4LR.mjs.map +1 -0
  121. package/dist/{chunk-3CLP35TT.mjs → chunk-6S3JE66D.mjs} +62 -97
  122. package/dist/chunk-6S3JE66D.mjs.map +1 -0
  123. package/dist/{chunk-4A5V73SR.mjs → chunk-6WEZWYRU.mjs} +9 -9
  124. package/dist/{chunk-4A5V73SR.mjs.map → chunk-6WEZWYRU.mjs.map} +1 -1
  125. package/dist/{chunk-JTF4DFUF.mjs → chunk-7AEVA667.mjs} +4 -4
  126. package/dist/{chunk-JTF4DFUF.mjs.map → chunk-7AEVA667.mjs.map} +1 -1
  127. package/dist/{chunk-H65OX263.js → chunk-7DV7Y7BZ.js} +15 -15
  128. package/dist/{chunk-H65OX263.js.map → chunk-7DV7Y7BZ.js.map} +1 -1
  129. package/dist/{chunk-7ZX6TO6C.mjs → chunk-7H4HB4UZ.mjs} +50 -26
  130. package/dist/chunk-7H4HB4UZ.mjs.map +1 -0
  131. package/dist/{chunk-FO4KGPGF.js → chunk-7TC3GRXQ.js} +73 -38
  132. package/dist/chunk-7TC3GRXQ.js.map +1 -0
  133. package/dist/{chunk-UQ5YULFU.mjs → chunk-AUHUEIBB.mjs} +4 -4
  134. package/dist/{chunk-UQ5YULFU.mjs.map → chunk-AUHUEIBB.mjs.map} +1 -1
  135. package/dist/{chunk-BQGEVMIR.mjs → chunk-AWF73RU2.mjs} +5 -5
  136. package/dist/{chunk-BQGEVMIR.mjs.map → chunk-AWF73RU2.mjs.map} +1 -1
  137. package/dist/{chunk-ELQ4SRRR.js → chunk-BHBW2SZF.js} +15 -15
  138. package/dist/{chunk-ELQ4SRRR.js.map → chunk-BHBW2SZF.js.map} +1 -1
  139. package/dist/{chunk-RNAGCAIB.js → chunk-BIGXEYKT.js} +7 -7
  140. package/dist/{chunk-RNAGCAIB.js.map → chunk-BIGXEYKT.js.map} +1 -1
  141. package/dist/chunk-BQP6JIE2.mjs +28 -0
  142. package/dist/chunk-BQP6JIE2.mjs.map +1 -0
  143. package/dist/{chunk-VFGEY6FJ.js → chunk-BY35X57A.js} +223 -110
  144. package/dist/chunk-BY35X57A.js.map +1 -0
  145. package/dist/{chunk-3YQILJKJ.js → chunk-CGCUHIAR.js} +60 -35
  146. package/dist/chunk-CGCUHIAR.js.map +1 -0
  147. package/dist/chunk-CUNZAD46.js +53 -0
  148. package/dist/chunk-CUNZAD46.js.map +1 -0
  149. package/dist/{chunk-FEWWGEQF.js → chunk-CWUYI6LI.js} +4 -4
  150. package/dist/{chunk-FEWWGEQF.js.map → chunk-CWUYI6LI.js.map} +1 -1
  151. package/dist/chunk-CXAXZFFW.js +157 -0
  152. package/dist/chunk-CXAXZFFW.js.map +1 -0
  153. package/dist/{chunk-H4OBGC43.mjs → chunk-DA7IANFG.mjs} +14 -3
  154. package/dist/chunk-DA7IANFG.mjs.map +1 -0
  155. package/dist/{chunk-57AFHENV.mjs → chunk-EHAUNF4V.mjs} +3 -3
  156. package/dist/{chunk-57AFHENV.mjs.map → chunk-EHAUNF4V.mjs.map} +1 -1
  157. package/dist/{chunk-2N27LCZH.js → chunk-FEKPEI2G.js} +9 -9
  158. package/dist/{chunk-2N27LCZH.js.map → chunk-FEKPEI2G.js.map} +1 -1
  159. package/dist/{chunk-LC7AM4J5.js → chunk-FHPW7XVH.js} +77 -20
  160. package/dist/chunk-FHPW7XVH.js.map +1 -0
  161. package/dist/{chunk-JNRHTZL4.js → chunk-FVW6FT6L.js} +73 -29
  162. package/dist/chunk-FVW6FT6L.js.map +1 -0
  163. package/dist/{chunk-YKUEFRZI.js → chunk-FWW4K6QP.js} +14 -14
  164. package/dist/{chunk-YKUEFRZI.js.map → chunk-FWW4K6QP.js.map} +1 -1
  165. package/dist/{chunk-JNAXDFC4.mjs → chunk-GF4LV5LX.mjs} +38 -156
  166. package/dist/chunk-GF4LV5LX.mjs.map +1 -0
  167. package/dist/{chunk-C563AHZZ.mjs → chunk-GKFTJ5AF.mjs} +3 -3
  168. package/dist/{chunk-C563AHZZ.mjs.map → chunk-GKFTJ5AF.mjs.map} +1 -1
  169. package/dist/{chunk-OZ3FU4BT.js → chunk-H5NBFNND.js} +2 -2
  170. package/dist/chunk-H5NBFNND.js.map +1 -0
  171. package/dist/chunk-HCN3IKMW.mjs +106 -0
  172. package/dist/chunk-HCN3IKMW.mjs.map +1 -0
  173. package/dist/{chunk-6FC5Q4KU.mjs → chunk-HOJ4J4X2.mjs} +30 -12
  174. package/dist/chunk-HOJ4J4X2.mjs.map +1 -0
  175. package/dist/{chunk-H6YVT3BL.js → chunk-I3ND4XYW.js} +12 -9
  176. package/dist/chunk-I3ND4XYW.js.map +1 -0
  177. package/dist/chunk-I7AZC5ZQ.js +0 -1
  178. package/dist/{chunk-V5THCFPG.mjs → chunk-JFJ7NHS3.mjs} +4 -4
  179. package/dist/{chunk-V5THCFPG.mjs.map → chunk-JFJ7NHS3.mjs.map} +1 -1
  180. package/dist/{chunk-KXGD4E7G.js → chunk-JI4EUPHB.js} +7 -7
  181. package/dist/{chunk-KXGD4E7G.js.map → chunk-JI4EUPHB.js.map} +1 -1
  182. package/dist/{chunk-GZJE23Y5.mjs → chunk-JLVCWC6A.mjs} +2 -2
  183. package/dist/chunk-JLVCWC6A.mjs.map +1 -0
  184. package/dist/chunk-JOYMIGR2.mjs +0 -1
  185. package/dist/chunk-JS75ORH7.js +0 -1
  186. package/dist/{chunk-Q7347KP6.mjs → chunk-JX5SM2MX.mjs} +6 -12
  187. package/dist/chunk-JX5SM2MX.mjs.map +1 -0
  188. package/dist/chunk-K4TCEAUX.js +52 -0
  189. package/dist/chunk-K4TCEAUX.js.map +1 -0
  190. package/dist/chunk-KV7XXLJV.mjs +30 -0
  191. package/dist/chunk-KV7XXLJV.mjs.map +1 -0
  192. package/dist/{chunk-JTCQJKJE.js → chunk-LIAISQUE.js} +76 -111
  193. package/dist/chunk-LIAISQUE.js.map +1 -0
  194. package/dist/{chunk-CPY74A4F.js → chunk-LMEUYRRR.js} +72 -106
  195. package/dist/chunk-LMEUYRRR.js.map +1 -0
  196. package/dist/{chunk-4WBTM6YE.js → chunk-LOEP76MQ.js} +4 -4
  197. package/dist/{chunk-4WBTM6YE.js.map → chunk-LOEP76MQ.js.map} +1 -1
  198. package/dist/chunk-LVGSOW2F.js +32 -0
  199. package/dist/chunk-LVGSOW2F.js.map +1 -0
  200. package/dist/{chunk-DOB37PV4.js → chunk-M45AL7EA.js} +37 -19
  201. package/dist/chunk-M45AL7EA.js.map +1 -0
  202. package/dist/{chunk-RCSTDJUH.js → chunk-M4UVFUFR.js} +8 -13
  203. package/dist/chunk-M4UVFUFR.js.map +1 -0
  204. package/dist/{chunk-R2SXXFXZ.mjs → chunk-MI2SRBCR.mjs} +3 -3
  205. package/dist/{chunk-R2SXXFXZ.mjs.map → chunk-MI2SRBCR.mjs.map} +1 -1
  206. package/dist/chunk-MLVHVKFT.mjs +148 -0
  207. package/dist/chunk-MLVHVKFT.mjs.map +1 -0
  208. package/dist/{chunk-L7ACQ6PC.js → chunk-MOAYT3KN.js} +4 -4
  209. package/dist/{chunk-L7ACQ6PC.js.map → chunk-MOAYT3KN.js.map} +1 -1
  210. package/dist/chunk-NG2TTI7D.js +8 -0
  211. package/dist/{chunk-5TXXTYXL.js.map → chunk-NG2TTI7D.js.map} +1 -1
  212. package/dist/{chunk-C4PZ2R3B.js → chunk-NLDN6PYM.js} +10 -10
  213. package/dist/{chunk-C4PZ2R3B.js.map → chunk-NLDN6PYM.js.map} +1 -1
  214. package/dist/chunk-NN2YE5WT.js +0 -1
  215. package/dist/chunk-NNZDWY3L.mjs +0 -1
  216. package/dist/chunk-NRBITVDK.js +114 -0
  217. package/dist/chunk-NRBITVDK.js.map +1 -0
  218. package/dist/{chunk-TSZIACRC.js → chunk-OBKYF4TP.js} +6 -12
  219. package/dist/chunk-OBKYF4TP.js.map +1 -0
  220. package/dist/{chunk-TP7H6BSK.mjs → chunk-OE7CTIOU.mjs} +73 -30
  221. package/dist/chunk-OE7CTIOU.mjs.map +1 -0
  222. package/dist/chunk-OESGRWI4.mjs +6 -0
  223. package/dist/{chunk-QRBPT6Z6.mjs.map → chunk-OESGRWI4.mjs.map} +1 -1
  224. package/dist/{chunk-UJ6CHZAI.mjs → chunk-OEW2LFOV.js} +169 -25
  225. package/dist/chunk-OEW2LFOV.js.map +1 -0
  226. package/dist/chunk-P4Y75QSU.js +19 -0
  227. package/dist/chunk-P4Y75QSU.js.map +1 -0
  228. package/dist/{chunk-47XQWV4S.mjs → chunk-PQVQAX67.mjs} +3 -3
  229. package/dist/{chunk-47XQWV4S.mjs.map → chunk-PQVQAX67.mjs.map} +1 -1
  230. package/dist/chunk-QRHVMTHF.mjs +94 -0
  231. package/dist/chunk-QRHVMTHF.mjs.map +1 -0
  232. package/dist/{chunk-FBDHKYNF.mjs → chunk-R4B3DFF4.mjs} +3 -3
  233. package/dist/{chunk-FBDHKYNF.mjs.map → chunk-R4B3DFF4.mjs.map} +1 -1
  234. package/dist/chunk-R7GHP3FY.js +81 -0
  235. package/dist/chunk-R7GHP3FY.js.map +1 -0
  236. package/dist/{chunk-4UVM7E2W.js → chunk-S5VL7AWW.js} +3 -3
  237. package/dist/{chunk-4UVM7E2W.js.map → chunk-S5VL7AWW.js.map} +1 -1
  238. package/dist/{chunk-P4TB4ROG.js → chunk-SEP5D4MI.js} +8 -2
  239. package/dist/chunk-SEP5D4MI.js.map +1 -0
  240. package/dist/{chunk-L4V6TKMJ.mjs → chunk-U2V542EO.mjs} +7 -3
  241. package/dist/chunk-U2V542EO.mjs.map +1 -0
  242. package/dist/{chunk-HBN4A2N4.mjs → chunk-U6H5ZY3B.mjs} +3 -3
  243. package/dist/{chunk-HBN4A2N4.mjs.map → chunk-U6H5ZY3B.mjs.map} +1 -1
  244. package/dist/{chunk-H7274TKR.mjs → chunk-VJV7WUR2.mjs} +12 -4
  245. package/dist/chunk-VJV7WUR2.mjs.map +1 -0
  246. package/dist/{chunk-F3AKYZOH.js → chunk-WED6ZDVS.js} +6 -13
  247. package/dist/chunk-WED6ZDVS.js.map +1 -0
  248. package/dist/{chunk-5B4FABFK.js → chunk-WS7MH3GD.js} +14 -2
  249. package/dist/chunk-WS7MH3GD.js.map +1 -0
  250. package/dist/{chunk-XLPU3TEE.mjs → chunk-X22BGNVL.mjs} +4 -4
  251. package/dist/{chunk-XLPU3TEE.mjs.map → chunk-X22BGNVL.mjs.map} +1 -1
  252. package/dist/{chunk-IPV2TUAT.js → chunk-XA2GJFVM.js} +12 -4
  253. package/dist/chunk-XA2GJFVM.js.map +1 -0
  254. package/dist/chunk-XBX2K3GA.js +33 -0
  255. package/dist/chunk-XBX2K3GA.js.map +1 -0
  256. package/dist/{chunk-ABZGEHTC.mjs → chunk-XSAHJ2BB.mjs} +3 -3
  257. package/dist/{chunk-ABZGEHTC.mjs.map → chunk-XSAHJ2BB.mjs.map} +1 -1
  258. package/dist/{chunk-6CJP7BFM.js → chunk-XZO5I4RS.mjs} +147 -20
  259. package/dist/chunk-XZO5I4RS.mjs.map +1 -0
  260. package/dist/chunk-Y5QZPUL3.mjs +47 -0
  261. package/dist/chunk-Y5QZPUL3.mjs.map +1 -0
  262. package/dist/{chunk-NOU3JQJK.js → chunk-Y6Z2W45H.js} +8 -8
  263. package/dist/{chunk-NOU3JQJK.js.map → chunk-Y6Z2W45H.js.map} +1 -1
  264. package/dist/{chunk-YYDZ2TYR.js → chunk-YCFYQN2Q.js} +3 -3
  265. package/dist/{chunk-YYDZ2TYR.js.map → chunk-YCFYQN2Q.js.map} +1 -1
  266. package/dist/chunk-YN7QHLWF.js +19 -0
  267. package/dist/chunk-YN7QHLWF.js.map +1 -0
  268. package/dist/{chunk-O2VJZOR2.mjs → chunk-YRNDASQY.mjs} +6 -11
  269. package/dist/chunk-YRNDASQY.mjs.map +1 -0
  270. package/dist/chunk-YU7QZ3PP.mjs +45 -0
  271. package/dist/chunk-YU7QZ3PP.mjs.map +1 -0
  272. package/dist/{chunk-3S5JN6KL.js → chunk-ZV6HIQRQ.js} +6 -6
  273. package/dist/{chunk-3S5JN6KL.js.map → chunk-ZV6HIQRQ.js.map} +1 -1
  274. package/dist/{chunk-RVRN5U7W.mjs → chunk-ZVI7MBVF.mjs} +73 -38
  275. package/dist/chunk-ZVI7MBVF.mjs.map +1 -0
  276. package/dist/cli/agent/checks.d.ts +15 -1
  277. package/dist/cli/agent/checks.d.ts.map +1 -1
  278. package/dist/cli/commands/doctor.d.ts.map +1 -1
  279. package/dist/cli/commands/og.d.ts +26 -8
  280. package/dist/cli/commands/og.d.ts.map +1 -1
  281. package/dist/cli/index.js +683 -323
  282. package/dist/cli/index.mjs +604 -244
  283. package/dist/client/index.js +6 -6
  284. package/dist/client/index.mjs +5 -5
  285. package/dist/commerce/CheckoutForm.d.ts.map +1 -1
  286. package/dist/commerce/ProductDetail.d.ts.map +1 -1
  287. package/dist/commerce/api.d.ts +14 -0
  288. package/dist/commerce/api.d.ts.map +1 -1
  289. package/dist/commerce/index.d.ts +1 -1
  290. package/dist/commerce/index.d.ts.map +1 -1
  291. package/dist/commerce/index.js +61 -56
  292. package/dist/commerce/index.mjs +6 -5
  293. package/dist/config/index.js +3 -3
  294. package/dist/config/index.mjs +1 -1
  295. package/dist/discover-CYXYKHZ2.mjs +4 -0
  296. package/dist/{discover-FGTKWOL3.mjs.map → discover-CYXYKHZ2.mjs.map} +1 -1
  297. package/dist/discover-NGEPXZOD.js +21 -0
  298. package/dist/{discover-NJZPWTDL.js.map → discover-NGEPXZOD.js.map} +1 -1
  299. package/dist/engage/index.js +12 -10
  300. package/dist/engage/index.js.map +1 -1
  301. package/dist/engage/index.mjs +9 -7
  302. package/dist/engage/index.mjs.map +1 -1
  303. package/dist/fleet/index.js +8 -8
  304. package/dist/fleet/index.mjs +4 -4
  305. package/dist/forms/FormClient.d.ts.map +1 -1
  306. package/dist/forms/FormField.d.ts +7 -1
  307. package/dist/forms/FormField.d.ts.map +1 -1
  308. package/dist/forms/FormSpotlight.d.ts +1 -1
  309. package/dist/forms/FormSpotlight.d.ts.map +1 -1
  310. package/dist/forms/FormStage.d.ts +1 -1
  311. package/dist/forms/FormStage.d.ts.map +1 -1
  312. package/dist/forms/experience-plan.d.ts +0 -1
  313. package/dist/forms/experience-plan.d.ts.map +1 -1
  314. package/dist/forms/field-interactions.d.ts +63 -0
  315. package/dist/forms/field-interactions.d.ts.map +1 -0
  316. package/dist/forms/field-rules.d.ts +41 -0
  317. package/dist/forms/field-rules.d.ts.map +1 -0
  318. package/dist/forms/index.js +25 -23
  319. package/dist/forms/index.js.map +1 -1
  320. package/dist/forms/index.mjs +13 -11
  321. package/dist/forms/index.mjs.map +1 -1
  322. package/dist/forms/server.js +11 -11
  323. package/dist/forms/server.mjs +9 -9
  324. package/dist/forms/static.js +8 -8
  325. package/dist/forms/static.mjs +7 -7
  326. package/dist/forms/tracking-session.d.ts +48 -3
  327. package/dist/forms/tracking-session.d.ts.map +1 -1
  328. package/dist/forms/types.d.ts +11 -0
  329. package/dist/forms/types.d.ts.map +1 -1
  330. package/dist/forms/useForm.d.ts +8 -0
  331. package/dist/forms/useForm.d.ts.map +1 -1
  332. package/dist/forms/useFormTracking.d.ts +29 -4
  333. package/dist/forms/useFormTracking.d.ts.map +1 -1
  334. package/dist/images/index.js +11 -11
  335. package/dist/images/index.mjs +4 -4
  336. package/dist/index.js +72 -68
  337. package/dist/index.js.map +1 -1
  338. package/dist/index.mjs +14 -10
  339. package/dist/index.mjs.map +1 -1
  340. package/dist/layout/client.js +10 -10
  341. package/dist/layout/client.mjs +9 -9
  342. package/dist/layout/index.js +13 -12
  343. package/dist/layout/index.js.map +1 -1
  344. package/dist/layout/index.mjs +11 -10
  345. package/dist/layout/index.mjs.map +1 -1
  346. package/dist/lib-6HOOMENJ.js +0 -1
  347. package/dist/lib-BGAWCSUH.js +0 -1
  348. package/dist/lib-R7IQ4ZHE.mjs +0 -1
  349. package/dist/lib-RSDMEKDQ.mjs +0 -1
  350. package/dist/llms/aiRobots.d.ts +20 -4
  351. package/dist/llms/aiRobots.d.ts.map +1 -1
  352. package/dist/llms/api.d.ts +8 -3
  353. package/dist/llms/api.d.ts.map +1 -1
  354. package/dist/llms/discovery-headers.d.ts +24 -0
  355. package/dist/llms/discovery-headers.d.ts.map +1 -1
  356. package/dist/llms/generateLLMsTxt.d.ts.map +1 -1
  357. package/dist/llms/index.d.ts +2 -2
  358. package/dist/llms/index.d.ts.map +1 -1
  359. package/dist/llms/index.js +45 -96
  360. package/dist/llms/index.js.map +1 -1
  361. package/dist/llms/index.mjs +11 -81
  362. package/dist/llms/index.mjs.map +1 -1
  363. package/dist/llms/links.d.ts +26 -0
  364. package/dist/llms/links.d.ts.map +1 -0
  365. package/dist/llms/types.d.ts +15 -0
  366. package/dist/llms/types.d.ts.map +1 -1
  367. package/dist/llms/wiring.d.ts +22 -0
  368. package/dist/llms/wiring.d.ts.map +1 -1
  369. package/dist/llms/writeLLMsTxt.d.ts +9 -0
  370. package/dist/llms/writeLLMsTxt.d.ts.map +1 -1
  371. package/dist/maps/index.js +5 -5
  372. package/dist/maps/index.mjs +3 -3
  373. package/dist/motion/gsap.d.ts +54 -0
  374. package/dist/motion/gsap.d.ts.map +1 -1
  375. package/dist/motion/gsap.js +34 -4
  376. package/dist/motion/gsap.js.map +1 -1
  377. package/dist/motion/gsap.mjs +33 -5
  378. package/dist/motion/gsap.mjs.map +1 -1
  379. package/dist/og/config.d.ts +6 -0
  380. package/dist/og/config.d.ts.map +1 -1
  381. package/dist/og/contrast.d.ts +33 -0
  382. package/dist/og/contrast.d.ts.map +1 -0
  383. package/dist/og/index.d.ts +2 -0
  384. package/dist/og/index.d.ts.map +1 -1
  385. package/dist/og/index.js +26 -8
  386. package/dist/og/index.mjs +3 -1
  387. package/dist/og/pages.d.ts +101 -0
  388. package/dist/og/pages.d.ts.map +1 -1
  389. package/dist/og/route-copy.d.ts +34 -0
  390. package/dist/og/route-copy.d.ts.map +1 -0
  391. package/dist/og/route-fit.d.ts +77 -0
  392. package/dist/og/route-fit.d.ts.map +1 -0
  393. package/dist/og/route.d.ts +80 -20
  394. package/dist/og/route.d.ts.map +1 -1
  395. package/dist/og/route.js +195 -25
  396. package/dist/og/route.js.map +1 -1
  397. package/dist/og/route.mjs +193 -26
  398. package/dist/og/route.mjs.map +1 -1
  399. package/dist/og/template.d.ts.map +1 -1
  400. package/dist/og/wiring.d.ts +43 -3
  401. package/dist/og/wiring.d.ts.map +1 -1
  402. package/dist/proxy/index.d.ts.map +1 -1
  403. package/dist/proxy/index.js +15 -10
  404. package/dist/proxy/index.js.map +1 -1
  405. package/dist/proxy/index.mjs +12 -7
  406. package/dist/proxy/index.mjs.map +1 -1
  407. package/dist/redirects/index.d.ts +24 -0
  408. package/dist/redirects/index.d.ts.map +1 -1
  409. package/dist/redirects/index.js +11 -8
  410. package/dist/redirects/index.mjs +4 -1
  411. package/dist/redirects/not-found.js +8 -5
  412. package/dist/redirects/not-found.js.map +1 -1
  413. package/dist/redirects/not-found.mjs +4 -1
  414. package/dist/redirects/not-found.mjs.map +1 -1
  415. package/dist/robots/index.d.ts +2 -0
  416. package/dist/robots/index.d.ts.map +1 -1
  417. package/dist/robots/index.js +23 -3
  418. package/dist/robots/index.js.map +1 -1
  419. package/dist/robots/index.mjs +2 -2
  420. package/dist/robots/index.mjs.map +1 -1
  421. package/dist/search/index.js +4 -4
  422. package/dist/search/index.mjs +3 -3
  423. package/dist/seo/ManagedContent.d.ts +4 -2
  424. package/dist/seo/ManagedContent.d.ts.map +1 -1
  425. package/dist/seo/ManagedFAQ.d.ts.map +1 -1
  426. package/dist/seo/ManagedInternalLinks.d.ts.map +1 -1
  427. package/dist/seo/ManagedSchema.d.ts.map +1 -1
  428. package/dist/seo/client.js +6 -6
  429. package/dist/seo/client.mjs +5 -5
  430. package/dist/seo/getManagedMetadata.d.ts.map +1 -1
  431. package/dist/seo/index.js +59 -49
  432. package/dist/seo/index.js.map +1 -1
  433. package/dist/seo/index.mjs +29 -19
  434. package/dist/seo/index.mjs.map +1 -1
  435. package/dist/seo/register-sitemap-cli-impl.d.ts +32 -0
  436. package/dist/seo/register-sitemap-cli-impl.d.ts.map +1 -1
  437. package/dist/seo/register-sitemap-cli.d.ts +7 -0
  438. package/dist/seo/register-sitemap-cli.d.ts.map +1 -1
  439. package/dist/seo/register-sitemap-cli.js +273 -57
  440. package/dist/seo/register-sitemap-cli.mjs +269 -53
  441. package/dist/seo/register-sitemap-request.d.ts +36 -0
  442. package/dist/seo/register-sitemap-request.d.ts.map +1 -0
  443. package/dist/seo/routing.d.ts +2 -0
  444. package/dist/seo/routing.d.ts.map +1 -1
  445. package/dist/seo/schema-filter.d.ts +43 -0
  446. package/dist/seo/schema-filter.d.ts.map +1 -0
  447. package/dist/seo/server-api.d.ts +15 -2
  448. package/dist/seo/server-api.d.ts.map +1 -1
  449. package/dist/seo/server.js +23 -18
  450. package/dist/seo/server.mjs +7 -2
  451. package/dist/seo/types.d.ts +30 -0
  452. package/dist/seo/types.d.ts.map +1 -1
  453. package/dist/seo-meta/contract.d.ts +60 -0
  454. package/dist/seo-meta/contract.d.ts.map +1 -0
  455. package/dist/seo-meta/contract.js +41 -0
  456. package/dist/seo-meta/contract.js.map +1 -0
  457. package/dist/seo-meta/contract.mjs +4 -0
  458. package/dist/seo-meta/contract.mjs.map +1 -0
  459. package/dist/server/index.js +4 -3
  460. package/dist/server/index.mjs +3 -2
  461. package/dist/server/mint-site-token.d.ts +2 -32
  462. package/dist/server/mint-site-token.d.ts.map +1 -1
  463. package/dist/{server-api-RG3ZL3DV.mjs → server-api-A2EFCTZX.mjs} +7 -3
  464. package/dist/{server-api-RG3ZL3DV.mjs.map → server-api-A2EFCTZX.mjs.map} +1 -1
  465. package/dist/{server-api-RYJQAUGO.js → server-api-IWTZ7C3O.js} +25 -21
  466. package/dist/{server-api-RYJQAUGO.js.map → server-api-IWTZ7C3O.js.map} +1 -1
  467. package/dist/shared/build-entries.d.ts +2 -0
  468. package/dist/shared/build-entries.d.ts.map +1 -1
  469. package/dist/shared/fresh-fetch.d.ts +64 -0
  470. package/dist/shared/fresh-fetch.d.ts.map +1 -0
  471. package/dist/shared/next-files.d.ts +7 -0
  472. package/dist/shared/next-files.d.ts.map +1 -1
  473. package/dist/shared/page-leave.d.ts +27 -0
  474. package/dist/shared/page-leave.d.ts.map +1 -0
  475. package/dist/shared/source-graph.d.ts +63 -0
  476. package/dist/shared/source-graph.d.ts.map +1 -0
  477. package/dist/shared/version.d.ts +1 -1
  478. package/dist/signal/SignalCore.d.ts.map +1 -1
  479. package/dist/signal/index.js +11 -11
  480. package/dist/signal/index.mjs +2 -2
  481. package/dist/sitemap/index.d.ts +19 -4
  482. package/dist/sitemap/index.d.ts.map +1 -1
  483. package/dist/sitemap/index.js +53 -43
  484. package/dist/sitemap/index.js.map +1 -1
  485. package/dist/sitemap/index.mjs +37 -27
  486. package/dist/sitemap/index.mjs.map +1 -1
  487. package/dist/sitemap/shared.d.ts +65 -0
  488. package/dist/sitemap/shared.d.ts.map +1 -1
  489. package/dist/sites/resolve.d.ts.map +1 -1
  490. package/dist/sites/site-param.d.ts +16 -0
  491. package/dist/sites/site-param.d.ts.map +1 -0
  492. package/dist/sync/index.js +17 -17
  493. package/dist/sync/index.mjs +4 -4
  494. package/dist/writeLLMsTxt-CQ7A4AAL.js +19 -0
  495. package/dist/writeLLMsTxt-NX5MSPYX.mjs +10 -0
  496. package/package.json +9 -4
  497. package/dist/AnalyticsProvider-EWF7JN2X.mjs +0 -11
  498. package/dist/AnalyticsProvider-GJFG7YXA.js +0 -32
  499. package/dist/BlogViewTracker-2D3IJPJK.js.map +0 -1
  500. package/dist/BlogViewTracker-CKYG6MYU.mjs.map +0 -1
  501. package/dist/ChatWidget-AWP6GBVW.js +0 -22
  502. package/dist/ChatWidget-Z5QXDZP3.mjs +0 -13
  503. package/dist/EngageWidget-BKEY5TPO.mjs +0 -12
  504. package/dist/EngageWidget-VT4DYXVO.js +0 -21
  505. package/dist/FormSpotlight-OTFB6QM5.mjs.map +0 -1
  506. package/dist/FormSpotlight-URS4XRS7.js.map +0 -1
  507. package/dist/FormStage-FVKMIV73.js.map +0 -1
  508. package/dist/FormStage-VPGOCMAV.mjs.map +0 -1
  509. package/dist/ManagedForm-CXVDJMHN.mjs +0 -14
  510. package/dist/ManagedForm-FGNTDGED.js +0 -23
  511. package/dist/ManagedNewsletterForm-3O5L44AZ.js.map +0 -1
  512. package/dist/ManagedNewsletterForm-SQYB4BZU.mjs.map +0 -1
  513. package/dist/SignalCore-M2PKKIGH.mjs.map +0 -1
  514. package/dist/SignalCore-RFBOBNLQ.js.map +0 -1
  515. package/dist/SitemapSync-4OVMIIGC.mjs +0 -9
  516. package/dist/SitemapSync-RK3SQ4M2.js +0 -18
  517. package/dist/analytics/send-gate.test.d.ts +0 -20
  518. package/dist/analytics/send-gate.test.d.ts.map +0 -1
  519. package/dist/api-D745LGGU.mjs.map +0 -1
  520. package/dist/api-XR5APCH3.js.map +0 -1
  521. package/dist/blog/artwork-components.test.d.ts +0 -2
  522. package/dist/blog/artwork-components.test.d.ts.map +0 -1
  523. package/dist/blog/artwork.test.d.ts +0 -2
  524. package/dist/blog/artwork.test.d.ts.map +0 -1
  525. package/dist/blog/author-social.test.d.ts +0 -2
  526. package/dist/blog/author-social.test.d.ts.map +0 -1
  527. package/dist/blog/blog-tables.test.d.ts +0 -2
  528. package/dist/blog/blog-tables.test.d.ts.map +0 -1
  529. package/dist/blog/blog-view-tracker.test.d.ts +0 -2
  530. package/dist/blog/blog-view-tracker.test.d.ts.map +0 -1
  531. package/dist/blog/category-metadata.test.d.ts +0 -2
  532. package/dist/blog/category-metadata.test.d.ts.map +0 -1
  533. package/dist/blog/metadata-images.test.d.ts +0 -2
  534. package/dist/blog/metadata-images.test.d.ts.map +0 -1
  535. package/dist/blog/newsletter-widget.test.d.ts +0 -2
  536. package/dist/blog/newsletter-widget.test.d.ts.map +0 -1
  537. package/dist/blog/publication-render.test.d.ts +0 -2
  538. package/dist/blog/publication-render.test.d.ts.map +0 -1
  539. package/dist/blog/publication-routes.test.d.ts +0 -2
  540. package/dist/blog/publication-routes.test.d.ts.map +0 -1
  541. package/dist/blog/reading-time.test.d.ts +0 -2
  542. package/dist/blog/reading-time.test.d.ts.map +0 -1
  543. package/dist/blog/sanitize-excerpt.test.d.ts +0 -2
  544. package/dist/blog/sanitize-excerpt.test.d.ts.map +0 -1
  545. package/dist/blog/server-core-contract.test.d.ts +0 -2
  546. package/dist/blog/server-core-contract.test.d.ts.map +0 -1
  547. package/dist/blog/static-params.test.d.ts +0 -2
  548. package/dist/blog/static-params.test.d.ts.map +0 -1
  549. package/dist/blog/tag-links.test.d.ts +0 -2
  550. package/dist/blog/tag-links.test.d.ts.map +0 -1
  551. package/dist/blog/types-wire-shape.test.d.ts +0 -2
  552. package/dist/blog/types-wire-shape.test.d.ts.map +0 -1
  553. package/dist/brand/status-contrast.test.d.ts +0 -2
  554. package/dist/brand/status-contrast.test.d.ts.map +0 -1
  555. package/dist/chunk-3CLP35TT.mjs.map +0 -1
  556. package/dist/chunk-3UC6JETG.js +0 -32
  557. package/dist/chunk-3UC6JETG.js.map +0 -1
  558. package/dist/chunk-3YQILJKJ.js.map +0 -1
  559. package/dist/chunk-4B4S56WJ.mjs.map +0 -1
  560. package/dist/chunk-5B4FABFK.js.map +0 -1
  561. package/dist/chunk-5TXXTYXL.js +0 -8
  562. package/dist/chunk-5YA6SI4Z.mjs.map +0 -1
  563. package/dist/chunk-6CJP7BFM.js.map +0 -1
  564. package/dist/chunk-6FC5Q4KU.mjs.map +0 -1
  565. package/dist/chunk-7ZX6TO6C.mjs.map +0 -1
  566. package/dist/chunk-AWK57R5S.mjs +0 -29
  567. package/dist/chunk-AWK57R5S.mjs.map +0 -1
  568. package/dist/chunk-BFJOZ3MU.mjs.map +0 -1
  569. package/dist/chunk-BFM5PEFV.js.map +0 -1
  570. package/dist/chunk-CPY74A4F.js.map +0 -1
  571. package/dist/chunk-DOB37PV4.js.map +0 -1
  572. package/dist/chunk-F3AKYZOH.js.map +0 -1
  573. package/dist/chunk-FO4KGPGF.js.map +0 -1
  574. package/dist/chunk-GZJE23Y5.mjs.map +0 -1
  575. package/dist/chunk-H4OBGC43.mjs.map +0 -1
  576. package/dist/chunk-H6YVT3BL.js.map +0 -1
  577. package/dist/chunk-H7274TKR.mjs.map +0 -1
  578. package/dist/chunk-I7AZC5ZQ.js.map +0 -1
  579. package/dist/chunk-ILNCUSXW.mjs.map +0 -1
  580. package/dist/chunk-IPV2TUAT.js.map +0 -1
  581. package/dist/chunk-JEOKDUPQ.js +0 -45
  582. package/dist/chunk-JEOKDUPQ.js.map +0 -1
  583. package/dist/chunk-JNAXDFC4.mjs.map +0 -1
  584. package/dist/chunk-JNRHTZL4.js.map +0 -1
  585. package/dist/chunk-JOYMIGR2.mjs.map +0 -1
  586. package/dist/chunk-JS75ORH7.js.map +0 -1
  587. package/dist/chunk-JTCQJKJE.js.map +0 -1
  588. package/dist/chunk-L4V6TKMJ.mjs.map +0 -1
  589. package/dist/chunk-LC7AM4J5.js.map +0 -1
  590. package/dist/chunk-M5GY2AI3.mjs.map +0 -1
  591. package/dist/chunk-NN2YE5WT.js.map +0 -1
  592. package/dist/chunk-NNZDWY3L.mjs.map +0 -1
  593. package/dist/chunk-O2VJZOR2.mjs.map +0 -1
  594. package/dist/chunk-OZ3FU4BT.js.map +0 -1
  595. package/dist/chunk-P4TB4ROG.js.map +0 -1
  596. package/dist/chunk-Q7347KP6.mjs.map +0 -1
  597. package/dist/chunk-QJU6HBSK.mjs +0 -39
  598. package/dist/chunk-QJU6HBSK.mjs.map +0 -1
  599. package/dist/chunk-QRBPT6Z6.mjs +0 -6
  600. package/dist/chunk-RCSTDJUH.js.map +0 -1
  601. package/dist/chunk-RVRN5U7W.mjs.map +0 -1
  602. package/dist/chunk-TDJKGN5Q.mjs.map +0 -1
  603. package/dist/chunk-TP7H6BSK.mjs.map +0 -1
  604. package/dist/chunk-TSZIACRC.js.map +0 -1
  605. package/dist/chunk-UJ6CHZAI.mjs.map +0 -1
  606. package/dist/chunk-VFGEY6FJ.js.map +0 -1
  607. package/dist/cli/agent/envelope.test.d.ts +0 -2
  608. package/dist/cli/agent/envelope.test.d.ts.map +0 -1
  609. package/dist/cli/agent/ssr-bailout.test.d.ts +0 -2
  610. package/dist/cli/agent/ssr-bailout.test.d.ts.map +0 -1
  611. package/dist/cli/codemod/diff.test.d.ts +0 -2
  612. package/dist/cli/codemod/diff.test.d.ts.map +0 -1
  613. package/dist/cli/codemod/transforms.test.d.ts +0 -2
  614. package/dist/cli/codemod/transforms.test.d.ts.map +0 -1
  615. package/dist/cli/commands/config-regression.test.d.ts +0 -2
  616. package/dist/cli/commands/config-regression.test.d.ts.map +0 -1
  617. package/dist/cli/commands/geo.test.d.ts +0 -2
  618. package/dist/cli/commands/geo.test.d.ts.map +0 -1
  619. package/dist/cli/commands/og.test.d.ts +0 -2
  620. package/dist/cli/commands/og.test.d.ts.map +0 -1
  621. package/dist/cli/config.test.d.ts +0 -2
  622. package/dist/cli/config.test.d.ts.map +0 -1
  623. package/dist/cli/generators/index.test.d.ts +0 -2
  624. package/dist/cli/generators/index.test.d.ts.map +0 -1
  625. package/dist/cli/index.js.map +0 -1
  626. package/dist/cli/index.mjs.map +0 -1
  627. package/dist/cli/state.test.d.ts +0 -2
  628. package/dist/cli/state.test.d.ts.map +0 -1
  629. package/dist/commerce/events-extras.test.d.ts +0 -2
  630. package/dist/commerce/events-extras.test.d.ts.map +0 -1
  631. package/dist/commerce/server-result.test.d.ts +0 -2
  632. package/dist/commerce/server-result.test.d.ts.map +0 -1
  633. package/dist/discover-FGTKWOL3.mjs +0 -4
  634. package/dist/discover-NJZPWTDL.js +0 -21
  635. package/dist/engage/chat-launcher.test.d.ts +0 -2
  636. package/dist/engage/chat-launcher.test.d.ts.map +0 -1
  637. package/dist/engage/dependency-contract.test.d.ts +0 -2
  638. package/dist/engage/dependency-contract.test.d.ts.map +0 -1
  639. package/dist/engage/launcher-placement.test.d.ts +0 -2
  640. package/dist/engage/launcher-placement.test.d.ts.map +0 -1
  641. package/dist/fleet/contract.test.d.ts +0 -2
  642. package/dist/fleet/contract.test.d.ts.map +0 -1
  643. package/dist/fleet/heartbeat.test.d.ts +0 -2
  644. package/dist/fleet/heartbeat.test.d.ts.map +0 -1
  645. package/dist/forms/contract.test.d.ts +0 -2
  646. package/dist/forms/contract.test.d.ts.map +0 -1
  647. package/dist/forms/ga4-identity.test.d.ts +0 -2
  648. package/dist/forms/ga4-identity.test.d.ts.map +0 -1
  649. package/dist/forms/native-fallback.test.d.ts +0 -2
  650. package/dist/forms/native-fallback.test.d.ts.map +0 -1
  651. package/dist/forms/stage.test.d.ts +0 -2
  652. package/dist/forms/stage.test.d.ts.map +0 -1
  653. package/dist/forms/static-form.test.d.ts +0 -2
  654. package/dist/forms/static-form.test.d.ts.map +0 -1
  655. package/dist/forms/tracking-session.test.d.ts +0 -22
  656. package/dist/forms/tracking-session.test.d.ts.map +0 -1
  657. package/dist/landing/contract.test.d.ts +0 -2
  658. package/dist/landing/contract.test.d.ts.map +0 -1
  659. package/dist/landing/server-entry.test.d.ts +0 -2
  660. package/dist/landing/server-entry.test.d.ts.map +0 -1
  661. package/dist/lib-6HOOMENJ.js.map +0 -1
  662. package/dist/lib-BGAWCSUH.js.map +0 -1
  663. package/dist/lib-R7IQ4ZHE.mjs.map +0 -1
  664. package/dist/lib-RSDMEKDQ.mjs.map +0 -1
  665. package/dist/llms/aiRobots.test.d.ts +0 -2
  666. package/dist/llms/aiRobots.test.d.ts.map +0 -1
  667. package/dist/llms/contract.test.d.ts +0 -2
  668. package/dist/llms/contract.test.d.ts.map +0 -1
  669. package/dist/llms/discovery-headers.test.d.ts +0 -2
  670. package/dist/llms/discovery-headers.test.d.ts.map +0 -1
  671. package/dist/llms/generateLLMsTxt.test.d.ts +0 -2
  672. package/dist/llms/generateLLMsTxt.test.d.ts.map +0 -1
  673. package/dist/llms/handlers.test.d.ts +0 -2
  674. package/dist/llms/handlers.test.d.ts.map +0 -1
  675. package/dist/llms/humanize-industry.test.d.ts +0 -2
  676. package/dist/llms/humanize-industry.test.d.ts.map +0 -1
  677. package/dist/llms/sourcedFacts.test.d.ts +0 -2
  678. package/dist/llms/sourcedFacts.test.d.ts.map +0 -1
  679. package/dist/llms/wiring.test.d.ts +0 -2
  680. package/dist/llms/wiring.test.d.ts.map +0 -1
  681. package/dist/llms/writeLLMsTxt.test.d.ts +0 -2
  682. package/dist/llms/writeLLMsTxt.test.d.ts.map +0 -1
  683. package/dist/mcp/protocol.test.d.ts +0 -2
  684. package/dist/mcp/protocol.test.d.ts.map +0 -1
  685. package/dist/motion/motion.test.d.ts +0 -16
  686. package/dist/motion/motion.test.d.ts.map +0 -1
  687. package/dist/og/pages.test.d.ts +0 -2
  688. package/dist/og/pages.test.d.ts.map +0 -1
  689. package/dist/og/template.test.d.ts +0 -2
  690. package/dist/og/template.test.d.ts.map +0 -1
  691. package/dist/og/wiring.test.d.ts +0 -2
  692. package/dist/og/wiring.test.d.ts.map +0 -1
  693. package/dist/portfolio/contract.test.d.ts +0 -2
  694. package/dist/portfolio/contract.test.d.ts.map +0 -1
  695. package/dist/proxy/securityHeaders.test.d.ts +0 -2
  696. package/dist/proxy/securityHeaders.test.d.ts.map +0 -1
  697. package/dist/proxy/segment.test.d.ts +0 -2
  698. package/dist/proxy/segment.test.d.ts.map +0 -1
  699. package/dist/robots/index.test.d.ts +0 -2
  700. package/dist/robots/index.test.d.ts.map +0 -1
  701. package/dist/seo/register-sitemap-cli-impl.test.d.ts +0 -2
  702. package/dist/seo/register-sitemap-cli-impl.test.d.ts.map +0 -1
  703. package/dist/seo/register-sitemap-cli.js.map +0 -1
  704. package/dist/seo/register-sitemap-cli.mjs.map +0 -1
  705. package/dist/seo-pages/contract.test.d.ts +0 -2
  706. package/dist/seo-pages/contract.test.d.ts.map +0 -1
  707. package/dist/server/mint-site-token.test.d.ts +0 -2
  708. package/dist/server/mint-site-token.test.d.ts.map +0 -1
  709. package/dist/server/server-fetch.test.d.ts +0 -2
  710. package/dist/server/server-fetch.test.d.ts.map +0 -1
  711. package/dist/shared/client-entry-boundary.test.d.ts +0 -2
  712. package/dist/shared/client-entry-boundary.test.d.ts.map +0 -1
  713. package/dist/shared/next-files.test.d.ts +0 -2
  714. package/dist/shared/next-files.test.d.ts.map +0 -1
  715. package/dist/shared/no-cjs-require.test.d.ts +0 -2
  716. package/dist/shared/no-cjs-require.test.d.ts.map +0 -1
  717. package/dist/shared/publishCredential.test.d.ts +0 -2
  718. package/dist/shared/publishCredential.test.d.ts.map +0 -1
  719. package/dist/shared/raw-browser-api-guard.test.d.ts +0 -15
  720. package/dist/shared/raw-browser-api-guard.test.d.ts.map +0 -1
  721. package/dist/shared/siteToken.test.d.ts +0 -2
  722. package/dist/shared/siteToken.test.d.ts.map +0 -1
  723. package/dist/shared/sonorFetch.test.d.ts +0 -2
  724. package/dist/shared/sonorFetch.test.d.ts.map +0 -1
  725. package/dist/shared/uuid.test.d.ts +0 -2
  726. package/dist/shared/uuid.test.d.ts.map +0 -1
  727. package/dist/shared/version.test.d.ts +0 -2
  728. package/dist/shared/version.test.d.ts.map +0 -1
  729. package/dist/shared/visual-viewport-gap.test.d.ts +0 -2
  730. package/dist/shared/visual-viewport-gap.test.d.ts.map +0 -1
  731. package/dist/sitemap/discover.test.d.ts +0 -2
  732. package/dist/sitemap/discover.test.d.ts.map +0 -1
  733. package/dist/sitemap/shared.test.d.ts +0 -2
  734. package/dist/sitemap/shared.test.d.ts.map +0 -1
  735. package/dist/sitemap/site-scope.test.d.ts +0 -2
  736. package/dist/sitemap/site-scope.test.d.ts.map +0 -1
  737. package/dist/sites/contract.test.d.ts +0 -2
  738. package/dist/sites/contract.test.d.ts.map +0 -1
  739. package/dist/slots/ManagedSlot.test.d.ts +0 -2
  740. package/dist/slots/ManagedSlot.test.d.ts.map +0 -1
  741. package/dist/slots/contract.test.d.ts +0 -2
  742. package/dist/slots/contract.test.d.ts.map +0 -1
  743. package/dist/slots/revalidate.test.d.ts +0 -2
  744. package/dist/slots/revalidate.test.d.ts.map +0 -1
  745. package/dist/slots/server-api.test.d.ts +0 -2
  746. package/dist/slots/server-api.test.d.ts.map +0 -1
  747. package/dist/sync/add-to-calendar.test.d.ts +0 -2
  748. package/dist/sync/add-to-calendar.test.d.ts.map +0 -1
  749. package/dist/sync/api-errors.test.d.ts +0 -2
  750. package/dist/sync/api-errors.test.d.ts.map +0 -1
  751. package/dist/sync/booking-flow.test.d.ts +0 -2
  752. package/dist/sync/booking-flow.test.d.ts.map +0 -1
@@ -1,14 +1,5 @@
1
- 'use strict';
2
-
3
- // src/og/config.ts
4
- function defineOgCard(config) {
5
- return config;
6
- }
7
- var OG_WIDTH = 1200;
8
- var OG_HEIGHT = 630;
9
- var TITLE_MAX_PX = 104;
10
- var TITLE_MIN_PX = 56;
11
- var OG_REPORT_ATTR = "data-og-report";
1
+ import { OG_HEIGHT, OG_WIDTH, TITLE_MAX_PX, barTextColor, TITLE_MIN_PX, OG_REPORT_ATTR } from './chunk-YU7QZ3PP.mjs';
2
+ import { applyTrailingSlash, resolveTrailingSlash } from './chunk-4LYW6PMU.mjs';
12
3
 
13
4
  // src/og/template.ts
14
5
  function fitScript() {
@@ -174,7 +165,7 @@ ${fontLink(config)}
174
165
  /* Never below 40px: script faces are illegible at thumbnail width under that. */
175
166
  .hand { font-size:42px; margin-top:14px; transform:rotate(-1.5deg); display:inline-block; }
176
167
  .bar { position:absolute; left:0; right:0; bottom:0; height:74px; display:flex; align-items:center; justify-content:center; gap:26px;
177
- font-weight:800; text-transform:uppercase; letter-spacing:.1em; font-size:31px; color:${theme.surface}; }
168
+ font-weight:800; text-transform:uppercase; letter-spacing:.1em; font-size:31px; color:${barTextColor(theme)}; }
178
169
  /* nowrap so an over-long segment overflows the bar sideways, where the
179
170
  fitter's width check sees it, instead of silently wrapping to a second
180
171
  line and spilling over the copy above. */
@@ -189,11 +180,147 @@ ${fitScript()}
189
180
  </body></html>`;
190
181
  }
191
182
 
192
- exports.OG_HEIGHT = OG_HEIGHT;
193
- exports.OG_REPORT_ATTR = OG_REPORT_ATTR;
194
- exports.OG_WIDTH = OG_WIDTH;
195
- exports.TITLE_MAX_PX = TITLE_MAX_PX;
196
- exports.buildOgHtml = buildOgHtml;
197
- exports.defineOgCard = defineOgCard;
198
- //# sourceMappingURL=chunk-6CJP7BFM.js.map
199
- //# sourceMappingURL=chunk-6CJP7BFM.js.map
183
+ // src/og/pages.ts
184
+ var DYNAMIC = "*";
185
+ function pathSegments(path) {
186
+ return path.split("/").filter(Boolean);
187
+ }
188
+ var TITLE_SEPARATOR = /\s*\|\s*|\s+[–—-]\s+/g;
189
+ var TRAILING_HOSTNAME = /,\s*(?:https?:\/\/)?(?:[a-z0-9-]+\.)+[a-z]{2,}\/?$/i;
190
+ var DANGLING_SEPARATOR = /(?:\s*\||\s+[–—-])\s*$/;
191
+ function stripBrandSuffix(title, brand) {
192
+ const original = title.trim();
193
+ const base = original.replace(DANGLING_SEPARATOR, "").replace(TRAILING_HOSTNAME, "").trim() || original;
194
+ let last = -1;
195
+ for (const m of base.matchAll(TITLE_SEPARATOR)) last = m.index ?? last;
196
+ const cleaned = last > 0 ? base.slice(0, last).trim() : base;
197
+ if (!cleaned) return base;
198
+ if (brand && cleaned.toLowerCase() === brand.toLowerCase()) return base;
199
+ return cleaned;
200
+ }
201
+ function titleFromPath(path) {
202
+ const last = pathSegments(path).filter((s) => s !== DYNAMIC).pop();
203
+ if (!last) return "Home";
204
+ return last.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
205
+ }
206
+ function kickerFromPath(path, fallback) {
207
+ const parts = pathSegments(path);
208
+ const section = (parts[parts.length - 1] === DYNAMIC ? parts : parts.slice(0, -1)).filter(
209
+ (s) => s !== DYNAMIC
210
+ );
211
+ if (!section.length) return fallback;
212
+ return section.join(" / ").replace(/[-_]+/g, " ");
213
+ }
214
+ function clampSubtitle(text, max = 100) {
215
+ if (!text) return void 0;
216
+ const flat = text.replace(/\s+/g, " ").trim();
217
+ if (!flat) return void 0;
218
+ if (flat.length <= max) return flat;
219
+ const sentence = flat.slice(0, max + 1).match(/^.*[.!?](?=\s|$)/)?.[0];
220
+ if (sentence && sentence.length >= 30) return sentence.trim();
221
+ return void 0;
222
+ }
223
+ function kickerIsRedundant(kicker, title) {
224
+ if (!kicker) return false;
225
+ const norm = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
226
+ const k = norm(kicker);
227
+ const t = norm(title);
228
+ if (!k) return true;
229
+ if (t.includes(k) || k.includes(t)) return true;
230
+ const titleWords = new Set(t.split(" "));
231
+ return k.split(" ").every((w) => titleWords.has(w));
232
+ }
233
+ function slugForPath(path) {
234
+ const segments = pathSegments(path);
235
+ if (!segments.length) return "home";
236
+ return segments.map((s) => s === DYNAMIC ? "any" : s).join("-").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
237
+ }
238
+ function unmatchedCardKeys(cards, paths) {
239
+ if (!cards) return [];
240
+ const known = new Set(paths.flatMap((p) => [p, slugForPath(p)]));
241
+ const patterns = paths.filter((p) => p.includes(DYNAMIC));
242
+ return Object.keys(cards).filter(
243
+ (key) => !known.has(key) && !patterns.some((pattern) => matchesRoutePattern(key, pattern))
244
+ );
245
+ }
246
+ function bareRoute(path) {
247
+ const segments = pathSegments(path);
248
+ return segments.length ? `/${segments.join("/")}` : "/";
249
+ }
250
+ function matchesRoutePattern(path, pattern) {
251
+ const concrete = pathSegments(path);
252
+ const shape = pathSegments(pattern);
253
+ if (concrete.includes(DYNAMIC) || concrete.length !== shape.length) return false;
254
+ return shape.every((seg, i) => seg === DYNAMIC || seg === concrete[i]);
255
+ }
256
+ function paramCardKeys(cards, paths) {
257
+ if (!cards) return [];
258
+ const known = new Set(paths.flatMap((p) => [p, slugForPath(p)]));
259
+ const patterns = paths.filter((p) => p.includes(DYNAMIC));
260
+ const found = [];
261
+ for (const key of Object.keys(cards)) {
262
+ if (known.has(key) || !key.startsWith("/")) continue;
263
+ const pattern = patterns.find((p) => matchesRoutePattern(key, p));
264
+ if (pattern) found.push({ path: bareRoute(key), pattern });
265
+ }
266
+ return found;
267
+ }
268
+ var PARAM_CARD_DIR = "_og";
269
+ function paramCardUrl(path) {
270
+ const segments = pathSegments(path);
271
+ return `/${PARAM_CARD_DIR}/${segments.length ? segments.join("/") : "home"}.jpg`;
272
+ }
273
+ function paramCardImage(path, options = {}) {
274
+ if (options.config) {
275
+ const bare = bareRoute(path);
276
+ const cards = options.config.cards ?? {};
277
+ if (!cards[bare] && !cards[`${bare}/`]) return void 0;
278
+ }
279
+ return {
280
+ url: paramCardUrl(path),
281
+ width: OG_WIDTH,
282
+ height: OG_HEIGHT,
283
+ type: "image/jpeg",
284
+ ...options.alt && { alt: options.alt }
285
+ };
286
+ }
287
+ function codeCardImage(path, options = {}) {
288
+ const base = bareRoute(path);
289
+ const url = applyTrailingSlash(`${base === "/" ? "" : base}/opengraph-image`, resolveTrailingSlash(options.trailingSlash));
290
+ return {
291
+ url,
292
+ width: OG_WIDTH,
293
+ height: OG_HEIGHT,
294
+ type: options.contentType ?? "image/png",
295
+ ...options.alt && { alt: options.alt }
296
+ };
297
+ }
298
+ function pageCardConfig(base, route, brand) {
299
+ const override = base.cards?.[route.path] ?? base.cards?.[`${route.path}/`] ?? base.cards?.[slugForPath(route.path)];
300
+ const isHome = route.path === "/";
301
+ const derived = isHome ? { ...base, cards: void 0 } : (() => {
302
+ const title = route.title ? stripBrandSuffix(route.title, brand) : titleFromPath(route.path);
303
+ const kicker = kickerFromPath(route.path, base.content.kicker);
304
+ return {
305
+ ...base,
306
+ // `cards` is a build-time instruction, not part of a rendered card.
307
+ cards: void 0,
308
+ content: {
309
+ ...base.content,
310
+ kicker: kickerIsRedundant(kicker, title) ? void 0 : kicker,
311
+ title,
312
+ subtitle: clampSubtitle(route.description) ?? base.content.subtitle
313
+ }
314
+ };
315
+ })();
316
+ if (!override) return derived;
317
+ return {
318
+ ...derived,
319
+ ...override,
320
+ content: { ...derived.content, ...override.content }
321
+ };
322
+ }
323
+
324
+ export { DYNAMIC, PARAM_CARD_DIR, buildOgHtml, codeCardImage, pageCardConfig, paramCardImage, paramCardKeys, paramCardUrl, unmatchedCardKeys };
325
+ //# sourceMappingURL=chunk-XZO5I4RS.mjs.map
326
+ //# sourceMappingURL=chunk-XZO5I4RS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/og/template.ts","../src/og/pages.ts"],"names":[],"mappings":"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","file":"chunk-XZO5I4RS.mjs","sourcesContent":["/**\n * OG card HTML template builder.\n *\n * Turns an OgCardConfig into a self-contained 1200x630 HTML document rendered\n * by headless Chrome. Layout rules baked in from the Ludlow card:\n * - content held inside the middle ~80% (platforms crop toward 2:1 and the\n * bottom bar is the first casualty)\n * - script/hand faces never below 40px — under that they turn to mush at\n * iMessage thumbnail width (~300px)\n * - the plate + title must survive alone if everything else is cropped\n */\n\nimport type { OgCardConfig, OgContent, OgTheme } from './config'\nimport { barTextColor } from './contrast'\nimport {\n OG_WIDTH,\n OG_HEIGHT,\n TITLE_MAX_PX,\n TITLE_MIN_PX,\n OG_REPORT_ATTR,\n} from './config'\n\n/**\n * The in-page fitter. Runs inside the render, after webfonts settle, and does\n * the two things a Node-side template cannot:\n *\n * 1. FITS THE TITLE. The h1 opens at TITLE_MAX_PX and steps down until the\n * copy column fits the frame. Before this the size was fixed, so title\n * length silently decided whether a card worked — a long one did not\n * shrink, it pushed the kicker off the top and the subtitle under the\n * bottom bar, and the CLI still reported success.\n * 2. MEASURES WHAT IS LEFT. Anything still clipped is written to the report\n * attribute, which `sonor-setup og` reads back through --dump-dom and\n * turns into a failure. Real measurement, not a character-count estimate.\n *\n * Fonts matter: measuring before `document.fonts.ready` measures the fallback\n * face and produces a size that is wrong for the face that actually renders.\n */\nfunction fitScript(): string {\n return `<script>\n(async function () {\n var report = { fits: true, titlePx: ${TITLE_MAX_PX}, issues: [] };\n function push(msg) { report.fits = false; report.issues.push(msg); }\n try {\n try { await document.fonts.ready; } catch (e) {}\n var h1 = document.querySelector('h1');\n var copy = document.querySelector('.copy');\n var wrap = document.querySelector('.wrap');\n var bar = document.querySelector('.bar');\n\n if (h1 && copy && wrap) {\n var cs = getComputedStyle(wrap);\n var avail = wrap.clientHeight - parseFloat(cs.paddingTop || '0') - parseFloat(cs.paddingBottom || '0');\n\n // Fit BOTH axes. Height alone is not enough: a single long word\n // (\"WORKBENCHES\") cannot wrap, so it keeps overflowing the column\n // sideways at a size that fits vertically. Shrinking for either\n // condition is what makes an arbitrary managed title safe to render.\n var tooTall = function () { return copy.scrollHeight > avail; };\n var tooWide = function () { return h1.scrollWidth > copy.clientWidth + 1; };\n var size = ${TITLE_MAX_PX};\n while (size > ${TITLE_MIN_PX} && (tooTall() || tooWide())) {\n size -= 2;\n h1.style.fontSize = size + 'px';\n }\n report.titlePx = size;\n\n if (tooTall()) {\n push('title/subtitle block overflows the card by ' + Math.ceil(copy.scrollHeight - avail) +\n 'px even at the ' + ${TITLE_MIN_PX} + 'px legibility floor - shorten content.title or content.subtitle');\n }\n if (tooWide()) {\n push('the longest title word still overflows the copy column by ' + Math.ceil(h1.scrollWidth - copy.clientWidth) +\n 'px at the ' + ${TITLE_MIN_PX} + 'px floor - shorten it or add a line break');\n }\n }\n\n // The bar is checked on BOTH axes. Width alone missed a real failure: a\n // long segment wrapped INSIDE its span, so scrollWidth never exceeded\n // clientWidth while the text grew past the bar's fixed height and spilled\n // over the subtitle. Segments are nowrap now, which turns that into\n // horizontal overflow the width check sees, and the height check is the\n // belt-and-braces for anything else that grows the bar.\n if (bar) {\n if (bar.scrollWidth > bar.clientWidth + 1) {\n push('bottom bar content overflows by ' + Math.ceil(bar.scrollWidth - bar.clientWidth) +\n 'px - drop a content.bar segment or shorten one');\n }\n if (bar.scrollHeight > bar.clientHeight + 1) {\n push('bottom bar content is ' + Math.ceil(bar.scrollHeight - bar.clientHeight) +\n 'px taller than the bar - a segment is wrapping; shorten it');\n }\n }\n\n // Nothing may sit outside the frame platforms actually crop to.\n var named = [['kicker', '.kicker'], ['title', 'h1'], ['subtitle', '.sub'], ['hand', '.hand'], ['bar', '.bar']];\n for (var i = 0; i < named.length; i++) {\n var el = document.querySelector(named[i][1]);\n if (!el) continue;\n var r = el.getBoundingClientRect();\n if (r.top < -1 || r.bottom > ${OG_HEIGHT} + 1) {\n push(named[i][0] + ' sits outside the ' + ${OG_HEIGHT} + 'px frame (top ' +\n Math.round(r.top) + ', bottom ' + Math.round(r.bottom) + ')');\n }\n }\n } catch (e) {\n push('fitter failed: ' + (e && e.message ? e.message : String(e)));\n }\n document.documentElement.setAttribute('${OG_REPORT_ATTR}', JSON.stringify(report));\n})();\n</script>`\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\nfunction fontLink(config: OgCardConfig): string {\n const fonts = config.fonts?.length\n ? config.fonts\n : [{ family: 'Barlow Condensed', weights: [800] }]\n const families = fonts\n .map(f => `family=${f.family.replace(/ /g, '+')}:wght@${(f.weights || [700]).join(';')}`)\n .join('&')\n return `<link href=\"https://fonts.googleapis.com/css2?${families}&display=block\" rel=\"stylesheet\">`\n}\n\nfunction displayFamily(config: OgCardConfig): string {\n return config.fonts?.[0]?.family || 'Barlow Condensed'\n}\n\nfunction handFamily(config: OgCardConfig): string {\n const fonts = config.fonts || []\n return fonts.length > 1 ? fonts[fonts.length - 1].family : displayFamily(config)\n}\n\nfunction muted(theme: OgTheme): string {\n return theme.muted || theme.text\n}\n\nfunction backgroundLayers(config: OgCardConfig): string {\n if (!config.background) return ''\n const { image, blur = 0, scrim } = config.background\n return `\n <div class=\"bg\"><img src=\"${esc(image)}\" style=\"filter:blur(${blur}px)\"></div>\n ${scrim ? `<div class=\"scrim\" style=\"background:${esc(scrim)}\"></div>` : ''}`\n}\n\nfunction barHtml(content: OgContent, theme: OgTheme): string {\n if (!content.bar?.length) return ''\n const segs = content.bar\n .map(s => `<span>${esc(s)}</span>`)\n .join('<span class=\"dot\"></span>')\n return `<div class=\"bar\" style=\"background:${esc(theme.accent)}\">${segs}</div>`\n}\n\nfunction copyHtml(config: OgCardConfig): string {\n const { content, theme } = config\n const titleHtml = esc(content.title).replace(/\\n/g, '<br>')\n // In `split` the photo owns the right pane, so a configured logo has nowhere\n // to go as a plate. It used to be dropped silently. Render it small above the\n // kicker instead: the brand mark still appears, and the plate invariant that\n // split has no `.plate` is preserved.\n const mark =\n config.logo && (config.layout ?? (config.logo ? 'plate-left' : 'banner')) === 'split'\n ? `<img class=\"mark\" src=\"${esc(config.logo)}\">`\n : ''\n return `\n <div class=\"copy\">\n ${mark}\n ${content.kicker ? `<div class=\"kicker\">${esc(content.kicker)}</div>` : ''}\n <h1>${titleHtml}</h1>\n ${content.subtitle ? `<div class=\"sub\" style=\"color:${esc(muted(theme))}\">${esc(content.subtitle)}</div>` : ''}\n ${content.hand ? `<div class=\"hand\" style=\"font-family:'${esc(handFamily(config))}',cursive\">${esc(content.hand)}</div>` : ''}\n </div>`\n}\n\nexport function buildOgHtml(config: OgCardConfig): string {\n if (config.html) return config.html\n if (config.template) {\n return config.template(config, {\n esc,\n fontLink: fontLink(config),\n width: OG_WIDTH,\n height: OG_HEIGHT,\n })\n }\n\n const { theme, logo, layout = logo ? 'plate-left' : 'banner' } = config\n const display = displayFamily(config)\n\n const plate = logo\n ? `<div class=\"plate\" style=\"background:${esc(theme.surface)}\"><img src=\"${esc(logo)}\"></div>`\n : ''\n\n const photo = config.photo\n ? `<div class=\"photo\" style=\"flex-basis:${config.photo.width ?? 430}px;border-radius:${config.photo.radius ?? 24}px\"><img src=\"${esc(config.photo.src)}\"></div>`\n : ''\n\n const body =\n layout === 'centered'\n ? `<div class=\"wrap centered\">${plate}${copyHtml(config)}</div>`\n : layout === 'banner'\n ? `<div class=\"wrap banner\">${copyHtml(config)}</div>`\n : layout === 'split'\n ? `<div class=\"wrap\">${copyHtml(config)}${photo}</div>`\n : `<div class=\"wrap\">${photo || plate}${copyHtml(config)}</div>`\n\n return `<!doctype html>\n<html><head><meta charset=\"utf-8\">\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n${fontLink(config)}\n<style>\n * { margin:0; padding:0; box-sizing:border-box; }\n html,body { width:${OG_WIDTH}px; height:${OG_HEIGHT}px; overflow:hidden; }\n body { position:relative; background:${theme.bg}; font-family:'${display}',sans-serif; color:${theme.text}; }\n .bg { position:absolute; inset:0; }\n .bg img { width:100%; height:100%; object-fit:cover; transform:scale(1.05); }\n .scrim { position:absolute; inset:0; }\n .wrap { position:relative; height:100%; display:flex; align-items:center; gap:52px; padding:0 68px ${config.content.bar?.length ? '74px' : '0'}; }\n .wrap.centered { flex-direction:column; justify-content:center; text-align:center; gap:28px; }\n .wrap.banner { padding-left:90px; }\n .plate { border-radius:28px; padding:26px; flex:0 0 auto; }\n .plate img { display:block; width:250px; height:auto; }\n .centered .plate img { width:180px; }\n .photo { flex:0 0 auto; height:76%; overflow:hidden; box-shadow:0 8px 40px rgba(0,0,0,.25); }\n .photo img { width:100%; height:100%; object-fit:cover; display:block; }\n .copy { flex:1 1 auto; min-width:0; }\n /* split-layout brand mark: the photo owns the right pane, so the logo rides\n above the kicker rather than being dropped. */\n .mark { display:block; height:44px; width:auto; margin-bottom:20px; }\n .kicker { font-weight:800; text-transform:uppercase; letter-spacing:.22em; font-size:24px; color:${theme.accent}; margin-bottom:14px; }\n /* Opening size only — the in-page fitter steps this down to fit the frame. */\n h1 { font-weight:800; text-transform:uppercase; font-size:${TITLE_MAX_PX}px; line-height:.9; letter-spacing:-.01em; }\n .sub { margin-top:22px; font-size:29px; font-weight:500; line-height:1.32; }\n /* Never below 40px: script faces are illegible at thumbnail width under that. */\n .hand { font-size:42px; margin-top:14px; transform:rotate(-1.5deg); display:inline-block; }\n .bar { position:absolute; left:0; right:0; bottom:0; height:74px; display:flex; align-items:center; justify-content:center; gap:26px;\n font-weight:800; text-transform:uppercase; letter-spacing:.1em; font-size:31px; color:${barTextColor(theme)}; }\n /* nowrap so an over-long segment overflows the bar sideways, where the\n fitter's width check sees it, instead of silently wrapping to a second\n line and spilling over the copy above. */\n .bar > span { white-space:nowrap; }\n .bar .dot { width:10px; height:10px; border-radius:50%; background:currentColor; opacity:.55; flex:0 0 auto; }\n</style></head>\n<body>\n${backgroundLayers(config)}\n${body}\n${barHtml(config.content, theme)}\n${fitScript()}\n</body></html>`\n}\n","/**\n * @sonordev/site-kit/og — per-page card derivation.\n *\n * The site-wide card answers \"what is this site\". A per-page card answers\n * \"what is THIS page\", which is what someone pasting a deep link is actually\n * sharing. Every static route gets one by default.\n *\n * Copy comes from Sonor's managed metadata when a key is configured, because\n * that is the same copy the page's <title> and description already use — the\n * card and the SERP entry then say the same thing. Without a key (or when a\n * lookup fails) the path itself is titled, which is worse copy but still a\n * real, page-specific card rather than the site default.\n *\n * Everything else — theme, fonts, logo, photo, bar — is inherited from the\n * site's own og.config.ts, so the whole set reads as one family.\n */\n\nimport type { OgCardConfig } from './config'\nimport { OG_HEIGHT, OG_WIDTH } from './config'\n// Single source of truth for Next's trailingSlash URL shape (pure string logic).\nimport { applyTrailingSlash, resolveTrailingSlash } from '../sitemap/shared'\n\n/** A route to build a card for. */\nexport interface OgPageRoute {\n /** URL path, e.g. `/services/garage`. */\n path: string\n /** Managed title, if Sonor had one. */\n title?: string\n /** Managed meta description, if Sonor had one. */\n description?: string\n}\n\n/**\n * The stand-in for a dynamic segment in a route path.\n *\n * A dynamic route has no single URL, so its card is keyed by a pattern with one\n * `*` per dynamic level: `/services/[slug]` is `/services/*`, and each further\n * dynamic level adds another star. The depth is what keeps those patterns\n * apart — they are different pages and deserve different cards.\n *\n * (Nested patterns are spelled out in prose rather than written literally in\n * these block comments: a star followed by a slash closes the comment. See\n * src/og/README.md.)\n */\nexport const DYNAMIC = '*'\n\n/** `/services/garage/` -> `['services', 'garage']`. */\nfunction pathSegments(path: string): string[] {\n return path.split('/').filter(Boolean)\n}\n\n/**\n * A separator between a title and its brand: a pipe with or without spaces\n * around it, or a dash (`-`, `–`, `—`) with spaces on both sides. A dash with\n * no spaces is part of a word (\"Walk-In Closets\"), never a separator; the old\n * pattern treated it as one and cut that title to \"Walk\".\n */\nconst TITLE_SEPARATOR = /\\s*\\|\\s*|\\s+[–—-]\\s+/g\n\n/** `, abbeyglenapts.com` at the very end: a domain appended as if it were the brand. */\nconst TRAILING_HOSTNAME = /,\\s*(?:https?:\\/\\/)?(?:[a-z0-9-]+\\.)+[a-z]{2,}\\/?$/i\n\n/** A separator the title ends on, with nothing after it (\"Contact Us |\"). */\nconst DANGLING_SEPARATOR = /(?:\\s*\\||\\s+[–—-])\\s*$/\n\n/**\n * Trailing brand suffix on a managed title (` | Acme`, ` - Acme`, ` — Acme`).\n * Managed titles carry the brand because a SERP entry needs it; a card does\n * not — the logo, the photo and the bar are already saying whose it is, and\n * every character spent on the brand is one not spent on the page.\n *\n * Also drops the two broken suffixes managed titles turn up with, both found\n * on 2026-09-15 and each worked around by hand in a site's `cards`: a\n * dangling separator with no brand after it (reinhart's \"About Us |\", Green\n * Bay's), and the domain after a comma (\"Privacy Policy, abbeyglenapts.com\").\n */\nexport function stripBrandSuffix(title: string, brand?: string): string {\n const original = title.trim()\n // The junk first, so \"About | Acme |\" still loses its brand after it.\n const base = original.replace(DANGLING_SEPARATOR, '').replace(TRAILING_HOSTNAME, '').trim() || original\n let last = -1\n for (const m of base.matchAll(TITLE_SEPARATOR)) last = m.index ?? last\n const cleaned = last > 0 ? base.slice(0, last).trim() : base\n // Only accept the strip if something survives it, so a title that IS the\n // brand (\"Acme\") is left alone rather than reduced to nothing.\n if (!cleaned) return base\n if (brand && cleaned.toLowerCase() === brand.toLowerCase()) return base\n return cleaned\n}\n\n/**\n * `/services/walk-in-closets` -> `Walk In Closets`. The no-managed-data path.\n *\n * `*` segments (a dynamic route's card, `/services/*`) are skipped rather than\n * titled: one file covers every param, so the honest title is the section the\n * params belong to. Without this, an unmanaged dynamic segment rendered a card\n * whose headline was literally `*`.\n */\nexport function titleFromPath(path: string): string {\n const last = pathSegments(path).filter(s => s !== DYNAMIC).pop()\n if (!last) return 'Home'\n return last\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, c => c.toUpperCase())\n .trim()\n}\n\n/**\n * The kicker for a page card: its parent section, so a deep link reads\n * \"SERVICES / Walk In Closets\" rather than repeating the site name on every\n * card. Falls back to the base card's kicker at the top level.\n */\nexport function kickerFromPath(path: string, fallback?: string): string | undefined {\n const parts = pathSegments(path)\n // When the leaf is a `*`, the stars ARE the leaf, so the section is every\n // static segment — `/services/*` and `/services/*/*` both read \"services\",\n // never \"services / *\". A static leaf under a dynamic segment\n // (`/properties/*/about`) is the page itself, so the section is what's\n // above it, minus the stars: \"properties\".\n const section = (parts[parts.length - 1] === DYNAMIC ? parts : parts.slice(0, -1)).filter(\n s => s !== DYNAMIC,\n )\n if (!section.length) return fallback\n return section.join(' / ').replace(/[-_]+/g, ' ')\n}\n\n/**\n * Keep a card subtitle to two readable lines, never a full meta description.\n *\n * A meta description is written for a SERP row and runs to ~155 characters; at\n * card size that is four lines crowding the bottom bar. This trims to the first\n * sentence when there is one, and otherwise cuts on a word boundary.\n */\nexport function clampSubtitle(text: string | undefined, max = 100): string | undefined {\n if (!text) return undefined\n const flat = text.replace(/\\s+/g, ' ').trim()\n if (!flat) return undefined\n if (flat.length <= max) return flat\n\n // A whole sentence reads as written rather than as truncated. The floor is\n // absolute rather than a ratio of `max` (a ratio rejected a clean\n // 48-character sentence) — but not so low it accepts a stray \"Inc.\".\n const sentence = flat.slice(0, max + 1).match(/^.*[.!?](?=\\s|$)/)?.[0]\n if (sentence && sentence.length >= 30) return sentence.trim()\n\n /*\n * Otherwise: refuse.\n *\n * A managed description is 150+ characters of prose written for a SERP row,\n * and at card size NO truncation of it looks deliberate. Both attempts\n * proved it on real cards: a word cut gave \"across Cincinnati and…\", and\n * cutting at the last comma gave \"home offices designed, built\" — worse,\n * because with no ellipsis it looks complete and merely ungrammatical.\n *\n * Returning undefined lets the caller fall back to the site's own subtitle,\n * which is short, hand-written and always fits. A clean generic line beats a\n * mangled specific one, and the TITLE is already page-specific — which is\n * the signal that actually matters on a card.\n */\n return undefined\n}\n\n/**\n * Is the kicker already saying what the title says?\n *\n * Managed titles are written for search and usually carry the section and the\n * city, so the home page came out as kicker \"Custom Closets · Cincinnati\" above\n * title \"CUSTOM CLOSETS CINCINNATI TRI-STATE\" — a stutter that also cost a line\n * of the frame. When either contains the other, the title wins.\n */\nfunction kickerIsRedundant(kicker: string | undefined, title: string): boolean {\n if (!kicker) return false\n const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim()\n const k = norm(kicker)\n const t = norm(title)\n if (!k) return true\n if (t.includes(k) || k.includes(t)) return true\n // Or every word of the kicker already appears in the title.\n const titleWords = new Set(t.split(' '))\n return k.split(' ').every(w => titleWords.has(w))\n}\n\n/**\n * File-safe name for a route's card: `/services/garage` -> `services-garage`,\n * `/` -> `home`. Deterministic, so the generator and anything reading the\n * output agree without a manifest.\n *\n * A `*` (dynamic) segment becomes `any`, one per level: `/services/*` is\n * `services-any`, and a second dynamic level is `services-any-any`. The naive\n * punctuation strip collapsed every one of those to `services` — the SAME slug\n * as the real `/services` route — so a `cards` override keyed by slug could\n * silently land on the wrong card. (A literal `/services/any` route would still collide;\n * key those by path, which is always unambiguous.)\n */\nexport function slugForPath(path: string): string {\n const segments = pathSegments(path)\n if (!segments.length) return 'home'\n return segments\n .map(s => (s === DYNAMIC ? 'any' : s))\n .join('-')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .toLowerCase()\n}\n\n/**\n * The `cards` keys in og.config.ts that match none of the routes being\n * rendered.\n *\n * `pageCardConfig` looks an override up by exact path or exact slug and\n * silently derives the card when neither hits, so a mistyped or stale key — or\n * one written for a route shape the generator does not produce (a two-star\n * services pattern, before nested dynamic segments got their own key) — cost a\n * hand-written card with nothing said about it. The caller reports these.\n */\nexport function unmatchedCardKeys(\n cards: Record<string, unknown> | undefined,\n paths: string[],\n): string[] {\n if (!cards) return []\n const known = new Set(paths.flatMap(p => [p, slugForPath(p)]))\n const patterns = paths.filter(p => p.includes(DYNAMIC))\n return Object.keys(cards).filter(\n key => !known.has(key) && !patterns.some(pattern => matchesRoutePattern(key, pattern)),\n )\n}\n\n/** `/floor-plans/1-bedroom/` -> `/floor-plans/1-bedroom`. */\nfunction bareRoute(path: string): string {\n const segments = pathSegments(path)\n return segments.length ? `/${segments.join('/')}` : '/'\n}\n\n/**\n * Does a concrete URL fall under a dynamic route pattern? One `*` matches\n * exactly one segment: `/properties/tall-pines/about` is under\n * `/properties/*` + `/about`, and `/floor-plans/1-bedroom` under\n * `/floor-plans/*`. A key that is itself a pattern matches nothing.\n */\nexport function matchesRoutePattern(path: string, pattern: string): boolean {\n const concrete = pathSegments(path)\n const shape = pathSegments(pattern)\n if (concrete.includes(DYNAMIC) || concrete.length !== shape.length) return false\n return shape.every((seg, i) => seg === DYNAMIC || seg === concrete[i])\n}\n\n/**\n * The `cards` keys that name one page under a dynamic route: a card per\n * floor plan, per community, per sub-page of a community. Keyed by the URL\n * itself (`/floor-plans/1-bedroom`), which any site can build from the same\n * data its `generateStaticParams` reads.\n *\n * A static file in a dynamic segment covers every param of the route, so\n * these can't be `opengraph-image` files. `sonor-setup og` renders each one to\n * `public/_og/` (see paramCardUrl), and the page declares it with\n * `paramCardImage`. The MDG property sites needed a card per floor plan and\n * per community and rendered them with their own script until this existed.\n *\n * Returns each key with the pattern it falls under. Keys that are a real\n * static route or a pattern are left to the route cards.\n */\nexport function paramCardKeys(\n cards: Record<string, unknown> | undefined,\n paths: string[],\n): Array<{ path: string; pattern: string }> {\n if (!cards) return []\n const known = new Set(paths.flatMap(p => [p, slugForPath(p)]))\n const patterns = paths.filter(p => p.includes(DYNAMIC))\n const found: Array<{ path: string; pattern: string }> = []\n for (const key of Object.keys(cards)) {\n if (known.has(key) || !key.startsWith('/')) continue\n const pattern = patterns.find(p => matchesRoutePattern(key, p))\n if (pattern) found.push({ path: bareRoute(key), pattern })\n }\n return found\n}\n\n/**\n * Public directory (under `public/`) that `sonor-setup og` owns for per-URL\n * cards. Generated; the command clears it on every run, so keep nothing else\n * in it.\n */\nexport const PARAM_CARD_DIR = '_og'\n\n/**\n * Where the per-URL card for a page is served: `/floor-plans/1-bedroom` ->\n * `/_og/floor-plans/1-bedroom.jpg`. Single source of truth for the file the\n * CLI writes and the URL `paramCardImage` declares.\n *\n * It ends in `.jpg` on purpose. Next serves a code-based `opengraph-image`\n * route without an extension, and `trailingSlash: true` answers that URL with\n * a 308 before the card, which some preview bots don't follow. A static file\n * with an extension is never redirected.\n */\nexport function paramCardUrl(path: string): string {\n const segments = pathSegments(path)\n return `/${PARAM_CARD_DIR}/${segments.length ? segments.join('/') : 'home'}.jpg`\n}\n\n/** An `openGraph.images` entry. */\nexport interface OgImageDescriptor {\n url: string\n width: number\n height: number\n type: string\n alt?: string\n}\n\n/**\n * The page's per-URL card, for its metadata:\n *\n * ```ts\n * const card = paramCardImage(`/floor-plans/${slug}`, { config: ogConfig })\n * return {\n * openGraph: { ...(card && { images: [card] }) },\n * twitter: { card: 'summary_large_image', ...(card && { images: [card.url] }) },\n * }\n * ```\n *\n * Pass `config` (the site's og.config) and it answers undefined for a page\n * with no `cards` entry, so the page keeps its segment's static card. Without\n * `config` it always answers, so only call it for URLs you gave a card.\n */\nexport function paramCardImage(\n path: string,\n options: { config?: Pick<OgCardConfig, 'cards'>; alt?: string } = {},\n): OgImageDescriptor | undefined {\n if (options.config) {\n const bare = bareRoute(path)\n const cards = options.config.cards ?? {}\n if (!cards[bare] && !cards[`${bare}/`]) return undefined\n }\n return {\n url: paramCardUrl(path),\n width: OG_WIDTH,\n height: OG_HEIGHT,\n type: 'image/jpeg',\n ...(options.alt && { alt: options.alt }),\n }\n}\n\n/**\n * A code-based card (`opengraph-image.tsx`) declared at the URL the site\n * actually serves it from.\n *\n * Next wires such a card in as `<path>/opengraph-image`, with no extension.\n * With `trailingSlash: true` that URL 308-redirects to the slashed one, so\n * every share preview starts with a redirect, and bots that don't follow one\n * show no card (the MDG property sites, 2026-09-15). Declaring the slashed URL\n * gets a 200 first time. Declared images beat the file convention, so this\n * replaces Next's own entry rather than adding a second.\n *\n * `trailingSlash` defaults to the site's next.config. Without it, this is the\n * URL Next would have used anyway.\n */\nexport function codeCardImage(\n path: string,\n options: { trailingSlash?: boolean; alt?: string; contentType?: string } = {},\n): OgImageDescriptor {\n const base = bareRoute(path)\n const url = applyTrailingSlash(`${base === '/' ? '' : base}/opengraph-image`, resolveTrailingSlash(options.trailingSlash))\n return {\n url,\n width: OG_WIDTH,\n height: OG_HEIGHT,\n type: options.contentType ?? 'image/png',\n ...(options.alt && { alt: options.alt }),\n }\n}\n\n/**\n * Build a page's card config by layering its copy over the site's card.\n *\n * `cards` in og.config.ts wins over everything derived here, so a site can\n * hand-write the two or three cards that matter and let the rest be generated.\n */\nexport function pageCardConfig(\n base: OgCardConfig,\n route: OgPageRoute,\n brand?: string,\n): OgCardConfig {\n const override =\n base.cards?.[route.path] ?? base.cards?.[`${route.path}/`] ?? base.cards?.[slugForPath(route.path)]\n const isHome = route.path === '/'\n\n /*\n * The home page keeps the card the site actually wrote.\n *\n * og.config.ts `content` IS the home page's card — it is the one route whose\n * subject is the whole site, and it is hand-written. Deriving it from the\n * managed <title> instead replaced a crafted headline (\"Built by brothers\")\n * with the SEO string (\"Custom Closets Cincinnati Tri-State\"), which repeated\n * the kicker and ran to four lines. Every other route has no hand-written\n * card, so deriving is a clear gain there.\n */\n const derived: OgCardConfig = isHome\n ? { ...base, cards: undefined }\n : (() => {\n const title = route.title ? stripBrandSuffix(route.title, brand) : titleFromPath(route.path)\n const kicker = kickerFromPath(route.path, base.content.kicker)\n return {\n ...base,\n // `cards` is a build-time instruction, not part of a rendered card.\n cards: undefined,\n content: {\n ...base.content,\n kicker: kickerIsRedundant(kicker, title) ? undefined : kicker,\n title,\n subtitle: clampSubtitle(route.description) ?? base.content.subtitle,\n },\n }\n })()\n\n if (!override) return derived\n return {\n ...derived,\n ...override,\n content: { ...derived.content, ...override.content },\n }\n}\n"]}
@@ -0,0 +1,47 @@
1
+ // src/blog/processBlogHtml.ts
2
+ function linkClassificationHost(siteUrl) {
3
+ try {
4
+ const base = siteUrl.startsWith("http") ? siteUrl : `https://${siteUrl}`;
5
+ const u = new URL(base);
6
+ return u.hostname.replace(/^www\./i, "").toLowerCase();
7
+ } catch {
8
+ return "";
9
+ }
10
+ }
11
+ var normalizeSiteHost = linkClassificationHost;
12
+ function resolveBlogSiteUrl(explicit) {
13
+ const fromProp = explicit?.trim();
14
+ if (fromProp) return fromProp;
15
+ const next = process.env.NEXT_PUBLIC_SITE_URL?.trim();
16
+ if (next) return next;
17
+ const site = process.env.SITE_URL?.trim();
18
+ if (site) return site;
19
+ const vercel = process.env.VERCEL_URL?.trim();
20
+ if (vercel) return vercel.startsWith("http") ? vercel : `https://${vercel}`;
21
+ return "";
22
+ }
23
+ function addExternalLinkTargets(html, siteUrl) {
24
+ if (!html || !siteUrl) return html;
25
+ const siteHost = linkClassificationHost(siteUrl);
26
+ if (!siteHost) return html;
27
+ return html.replace(/<a\b([^>]*)>/gi, (_full, attrs) => {
28
+ const hrefMatch = attrs.match(/\bhref\s*=\s*(["'])([^"']*)\1/i);
29
+ if (!hrefMatch) return `<a${attrs}>`;
30
+ const href = hrefMatch[2].trim();
31
+ if (!/^https?:\/\//i.test(href)) return `<a${attrs}>`;
32
+ try {
33
+ const url = new URL(href);
34
+ const linkHost = url.hostname.replace(/^www\./i, "").toLowerCase();
35
+ if (linkHost === siteHost) return `<a${attrs}>`;
36
+ if (/\btarget\s*=/i.test(attrs)) return `<a${attrs}>`;
37
+ const trimmed = attrs.trim();
38
+ return `<a ${trimmed} target="_blank" rel="noopener noreferrer">`;
39
+ } catch {
40
+ return `<a${attrs}>`;
41
+ }
42
+ });
43
+ }
44
+
45
+ export { addExternalLinkTargets, linkClassificationHost, normalizeSiteHost, resolveBlogSiteUrl };
46
+ //# sourceMappingURL=chunk-Y5QZPUL3.mjs.map
47
+ //# sourceMappingURL=chunk-Y5QZPUL3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/blog/processBlogHtml.ts"],"names":[],"mappings":";AAgBO,SAAS,uBAAuB,OAAA,EAAyB;AAC9D,EAAA,IAAI;AACF,IAAA,MAAM,OAAO,OAAA,CAAQ,UAAA,CAAW,MAAM,CAAA,GAAI,OAAA,GAAU,WAAW,OAAO,CAAA,CAAA;AACtE,IAAA,MAAM,CAAA,GAAI,IAAI,GAAA,CAAI,IAAI,CAAA;AACtB,IAAA,OAAO,EAAE,QAAA,CAAS,OAAA,CAAQ,SAAA,EAAW,EAAE,EAAE,WAAA,EAAY;AAAA,EACvD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAA;AAAA,EACT;AACF;AAQO,IAAM,iBAAA,GAAoB;AAM1B,SAAS,mBAAmB,QAAA,EAA2B;AAC5D,EAAA,MAAM,QAAA,GAAW,UAAU,IAAA,EAAK;AAChC,EAAA,IAAI,UAAU,OAAO,QAAA;AACrB,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,oBAAA,EAAsB,IAAA,EAAK;AACpD,EAAA,IAAI,MAAM,OAAO,IAAA;AACjB,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,QAAA,EAAU,IAAA,EAAK;AACxC,EAAA,IAAI,MAAM,OAAO,IAAA;AACjB,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,UAAA,EAAY,IAAA,EAAK;AAC5C,EAAA,IAAI,MAAA,SAAe,MAAA,CAAO,UAAA,CAAW,MAAM,CAAA,GAAI,MAAA,GAAS,WAAW,MAAM,CAAA,CAAA;AACzE,EAAA,OAAO,EAAA;AACT;AAOO,SAAS,sBAAA,CAAuB,MAAc,OAAA,EAAyB;AAC5E,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,OAAA,EAAS,OAAO,IAAA;AAC9B,EAAA,MAAM,QAAA,GAAW,uBAAuB,OAAO,CAAA;AAC/C,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAEtB,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,gBAAA,EAAkB,CAAC,OAAO,KAAA,KAAkB;AAC9D,IAAA,MAAM,SAAA,GAAY,KAAA,CAAM,KAAA,CAAM,gCAAgC,CAAA;AAC9D,IAAA,IAAI,CAAC,SAAA,EAAW,OAAO,CAAA,EAAA,EAAK,KAAK,CAAA,CAAA,CAAA;AACjC,IAAA,MAAM,IAAA,GAAO,SAAA,CAAU,CAAC,CAAA,CAAE,IAAA,EAAK;AAC/B,IAAA,IAAI,CAAC,eAAA,CAAgB,IAAA,CAAK,IAAI,CAAA,EAAG,OAAO,KAAK,KAAK,CAAA,CAAA,CAAA;AAElD,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAI,CAAA;AACxB,MAAA,MAAM,WAAW,GAAA,CAAI,QAAA,CAAS,QAAQ,SAAA,EAAW,EAAE,EAAE,WAAA,EAAY;AACjE,MAAA,IAAI,QAAA,KAAa,QAAA,EAAU,OAAO,CAAA,EAAA,EAAK,KAAK,CAAA,CAAA,CAAA;AAC5C,MAAA,IAAI,gBAAgB,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,KAAK,KAAK,CAAA,CAAA,CAAA;AAClD,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,MAAA,OAAO,MAAM,OAAO,CAAA,2CAAA,CAAA;AAAA,IACtB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAK,KAAK,CAAA,CAAA,CAAA;AAAA,IACnB;AAAA,EACF,CAAC,CAAA;AACH","file":"chunk-Y5QZPUL3.mjs","sourcesContent":["/**\n * Post-process Portal/blog HTML for safe, consistent link behavior.\n * Server-safe string transforms only (no DOM).\n */\n\n/**\n * The host `addExternalLinkTargets` compares links against to decide whether a\n * link is internal (same tab) or external (`target=\"_blank\"`). Lowercased,\n * leading `www.` stripped, so `www.example.com` and `example.com` count as the\n * same site; returns '' for anything unparseable.\n *\n * NOT the multi-site host normalizer. That is `normalizeSiteHost` in\n * `sites/normalize`, which keeps `www.` because `www.example.com` and\n * `example.com` can be different sub-sites of one Sonor project. This used to\n * share that name, so the two were easy to swap by accident.\n */\nexport function linkClassificationHost(siteUrl: string): string {\n try {\n const base = siteUrl.startsWith('http') ? siteUrl : `https://${siteUrl}`\n const u = new URL(base)\n return u.hostname.replace(/^www\\./i, '').toLowerCase()\n } catch {\n return ''\n }\n}\n\n/**\n * @deprecated Renamed to {@link linkClassificationHost} (same behavior: strips\n * `www.`). It shared a name with the multi-site `normalizeSiteHost` from\n * `sites/normalize`, which keeps `www.`. Kept so existing imports from\n * `@sonordev/site-kit/blog` still work.\n */\nexport const normalizeSiteHost = linkClassificationHost\n\n/**\n * Resolve canonical site URL for link classification.\n * Pass `explicit` from props when env vars are not set (e.g. non-Vercel hosts).\n */\nexport function resolveBlogSiteUrl(explicit?: string): string {\n const fromProp = explicit?.trim()\n if (fromProp) return fromProp\n const next = process.env.NEXT_PUBLIC_SITE_URL?.trim()\n if (next) return next\n const site = process.env.SITE_URL?.trim()\n if (site) return site\n const vercel = process.env.VERCEL_URL?.trim()\n if (vercel) return vercel.startsWith('http') ? vercel : `https://${vercel}`\n return ''\n}\n\n/**\n * Add `target=\"_blank\"` and `rel=\"noopener noreferrer\"` to external http(s) links.\n * Same registrable host (with or without `www`) is treated as internal.\n * Skips anchors that already set `target`.\n */\nexport function addExternalLinkTargets(html: string, siteUrl: string): string {\n if (!html || !siteUrl) return html\n const siteHost = linkClassificationHost(siteUrl)\n if (!siteHost) return html\n\n return html.replace(/<a\\b([^>]*)>/gi, (_full, attrs: string) => {\n const hrefMatch = attrs.match(/\\bhref\\s*=\\s*([\"'])([^\"']*)\\1/i)\n if (!hrefMatch) return `<a${attrs}>`\n const href = hrefMatch[2].trim()\n if (!/^https?:\\/\\//i.test(href)) return `<a${attrs}>`\n\n try {\n const url = new URL(href)\n const linkHost = url.hostname.replace(/^www\\./i, '').toLowerCase()\n if (linkHost === siteHost) return `<a${attrs}>`\n if (/\\btarget\\s*=/i.test(attrs)) return `<a${attrs}>`\n const trimmed = attrs.trim()\n return `<a ${trimmed} target=\"_blank\" rel=\"noopener noreferrer\">`\n } catch {\n return `<a${attrs}>`\n }\n })\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkYYDZ2TYR_js = require('./chunk-YYDZ2TYR.js');
4
+ var chunkYCFYQN2Q_js = require('./chunk-YCFYQN2Q.js');
5
5
  var React = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
 
@@ -16,8 +16,8 @@ function SignalExperiment({
16
16
  trackImpression = true,
17
17
  children
18
18
  }) {
19
- const { assignment, variant, isControl } = chunkYYDZ2TYR_js.useSignalExperiment(experimentId);
20
- const trackEvent = chunkYYDZ2TYR_js.useSignalEvent();
19
+ const { assignment, variant, isControl } = chunkYCFYQN2Q_js.useSignalExperiment(experimentId);
20
+ const trackEvent = chunkYCFYQN2Q_js.useSignalEvent();
21
21
  React.useEffect(() => {
22
22
  if (trackImpression && variant) {
23
23
  trackEvent({
@@ -44,7 +44,7 @@ function SignalExperiment({
44
44
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: variants.control || null });
45
45
  }
46
46
  function useExperimentVariant(experimentId) {
47
- return chunkYYDZ2TYR_js.useSignalExperiment(experimentId);
47
+ return chunkYCFYQN2Q_js.useSignalExperiment(experimentId);
48
48
  }
49
49
  function ExperimentConversion({
50
50
  experimentId,
@@ -52,8 +52,8 @@ function ExperimentConversion({
52
52
  value,
53
53
  children
54
54
  }) {
55
- const trackEvent = chunkYYDZ2TYR_js.useSignalEvent();
56
- const { variant } = chunkYYDZ2TYR_js.useSignalExperiment(experimentId);
55
+ const trackEvent = chunkYCFYQN2Q_js.useSignalEvent();
56
+ const { variant } = chunkYCFYQN2Q_js.useSignalExperiment(experimentId);
57
57
  const handleInteraction = () => {
58
58
  trackEvent({
59
59
  event_type: "experiment",
@@ -79,5 +79,5 @@ function ExperimentConversion({
79
79
  exports.ExperimentConversion = ExperimentConversion;
80
80
  exports.SignalExperiment = SignalExperiment;
81
81
  exports.useExperimentVariant = useExperimentVariant;
82
- //# sourceMappingURL=chunk-NOU3JQJK.js.map
83
- //# sourceMappingURL=chunk-NOU3JQJK.js.map
82
+ //# sourceMappingURL=chunk-Y6Z2W45H.js.map
83
+ //# sourceMappingURL=chunk-Y6Z2W45H.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/signal/SignalExperiment.tsx"],"names":["useSignalExperiment","useSignalEvent","useEffect","jsx","Fragment","React"],"mappings":";;;;;;;;;;AAgDO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA,GAAkB,IAAA;AAAA,EAClB;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,SAAA,EAAU,GAAIA,qCAAoB,YAAY,CAAA;AAC3E,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAGlC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,mBAAmB,OAAA,EAAS;AAC9B,MAAA,UAAA,CAAW;AAAA,QACT,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,aAAA,EAAe,YAAA;AAAA,UACf,WAAA,EAAa;AAAA;AACf,OACD,CAAA;AAAA,IACH;AAAA,EACF,GAAG,CAAC,YAAA,EAAc,OAAA,EAAS,eAAA,EAAiB,UAAU,CAAC,CAAA;AAGvD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBAAOC,cAAA,CAAAC,mBAAA,EAAA,EAAG,mBAAS,EAAE,OAAA,EAAS,WAAW,SAAA,EAAW,SAAA,EAAW,CAAA,EAAE,CAAA;AAAA,EACnE;AAGA,EAAA,MAAM,kBAAkB,OAAA,IAAW,SAAA;AACnC,EAAA,MAAM,OAAA,GAAU,SAAS,eAAe,CAAA;AAExC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,6DAAU,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EACpB;AAGA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,6DAAU,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAOD,cAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,CAAS,OAAA,IAAW,IAAA,EAAK,CAAA;AACrC;AAYO,SAAS,qBAAqB,YAAA,EAAsB;AACzD,EAAA,OAAOJ,qCAAoB,YAAY,CAAA;AACzC;AAoBO,SAAS,oBAAA,CAAqB;AAAA,EACnC,YAAA;AAAA,EACA,WAAA,GAAc,OAAA;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAClC,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAID,oCAAA,CAAoB,YAAY,CAAA;AAEpD,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,UAAA,CAAW;AAAA,MACT,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY;AAAA,QACV,aAAA,EAAe,YAAA;AAAA,QACf,WAAA,EAAa,OAAA;AAAA,QACb,YAAA,EAAc,WAAA;AAAA,QACd;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAOK,sBAAA,CAAM,aAAa,QAAA,EAAU;AAAA,IAClC,OAAA,EAAS,CAAC,CAAA,KAAwB;AAChC,MAAA,iBAAA,EAAkB;AAElB,MAAA,IAAK,QAAA,CAAS,MAAsD,OAAA,EAAS;AAC3E,QAAC,QAAA,CAAS,KAAA,CAAsD,OAAA,CAAS,CAAC,CAAA;AAAA,MAC5E;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-NOU3JQJK.js","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalExperiment\n * \n * A/B test component that renders different variants based on Signal assignment.\n * Uses Thompson Sampling (Bayesian bandit) for optimization.\n */\n\n'use client'\n\nimport React, { useMemo, useEffect } from 'react'\nimport { useSignalExperiment, useSignalEvent } from './SignalBridge'\n\ninterface SignalExperimentProps {\n /** Unique experiment ID */\n experimentId: string\n \n /** Variants to test - keys are variant names, values are React nodes */\n variants: Record<string, React.ReactNode>\n \n /** Fallback content if no assignment (defaults to 'control' variant) */\n fallback?: React.ReactNode\n \n /** Track impression automatically */\n trackImpression?: boolean\n \n /** Children function for more control */\n children?: (props: { variant: string; isControl: boolean }) => React.ReactNode\n}\n\n/**\n * Renders different content variants based on Signal's A/B assignment.\n * \n * @example\n * // Simple variant switching\n * <SignalExperiment experimentId=\"hero-cta\" variants={{\n * control: <Button>Get Started</Button>,\n * variant_a: <Button variant=\"primary\">Start Free Trial</Button>,\n * variant_b: <Button variant=\"secondary\">Book a Demo</Button>,\n * }} />\n * \n * @example\n * // With render prop for more control\n * <SignalExperiment experimentId=\"pricing-layout\">\n * {({ variant, isControl }) => (\n * <PricingSection layout={isControl ? 'cards' : 'table'} />\n * )}\n * </SignalExperiment>\n */\nexport function SignalExperiment({\n experimentId,\n variants,\n fallback,\n trackImpression = true,\n children,\n}: SignalExperimentProps) {\n const { assignment, variant, isControl } = useSignalExperiment(experimentId)\n const trackEvent = useSignalEvent()\n \n // Track impression when variant is rendered\n useEffect(() => {\n if (trackImpression && variant) {\n trackEvent({\n event_type: 'experiment',\n event_name: 'impression',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n },\n })\n }\n }, [experimentId, variant, trackImpression, trackEvent])\n \n // If using render prop\n if (children) {\n return <>{children({ variant: variant || 'control', isControl })}</>\n }\n \n // Determine what to render\n const selectedVariant = variant || 'control'\n const content = variants[selectedVariant]\n \n if (content !== undefined) {\n return <>{content}</>\n }\n \n // Fallback to provided fallback or control\n if (fallback) {\n return <>{fallback}</>\n }\n \n return <>{variants.control || null}</>\n}\n\n/**\n * Hook for conditional experiment logic\n * \n * @example\n * const { variant, isControl } = useExperimentVariant('pricing-test')\n * \n * return isControl \n * ? <OldPricing />\n * : <NewPricing showAnnual={variant === 'annual_first'} />\n */\nexport function useExperimentVariant(experimentId: string) {\n return useSignalExperiment(experimentId)\n}\n\n/**\n * Component for tracking experiment conversions\n * Wraps interactive elements to track when they convert\n * \n * @example\n * <SignalExperiment experimentId=\"signup-button\" variants={{\n * control: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button>Sign Up</Button>\n * </ExperimentConversion>\n * ),\n * variant_a: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button variant=\"large\">Join Now - It's Free!</Button>\n * </ExperimentConversion>\n * ),\n * }} />\n */\nexport function ExperimentConversion({\n experimentId,\n outcomeType = 'click',\n value,\n children,\n}: {\n experimentId: string\n outcomeType?: string\n value?: number\n children: React.ReactElement<{ onClick?: (e: React.MouseEvent) => void }>\n}) {\n const trackEvent = useSignalEvent()\n const { variant } = useSignalExperiment(experimentId)\n\n const handleInteraction = () => {\n trackEvent({\n event_type: 'experiment',\n event_name: 'conversion',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n outcome_type: outcomeType,\n value,\n },\n })\n }\n\n return React.cloneElement(children, {\n onClick: (e: React.MouseEvent) => {\n handleInteraction()\n // Call original onClick if exists\n if ((children.props as { onClick?: (e: React.MouseEvent) => void }).onClick) {\n (children.props as { onClick?: (e: React.MouseEvent) => void }).onClick!(e)\n }\n },\n })\n}\n"]}
1
+ {"version":3,"sources":["../src/signal/SignalExperiment.tsx"],"names":["useSignalExperiment","useSignalEvent","useEffect","jsx","Fragment","React"],"mappings":";;;;;;;;;;AAgDO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA,GAAkB,IAAA;AAAA,EAClB;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,SAAA,EAAU,GAAIA,qCAAoB,YAAY,CAAA;AAC3E,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAGlC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,mBAAmB,OAAA,EAAS;AAC9B,MAAA,UAAA,CAAW;AAAA,QACT,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY,YAAA;AAAA,QACZ,UAAA,EAAY;AAAA,UACV,aAAA,EAAe,YAAA;AAAA,UACf,WAAA,EAAa;AAAA;AACf,OACD,CAAA;AAAA,IACH;AAAA,EACF,GAAG,CAAC,YAAA,EAAc,OAAA,EAAS,eAAA,EAAiB,UAAU,CAAC,CAAA;AAGvD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBAAOC,cAAA,CAAAC,mBAAA,EAAA,EAAG,mBAAS,EAAE,OAAA,EAAS,WAAW,SAAA,EAAW,SAAA,EAAW,CAAA,EAAE,CAAA;AAAA,EACnE;AAGA,EAAA,MAAM,kBAAkB,OAAA,IAAW,SAAA;AACnC,EAAA,MAAM,OAAA,GAAU,SAAS,eAAe,CAAA;AAExC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,6DAAU,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EACpB;AAGA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,6DAAU,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,EACrB;AAEA,EAAA,uBAAOD,cAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,CAAS,OAAA,IAAW,IAAA,EAAK,CAAA;AACrC;AAYO,SAAS,qBAAqB,YAAA,EAAsB;AACzD,EAAA,OAAOJ,qCAAoB,YAAY,CAAA;AACzC;AAoBO,SAAS,oBAAA,CAAqB;AAAA,EACnC,YAAA;AAAA,EACA,WAAA,GAAc,OAAA;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,MAAM,aAAaC,+BAAA,EAAe;AAClC,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAID,oCAAA,CAAoB,YAAY,CAAA;AAEpD,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,UAAA,CAAW;AAAA,MACT,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY,YAAA;AAAA,MACZ,UAAA,EAAY;AAAA,QACV,aAAA,EAAe,YAAA;AAAA,QACf,WAAA,EAAa,OAAA;AAAA,QACb,YAAA,EAAc,WAAA;AAAA,QACd;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAOK,sBAAA,CAAM,aAAa,QAAA,EAAU;AAAA,IAClC,OAAA,EAAS,CAAC,CAAA,KAAwB;AAChC,MAAA,iBAAA,EAAkB;AAElB,MAAA,IAAK,QAAA,CAAS,MAAsD,OAAA,EAAS;AAC3E,QAAC,QAAA,CAAS,KAAA,CAAsD,OAAA,CAAS,CAAC,CAAA;AAAA,MAC5E;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-Y6Z2W45H.js","sourcesContent":["/**\n * @sonordev/site-kit/signal - SignalExperiment\n * \n * A/B test component that renders different variants based on Signal assignment.\n * Uses Thompson Sampling (Bayesian bandit) for optimization.\n */\n\n'use client'\n\nimport React, { useMemo, useEffect } from 'react'\nimport { useSignalExperiment, useSignalEvent } from './SignalBridge'\n\ninterface SignalExperimentProps {\n /** Unique experiment ID */\n experimentId: string\n \n /** Variants to test - keys are variant names, values are React nodes */\n variants: Record<string, React.ReactNode>\n \n /** Fallback content if no assignment (defaults to 'control' variant) */\n fallback?: React.ReactNode\n \n /** Track impression automatically */\n trackImpression?: boolean\n \n /** Children function for more control */\n children?: (props: { variant: string; isControl: boolean }) => React.ReactNode\n}\n\n/**\n * Renders different content variants based on Signal's A/B assignment.\n * \n * @example\n * // Simple variant switching\n * <SignalExperiment experimentId=\"hero-cta\" variants={{\n * control: <Button>Get Started</Button>,\n * variant_a: <Button variant=\"primary\">Start Free Trial</Button>,\n * variant_b: <Button variant=\"secondary\">Book a Demo</Button>,\n * }} />\n * \n * @example\n * // With render prop for more control\n * <SignalExperiment experimentId=\"pricing-layout\">\n * {({ variant, isControl }) => (\n * <PricingSection layout={isControl ? 'cards' : 'table'} />\n * )}\n * </SignalExperiment>\n */\nexport function SignalExperiment({\n experimentId,\n variants,\n fallback,\n trackImpression = true,\n children,\n}: SignalExperimentProps) {\n const { assignment, variant, isControl } = useSignalExperiment(experimentId)\n const trackEvent = useSignalEvent()\n \n // Track impression when variant is rendered\n useEffect(() => {\n if (trackImpression && variant) {\n trackEvent({\n event_type: 'experiment',\n event_name: 'impression',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n },\n })\n }\n }, [experimentId, variant, trackImpression, trackEvent])\n \n // If using render prop\n if (children) {\n return <>{children({ variant: variant || 'control', isControl })}</>\n }\n \n // Determine what to render\n const selectedVariant = variant || 'control'\n const content = variants[selectedVariant]\n \n if (content !== undefined) {\n return <>{content}</>\n }\n \n // Fallback to provided fallback or control\n if (fallback) {\n return <>{fallback}</>\n }\n \n return <>{variants.control || null}</>\n}\n\n/**\n * Hook for conditional experiment logic\n * \n * @example\n * const { variant, isControl } = useExperimentVariant('pricing-test')\n * \n * return isControl \n * ? <OldPricing />\n * : <NewPricing showAnnual={variant === 'annual_first'} />\n */\nexport function useExperimentVariant(experimentId: string) {\n return useSignalExperiment(experimentId)\n}\n\n/**\n * Component for tracking experiment conversions\n * Wraps interactive elements to track when they convert\n * \n * @example\n * <SignalExperiment experimentId=\"signup-button\" variants={{\n * control: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button>Sign Up</Button>\n * </ExperimentConversion>\n * ),\n * variant_a: (\n * <ExperimentConversion experimentId=\"signup-button\" outcomeType=\"click\">\n * <Button variant=\"large\">Join Now - It's Free!</Button>\n * </ExperimentConversion>\n * ),\n * }} />\n */\nexport function ExperimentConversion({\n experimentId,\n outcomeType = 'click',\n value,\n children,\n}: {\n experimentId: string\n outcomeType?: string\n value?: number\n children: React.ReactElement<{ onClick?: (e: React.MouseEvent) => void }>\n}) {\n const trackEvent = useSignalEvent()\n const { variant } = useSignalExperiment(experimentId)\n\n const handleInteraction = () => {\n trackEvent({\n event_type: 'experiment',\n event_name: 'conversion',\n event_data: {\n experiment_id: experimentId,\n variant_key: variant,\n outcome_type: outcomeType,\n value,\n },\n })\n }\n\n return React.cloneElement(children, {\n onClick: (e: React.MouseEvent) => {\n handleInteraction()\n // Call original onClick if exists\n if ((children.props as { onClick?: (e: React.MouseEvent) => void }).onClick) {\n (children.props as { onClick?: (e: React.MouseEvent) => void }).onClick!(e)\n }\n },\n })\n}\n"]}
@@ -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-RFBOBNLQ.js').then((m) => ({ default: m.SignalCore })),
63
+ () => import('./SignalCore-MWHF2WG4.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-YYDZ2TYR.js.map
176
- //# sourceMappingURL=chunk-YYDZ2TYR.js.map
175
+ //# sourceMappingURL=chunk-YCFYQN2Q.js.map
176
+ //# sourceMappingURL=chunk-YCFYQN2Q.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-YYDZ2TYR.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-YCFYQN2Q.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"]}
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ var chunkH5NBFNND_js = require('./chunk-H5NBFNND.js');
4
+
5
+ // src/sites/site-param.ts
6
+ function withSiteParam(url, site) {
7
+ const host = chunkH5NBFNND_js.resolveSiteHost(site);
8
+ if (!host) return url;
9
+ return `${url}${url.includes("?") ? "&" : "?"}site=${encodeURIComponent(host)}`;
10
+ }
11
+ function withSiteBody(body, site) {
12
+ const host = chunkH5NBFNND_js.resolveSiteHost(site);
13
+ return host ? { ...body, site: host } : body;
14
+ }
15
+
16
+ exports.withSiteBody = withSiteBody;
17
+ exports.withSiteParam = withSiteParam;
18
+ //# sourceMappingURL=chunk-YN7QHLWF.js.map
19
+ //# sourceMappingURL=chunk-YN7QHLWF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sites/site-param.ts"],"names":["resolveSiteHost"],"mappings":";;;;;AAiCO,SAAS,aAAA,CAAc,KAAa,IAAA,EAAuB;AAChE,EAAA,MAAM,IAAA,GAAOA,iCAAgB,IAAI,CAAA;AACjC,EAAA,IAAI,CAAC,MAAM,OAAO,GAAA;AAClB,EAAA,OAAO,CAAA,EAAG,GAAG,CAAA,EAAG,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,GAAI,GAAA,GAAM,GAAG,CAAA,KAAA,EAAQ,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAA;AAC/E;AAMO,SAAS,YAAA,CAA+B,MAAS,IAAA,EAAsC;AAC5F,EAAA,MAAM,IAAA,GAAOA,iCAAgB,IAAI,CAAA;AACjC,EAAA,OAAO,OAAO,EAAE,GAAG,IAAA,EAAM,IAAA,EAAM,MAAK,GAAI,IAAA;AAC1C","file":"chunk-YN7QHLWF.js","sourcesContent":["/**\n * @sonordev/site-kit/sites — withSiteParam / withSiteBody (leaf module)\n *\n * SINGLE SOURCE OF TRUTH for \"tell the Sonor API which sub-site is asking\".\n * Every site-scoped read goes through one of these two: the llms reads\n * (`llms/api`, FAQ items included), every blog read (`blog/server-core` and\n * the blog server-ui components, plus the client `BlogViewTracker`), the\n * managed FAQ, internal-link and content-block reads (`seo/server-api`\n * getFAQData / getInternalLinks / getContentBlock), and the managed redirect\n * rules and hit tracking (`redirects`). Do not re-fork the\n * append-or-omit rule into a module of its own — the llms copy of it is where\n * this came from, and two copies drift.\n *\n * The host comes from `resolveSiteHost` (explicit → NEXT_PUBLIC_SITE_URL host\n * → window.location.host), already normalized, so it matches what the API\n * stores. When nothing resolves, the param/field is OMITTED rather than sent\n * empty: an absent `site` is how single-site projects (and older API servers)\n * keep their project-wide behavior.\n *\n * A leaf on purpose. It imports only `./resolve` (→ `./normalize`), both pure\n * string logic, so the client-stamped `blog` barrel and `BlogViewTracker` can\n * use it without reaching `server-only` code or the sites contract's JSON\n * schema.\n */\nimport { resolveSiteHost } from './resolve'\n\n/**\n * Append `site=<host>` to an API URL or endpoint path. Returns the input\n * unchanged when the host resolves empty.\n *\n * withSiteParam('/public/blog/posts?page=2', 'bd-charlotte.com')\n * → '/public/blog/posts?page=2&site=bd-charlotte.com'\n */\nexport function withSiteParam(url: string, site?: string): string {\n const host = resolveSiteHost(site)\n if (!host) return url\n return `${url}${url.includes('?') ? '&' : '?'}site=${encodeURIComponent(host)}`\n}\n\n/**\n * Add `site: <host>` to a JSON request body. Returns the body unchanged (no\n * `site` key at all) when the host resolves empty.\n */\nexport function withSiteBody<T extends object>(body: T, site?: string): T & { site?: string } {\n const host = resolveSiteHost(site)\n return host ? { ...body, site: host } : body\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  'use client';
2
2
  import { registerAnalyticsDispatcher } from './chunk-SHLWA6JY.mjs';
3
3
  import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-ZZQAGCSI.mjs';
4
+ import { onPageLeave } from './chunk-5SANRSX3.mjs';
4
5
  import { resolveAnalyticsTarget } from './chunk-A6UYV475.mjs';
5
- import { sonorFetch, sonorBeacon } from './chunk-XLPU3TEE.mjs';
6
+ import { sonorFetch, sonorBeacon } from './chunk-X22BGNVL.mjs';
6
7
  import { createContext, useRef, useEffect, useState, useMemo, useCallback, useContext } from 'react';
7
8
  import { usePathname } from 'next/navigation';
8
9
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -873,16 +874,10 @@ function AnalyticsProvider({
873
874
  hasTracked = false;
874
875
  window.addEventListener("scroll", handleScroll, { passive: true });
875
876
  handleScroll();
876
- const handlePageHide = () => sendScrollData(true);
877
- const handleVisibilityChange = () => {
878
- if (document.visibilityState === "hidden") sendScrollData(true);
879
- };
880
- window.addEventListener("pagehide", handlePageHide);
881
- document.addEventListener("visibilitychange", handleVisibilityChange);
877
+ const stopLeaveListener = onPageLeave(() => sendScrollData(true));
882
878
  return () => {
883
879
  window.removeEventListener("scroll", handleScroll);
884
- window.removeEventListener("pagehide", handlePageHide);
885
- document.removeEventListener("visibilitychange", handleVisibilityChange);
880
+ stopLeaveListener();
886
881
  sendScrollData(false);
887
882
  };
888
883
  }, [pathname, gate, trackScrollDepth, debug]);
@@ -1017,5 +1012,5 @@ function useTrackEvent() {
1017
1012
  }
1018
1013
 
1019
1014
  export { AnalyticsProvider, WebVitals, useAnalytics, useAnalyticsOptional, useTrackEvent };
1020
- //# sourceMappingURL=chunk-O2VJZOR2.mjs.map
1021
- //# sourceMappingURL=chunk-O2VJZOR2.mjs.map
1015
+ //# sourceMappingURL=chunk-YRNDASQY.mjs.map
1016
+ //# sourceMappingURL=chunk-YRNDASQY.mjs.map