@sonordev/site-kit 5.4.0 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/AGENTS.md +16 -6
  2. package/README.md +9 -7
  3. package/agent-manifest.json +7 -7
  4. package/dist/AnalyticsProvider-6PXC7UDP.js +32 -0
  5. package/dist/{AnalyticsProvider-Y2P2BPOI.js.map → AnalyticsProvider-6PXC7UDP.js.map} +1 -1
  6. package/dist/AnalyticsProvider-FVQIYSLY.mjs +11 -0
  7. package/dist/{AnalyticsProvider-2XIOMRCN.mjs.map → AnalyticsProvider-FVQIYSLY.mjs.map} +1 -1
  8. package/dist/{BlogViewTracker-6EGEDPP3.js → BlogViewTracker-S4HSRCW7.js} +6 -6
  9. package/dist/{BlogViewTracker-6EGEDPP3.js.map → BlogViewTracker-S4HSRCW7.js.map} +1 -1
  10. package/dist/{BlogViewTracker-R4YQ76WP.mjs → BlogViewTracker-ZUGLBOVI.mjs} +5 -5
  11. package/dist/{BlogViewTracker-R4YQ76WP.mjs.map → BlogViewTracker-ZUGLBOVI.mjs.map} +1 -1
  12. package/dist/ChatWidget-2TQWCXWP.js +22 -0
  13. package/dist/{ChatWidget-2OFWPCWF.js.map → ChatWidget-2TQWCXWP.js.map} +1 -1
  14. package/dist/ChatWidget-DG52ZIE6.mjs +13 -0
  15. package/dist/{ChatWidget-4AOGHYXQ.mjs.map → ChatWidget-DG52ZIE6.mjs.map} +1 -1
  16. package/dist/EngageWidget-2VUJADIU.mjs +12 -0
  17. package/dist/{EngageWidget-SFO2XRNG.mjs.map → EngageWidget-2VUJADIU.mjs.map} +1 -1
  18. package/dist/EngageWidget-Z7RC2INM.js +21 -0
  19. package/dist/{EngageWidget-T4KAAD3G.js.map → EngageWidget-Z7RC2INM.js.map} +1 -1
  20. package/dist/{FileField-7DF2SLPF.mjs → FileField-FSQ7W3A5.mjs} +5 -5
  21. package/dist/{FileField-7DF2SLPF.mjs.map → FileField-FSQ7W3A5.mjs.map} +1 -1
  22. package/dist/{FileField-CE2XNBBG.js → FileField-UOQHL25J.js} +6 -6
  23. package/dist/{FileField-CE2XNBBG.js.map → FileField-UOQHL25J.js.map} +1 -1
  24. package/dist/{FormSpotlight-IRLKSZGV.mjs → FormSpotlight-RHL5FWM2.mjs} +3 -3
  25. package/dist/{FormSpotlight-IRLKSZGV.mjs.map → FormSpotlight-RHL5FWM2.mjs.map} +1 -1
  26. package/dist/{FormSpotlight-ZD3WR5BC.js → FormSpotlight-TED32NHP.js} +15 -15
  27. package/dist/{FormSpotlight-ZD3WR5BC.js.map → FormSpotlight-TED32NHP.js.map} +1 -1
  28. package/dist/{FormStage-2OSRNQJL.mjs → FormStage-DINIRFOX.mjs} +3 -3
  29. package/dist/{FormStage-2OSRNQJL.mjs.map → FormStage-DINIRFOX.mjs.map} +1 -1
  30. package/dist/{FormStage-OSPXOUQE.js → FormStage-PFEBKHGY.js} +13 -13
  31. package/dist/{FormStage-OSPXOUQE.js.map → FormStage-PFEBKHGY.js.map} +1 -1
  32. package/dist/ManagedForm-43WLCUAK.js +23 -0
  33. package/dist/{ManagedForm-JCHGBBQW.js.map → ManagedForm-43WLCUAK.js.map} +1 -1
  34. package/dist/ManagedForm-545YAUFC.mjs +14 -0
  35. package/dist/{ManagedForm-5G37EDJT.mjs.map → ManagedForm-545YAUFC.mjs.map} +1 -1
  36. package/dist/{ManagedNewsletterForm-4LVJZROZ.js → ManagedNewsletterForm-I3QN57HB.js} +8 -8
  37. package/dist/{ManagedNewsletterForm-4LVJZROZ.js.map → ManagedNewsletterForm-I3QN57HB.js.map} +1 -1
  38. package/dist/{ManagedNewsletterForm-QJSVH23S.mjs → ManagedNewsletterForm-ZPY5RRKX.mjs} +7 -7
  39. package/dist/{ManagedNewsletterForm-QJSVH23S.mjs.map → ManagedNewsletterForm-ZPY5RRKX.mjs.map} +1 -1
  40. package/dist/{SignalCore-L6Z3YTCF.mjs → SignalCore-EEH5IM4U.mjs} +5 -5
  41. package/dist/{SignalCore-L6Z3YTCF.mjs.map → SignalCore-EEH5IM4U.mjs.map} +1 -1
  42. package/dist/{SignalCore-NQ4YEOI7.js → SignalCore-M4AXIMV4.js} +11 -11
  43. package/dist/{SignalCore-NQ4YEOI7.js.map → SignalCore-M4AXIMV4.js.map} +1 -1
  44. package/dist/SitemapSync-46G7LVZS.mjs +9 -0
  45. package/dist/{SitemapSync-MYSTLJOM.mjs.map → SitemapSync-46G7LVZS.mjs.map} +1 -1
  46. package/dist/SitemapSync-XK4JKCS7.js +18 -0
  47. package/dist/{SitemapSync-3LUZWBTB.js.map → SitemapSync-XK4JKCS7.js.map} +1 -1
  48. package/dist/SitemapSync.d.ts +3 -2
  49. package/dist/SitemapSync.d.ts.map +1 -1
  50. package/dist/analytics/AnalyticsProvider.d.ts +3 -1
  51. package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
  52. package/dist/analytics/WebVitals.d.ts +3 -1
  53. package/dist/analytics/WebVitals.d.ts.map +1 -1
  54. package/dist/analytics/dispatch.d.ts +4 -4
  55. package/dist/analytics/index.js +19 -19
  56. package/dist/analytics/index.mjs +7 -7
  57. package/dist/analytics/send-gate.d.ts +8 -37
  58. package/dist/analytics/send-gate.d.ts.map +1 -1
  59. package/dist/{api-NTHZ6PAW.mjs → api-D745LGGU.mjs} +3 -3
  60. package/dist/api-D745LGGU.mjs.map +1 -0
  61. package/dist/{api-N5OLQXYN.js → api-XR5APCH3.js} +3 -3
  62. package/dist/api-XR5APCH3.js.map +1 -0
  63. package/dist/blog/index.js +20 -20
  64. package/dist/blog/index.mjs +3 -3
  65. package/dist/blog/server-ui.js +14 -14
  66. package/dist/blog/server-ui.mjs +2 -2
  67. package/dist/{chunk-HMFFAUCD.js → chunk-3DWIYCQX.js} +2 -2
  68. package/dist/chunk-3DWIYCQX.js.map +1 -0
  69. package/dist/{chunk-3EPMDPWI.js → chunk-3SDMJMN2.js} +5 -5
  70. package/dist/{chunk-3EPMDPWI.js.map → chunk-3SDMJMN2.js.map} +1 -1
  71. package/dist/{chunk-LIYSLNEK.mjs → chunk-473WDGQZ.mjs} +3 -3
  72. package/dist/{chunk-LIYSLNEK.mjs.map → chunk-473WDGQZ.mjs.map} +1 -1
  73. package/dist/chunk-4U5NCKQY.mjs +39 -0
  74. package/dist/chunk-4U5NCKQY.mjs.map +1 -0
  75. package/dist/{chunk-ITFZZ6YT.js → chunk-53KMRZT7.js} +3 -3
  76. package/dist/{chunk-ITFZZ6YT.js.map → chunk-53KMRZT7.js.map} +1 -1
  77. package/dist/{chunk-N6AVWMIB.mjs → chunk-5KIEZHVK.mjs} +19 -18
  78. package/dist/chunk-5KIEZHVK.mjs.map +1 -0
  79. package/dist/{chunk-ZLPXFV5Y.js → chunk-5KIO6FXE.js} +5 -5
  80. package/dist/{chunk-ZLPXFV5Y.js.map → chunk-5KIO6FXE.js.map} +1 -1
  81. package/dist/chunk-5RNAUYWE.js +50 -0
  82. package/dist/chunk-5RNAUYWE.js.map +1 -0
  83. package/dist/{chunk-ACTLQ2RH.mjs → chunk-5UFDHGFE.mjs} +4 -4
  84. package/dist/chunk-5UFDHGFE.mjs.map +1 -0
  85. package/dist/{chunk-RO55G3OA.mjs → chunk-64BOVMXG.mjs} +3 -3
  86. package/dist/{chunk-RO55G3OA.mjs.map → chunk-64BOVMXG.mjs.map} +1 -1
  87. package/dist/{chunk-G5I3XEQS.mjs → chunk-6OP5XSMM.mjs} +3 -3
  88. package/dist/{chunk-G5I3XEQS.mjs.map → chunk-6OP5XSMM.mjs.map} +1 -1
  89. package/dist/{chunk-7Y2UPFSY.mjs → chunk-7AUDKXY5.mjs} +3 -3
  90. package/dist/{chunk-7Y2UPFSY.mjs.map → chunk-7AUDKXY5.mjs.map} +1 -1
  91. package/dist/{chunk-A2VLEORI.mjs → chunk-7C7XO5HX.mjs} +3 -3
  92. package/dist/{chunk-A2VLEORI.mjs.map → chunk-7C7XO5HX.mjs.map} +1 -1
  93. package/dist/chunk-A6UYV475.mjs +45 -0
  94. package/dist/chunk-A6UYV475.mjs.map +1 -0
  95. package/dist/{chunk-SZHKNGNR.mjs → chunk-AEARU24Q.mjs} +40 -26
  96. package/dist/chunk-AEARU24Q.mjs.map +1 -0
  97. package/dist/{chunk-ZDFVYSKK.mjs → chunk-AHZR4VGY.mjs} +5 -5
  98. package/dist/{chunk-ZDFVYSKK.mjs.map → chunk-AHZR4VGY.mjs.map} +1 -1
  99. package/dist/{chunk-4WQB2ORG.js → chunk-AY7JBGYC.js} +15 -15
  100. package/dist/chunk-AY7JBGYC.js.map +1 -0
  101. package/dist/{chunk-5737U6DI.js → chunk-B64AZC6P.js} +15 -15
  102. package/dist/{chunk-5737U6DI.js.map → chunk-B64AZC6P.js.map} +1 -1
  103. package/dist/{chunk-ZY5AVC4P.js → chunk-B6O7D5U4.js} +55 -49
  104. package/dist/chunk-B6O7D5U4.js.map +1 -0
  105. package/dist/{chunk-LHYVFWHL.js → chunk-BWSMUSDB.js} +8 -8
  106. package/dist/{chunk-LHYVFWHL.js.map → chunk-BWSMUSDB.js.map} +1 -1
  107. package/dist/{chunk-WSUQ76LN.js → chunk-BZLIOT7Q.js} +18 -18
  108. package/dist/{chunk-WSUQ76LN.js.map → chunk-BZLIOT7Q.js.map} +1 -1
  109. package/dist/{chunk-HH5KGXTK.mjs → chunk-C2MSD2UM.mjs} +4 -4
  110. package/dist/{chunk-HH5KGXTK.mjs.map → chunk-C2MSD2UM.mjs.map} +1 -1
  111. package/dist/{chunk-DPDV5Z4G.js → chunk-CQRLKNHQ.js} +12 -12
  112. package/dist/{chunk-DPDV5Z4G.js.map → chunk-CQRLKNHQ.js.map} +1 -1
  113. package/dist/{chunk-SJXGIUHP.mjs → chunk-CQS5ZYI6.mjs} +22 -9
  114. package/dist/chunk-CQS5ZYI6.mjs.map +1 -0
  115. package/dist/{chunk-LUYUFILE.js → chunk-DHIWR7CG.js} +4 -4
  116. package/dist/{chunk-LUYUFILE.js.map → chunk-DHIWR7CG.js.map} +1 -1
  117. package/dist/chunk-DQUBETXH.mjs +6 -0
  118. package/dist/{chunk-7U7C6XRI.mjs.map → chunk-DQUBETXH.mjs.map} +1 -1
  119. package/dist/chunk-ESP5RMB7.js +42 -0
  120. package/dist/chunk-ESP5RMB7.js.map +1 -0
  121. package/dist/chunk-G6WF4G3E.js +43 -0
  122. package/dist/chunk-G6WF4G3E.js.map +1 -0
  123. package/dist/{chunk-XWF7QPIP.mjs → chunk-GJ6NOLGC.mjs} +3 -3
  124. package/dist/{chunk-XWF7QPIP.mjs.map → chunk-GJ6NOLGC.mjs.map} +1 -1
  125. package/dist/{chunk-MTANHZKJ.mjs → chunk-GPLCPMVD.mjs} +7 -7
  126. package/dist/{chunk-MTANHZKJ.mjs.map → chunk-GPLCPMVD.mjs.map} +1 -1
  127. package/dist/{chunk-QWLL3B6U.js → chunk-H3D3ZGOJ.js} +26 -23
  128. package/dist/chunk-H3D3ZGOJ.js.map +1 -0
  129. package/dist/{chunk-NUH245XK.mjs → chunk-H44XZUOV.mjs} +16 -13
  130. package/dist/chunk-H44XZUOV.mjs.map +1 -0
  131. package/dist/{chunk-MIFP6QEQ.mjs → chunk-HIHAXEPD.mjs} +4 -4
  132. package/dist/{chunk-MIFP6QEQ.mjs.map → chunk-HIHAXEPD.mjs.map} +1 -1
  133. package/dist/{chunk-UOLY4NXK.mjs → chunk-IYCLN3XS.mjs} +15 -34
  134. package/dist/chunk-IYCLN3XS.mjs.map +1 -0
  135. package/dist/{chunk-HBMF3M5F.js → chunk-JE5DWAE6.js} +4 -4
  136. package/dist/{chunk-HBMF3M5F.js.map → chunk-JE5DWAE6.js.map} +1 -1
  137. package/dist/{chunk-KQ3VAOAF.mjs → chunk-JNABXCLY.mjs} +4 -4
  138. package/dist/{chunk-KQ3VAOAF.mjs.map → chunk-JNABXCLY.mjs.map} +1 -1
  139. package/dist/{chunk-3TXX5KIN.js → chunk-JNRHTZL4.js} +2 -2
  140. package/dist/{chunk-3TXX5KIN.js.map → chunk-JNRHTZL4.js.map} +1 -1
  141. package/dist/{chunk-I4PDSDVE.mjs → chunk-K2V3ZW36.mjs} +3 -3
  142. package/dist/{chunk-I4PDSDVE.mjs.map → chunk-K2V3ZW36.mjs.map} +1 -1
  143. package/dist/{chunk-L2LJQIM3.js → chunk-KPKQKFT4.js} +11 -11
  144. package/dist/chunk-KPKQKFT4.js.map +1 -0
  145. package/dist/chunk-KSL3WA2I.js +8 -0
  146. package/dist/{chunk-UTOHMK52.js.map → chunk-KSL3WA2I.js.map} +1 -1
  147. package/dist/{chunk-VWDT7H6L.js → chunk-KY6M76JW.js} +3 -3
  148. package/dist/{chunk-VWDT7H6L.js.map → chunk-KY6M76JW.js.map} +1 -1
  149. package/dist/{chunk-EBMPXFOP.mjs → chunk-LCSYJXIO.mjs} +3 -3
  150. package/dist/{chunk-EBMPXFOP.mjs.map → chunk-LCSYJXIO.mjs.map} +1 -1
  151. package/dist/{chunk-AWFZIXCT.js → chunk-N2PGTPWN.js} +25 -12
  152. package/dist/chunk-N2PGTPWN.js.map +1 -0
  153. package/dist/chunk-NSWO43XW.mjs +39 -0
  154. package/dist/chunk-NSWO43XW.mjs.map +1 -0
  155. package/dist/{chunk-KMGGAL2X.js → chunk-NZSFOZJV.js} +40 -26
  156. package/dist/chunk-NZSFOZJV.js.map +1 -0
  157. package/dist/{chunk-JJ26JKBJ.mjs → chunk-OA7KKOAK.mjs} +25 -31
  158. package/dist/chunk-OA7KKOAK.mjs.map +1 -0
  159. package/dist/{chunk-GQ6CUOLA.js → chunk-OC7AO7XS.js} +15 -15
  160. package/dist/{chunk-GQ6CUOLA.js.map → chunk-OC7AO7XS.js.map} +1 -1
  161. package/dist/{chunk-HDDV63XJ.mjs → chunk-QNPVVWR7.mjs} +3 -3
  162. package/dist/{chunk-HDDV63XJ.mjs.map → chunk-QNPVVWR7.mjs.map} +1 -1
  163. package/dist/{chunk-URVGBWCP.js → chunk-R3KTBKSW.js} +4 -4
  164. package/dist/{chunk-URVGBWCP.js.map → chunk-R3KTBKSW.js.map} +1 -1
  165. package/dist/{chunk-6CUBSQMD.mjs → chunk-RIYAMYLV.mjs} +3 -3
  166. package/dist/{chunk-6CUBSQMD.mjs.map → chunk-RIYAMYLV.mjs.map} +1 -1
  167. package/dist/{chunk-B4BFQSSS.mjs → chunk-RU54J2PY.mjs} +4 -4
  168. package/dist/chunk-RU54J2PY.mjs.map +1 -0
  169. package/dist/{chunk-7IPSQ5JR.js → chunk-S4RC6VAQ.js} +21 -20
  170. package/dist/chunk-S4RC6VAQ.js.map +1 -0
  171. package/dist/{chunk-3DPXOZAU.mjs → chunk-SHLWA6JY.mjs} +2 -2
  172. package/dist/chunk-SHLWA6JY.mjs.map +1 -0
  173. package/dist/{chunk-OXZYP32B.js → chunk-SYGGZZMU.js} +21 -17
  174. package/dist/chunk-SYGGZZMU.js.map +1 -0
  175. package/dist/{chunk-LF4L3ZP5.js → chunk-T5VTQUNF.js} +8 -8
  176. package/dist/{chunk-LF4L3ZP5.js.map → chunk-T5VTQUNF.js.map} +1 -1
  177. package/dist/{chunk-UOTXSWKZ.mjs → chunk-TP7H6BSK.mjs} +2 -2
  178. package/dist/{chunk-UOTXSWKZ.mjs.map → chunk-TP7H6BSK.mjs.map} +1 -1
  179. package/dist/{chunk-N6X76QUF.mjs → chunk-USKIL6V6.mjs} +3 -3
  180. package/dist/{chunk-N6X76QUF.mjs.map → chunk-USKIL6V6.mjs.map} +1 -1
  181. package/dist/{chunk-2KIGFOPM.js → chunk-UU47DGHE.js} +25 -44
  182. package/dist/chunk-UU47DGHE.js.map +1 -0
  183. package/dist/{chunk-B36PTS7B.mjs → chunk-VHZ4LHQT.mjs} +48 -42
  184. package/dist/chunk-VHZ4LHQT.mjs.map +1 -0
  185. package/dist/{chunk-7PLH3H3W.js → chunk-X5TCH7VZ.js} +3 -3
  186. package/dist/{chunk-7PLH3H3W.js.map → chunk-X5TCH7VZ.js.map} +1 -1
  187. package/dist/{chunk-LBS4PRC7.js → chunk-XK5AIWQG.js} +3 -3
  188. package/dist/{chunk-LBS4PRC7.js.map → chunk-XK5AIWQG.js.map} +1 -1
  189. package/dist/{chunk-U53KN4SA.js → chunk-XR32C47O.js} +26 -32
  190. package/dist/chunk-XR32C47O.js.map +1 -0
  191. package/dist/{chunk-DQM5GR2P.mjs → chunk-YCI36ZUS.mjs} +18 -14
  192. package/dist/chunk-YCI36ZUS.mjs.map +1 -0
  193. package/dist/{chunk-VA36CJRV.js → chunk-YYN4YZYZ.js} +4 -4
  194. package/dist/{chunk-VA36CJRV.js.map → chunk-YYN4YZYZ.js.map} +1 -1
  195. package/dist/cli/agent/checks.d.ts.map +1 -1
  196. package/dist/cli/agent/ssr-bailout.d.ts +27 -0
  197. package/dist/cli/agent/ssr-bailout.d.ts.map +1 -0
  198. package/dist/cli/agent/ssr-bailout.test.d.ts +2 -0
  199. package/dist/cli/agent/ssr-bailout.test.d.ts.map +1 -0
  200. package/dist/cli/api/{uptrade.d.ts → sonor.d.ts} +3 -2
  201. package/dist/cli/api/sonor.d.ts.map +1 -0
  202. package/dist/cli/codemod/transforms.d.ts.map +1 -1
  203. package/dist/cli/commands/config-regression.test.d.ts +2 -0
  204. package/dist/cli/commands/config-regression.test.d.ts.map +1 -0
  205. package/dist/cli/commands/faqs.d.ts.map +1 -1
  206. package/dist/cli/commands/images.d.ts.map +1 -1
  207. package/dist/cli/commands/locations.d.ts.map +1 -1
  208. package/dist/cli/commands/migrate.d.ts.map +1 -1
  209. package/dist/cli/commands/setup.d.ts.map +1 -1
  210. package/dist/cli/config.d.ts +31 -0
  211. package/dist/cli/config.d.ts.map +1 -0
  212. package/dist/cli/config.test.d.ts +2 -0
  213. package/dist/cli/config.test.d.ts.map +1 -0
  214. package/dist/cli/index.js +494 -518
  215. package/dist/cli/index.js.map +1 -1
  216. package/dist/cli/index.mjs +487 -511
  217. package/dist/cli/index.mjs.map +1 -1
  218. package/dist/cli/migrator/index.d.ts +1 -0
  219. package/dist/cli/migrator/index.d.ts.map +1 -1
  220. package/dist/cli/state.d.ts +7 -0
  221. package/dist/cli/state.d.ts.map +1 -0
  222. package/dist/cli/state.test.d.ts +2 -0
  223. package/dist/cli/state.test.d.ts.map +1 -0
  224. package/dist/client/index.d.ts +1 -0
  225. package/dist/client/index.d.ts.map +1 -1
  226. package/dist/client/index.js +20 -7
  227. package/dist/client/index.js.map +1 -1
  228. package/dist/client/index.mjs +5 -4
  229. package/dist/client/index.mjs.map +1 -1
  230. package/dist/cms/index.js.map +1 -1
  231. package/dist/cms/index.mjs.map +1 -1
  232. package/dist/cms/sanity-image.d.ts +1 -1
  233. package/dist/commerce/index.js +59 -59
  234. package/dist/commerce/index.mjs +8 -8
  235. package/dist/engage/ChatWidget.d.ts.map +1 -1
  236. package/dist/engage/EngageWidget.d.ts +4 -4
  237. package/dist/engage/EngageWidget.d.ts.map +1 -1
  238. package/dist/engage/chat-launcher.test.d.ts +2 -0
  239. package/dist/engage/chat-launcher.test.d.ts.map +1 -0
  240. package/dist/engage/index.js +13 -10
  241. package/dist/engage/index.js.map +1 -1
  242. package/dist/engage/index.mjs +10 -7
  243. package/dist/engage/index.mjs.map +1 -1
  244. package/dist/engage/launcher-placement.d.ts +56 -0
  245. package/dist/engage/launcher-placement.d.ts.map +1 -0
  246. package/dist/engage/launcher-placement.test.d.ts +2 -0
  247. package/dist/engage/launcher-placement.test.d.ts.map +1 -0
  248. package/dist/engage/types.d.ts +41 -7
  249. package/dist/engage/types.d.ts.map +1 -1
  250. package/dist/fleet/FleetHeartbeat.d.ts +3 -2
  251. package/dist/fleet/FleetHeartbeat.d.ts.map +1 -1
  252. package/dist/fleet/heartbeat.d.ts +3 -2
  253. package/dist/fleet/heartbeat.d.ts.map +1 -1
  254. package/dist/fleet/heartbeat.test.d.ts +2 -0
  255. package/dist/fleet/heartbeat.test.d.ts.map +1 -0
  256. package/dist/fleet/index.js +9 -8
  257. package/dist/fleet/index.mjs +5 -4
  258. package/dist/forms/index.js +16 -16
  259. package/dist/forms/index.mjs +9 -9
  260. package/dist/forms/server.js +10 -10
  261. package/dist/forms/server.mjs +8 -8
  262. package/dist/forms/static.js +7 -7
  263. package/dist/forms/static.mjs +6 -6
  264. package/dist/images/ManagedImage.d.ts.map +1 -1
  265. package/dist/images/index.js +11 -11
  266. package/dist/images/index.mjs +4 -4
  267. package/dist/index.js +66 -66
  268. package/dist/index.mjs +12 -12
  269. package/dist/layout/SiteKitClientProviders.d.ts.map +1 -1
  270. package/dist/layout/client.d.ts.map +1 -1
  271. package/dist/layout/client.js +9 -8
  272. package/dist/layout/client.mjs +8 -7
  273. package/dist/layout/index.js +11 -10
  274. package/dist/layout/index.js.map +1 -1
  275. package/dist/layout/index.mjs +9 -8
  276. package/dist/layout/index.mjs.map +1 -1
  277. package/dist/layout/types.d.ts +9 -3
  278. package/dist/layout/types.d.ts.map +1 -1
  279. package/dist/llms/generateLLMsTxt.d.ts.map +1 -1
  280. package/dist/llms/index.js +12 -12
  281. package/dist/llms/index.mjs +2 -2
  282. package/dist/llms/types.d.ts +7 -1
  283. package/dist/llms/types.d.ts.map +1 -1
  284. package/dist/maps/index.js +5 -5
  285. package/dist/maps/index.mjs +3 -3
  286. package/dist/mcp/WebMcpTools.d.ts +5 -2
  287. package/dist/mcp/WebMcpTools.d.ts.map +1 -1
  288. package/dist/mcp/client.js.map +1 -1
  289. package/dist/mcp/client.mjs.map +1 -1
  290. package/dist/search/index.js +4 -4
  291. package/dist/search/index.mjs +3 -3
  292. package/dist/seo/LocationPageContent.d.ts +6 -5
  293. package/dist/seo/LocationPageContent.d.ts.map +1 -1
  294. package/dist/seo/api.d.ts +4 -5
  295. package/dist/seo/api.d.ts.map +1 -1
  296. package/dist/seo/client.js +6 -6
  297. package/dist/seo/client.mjs +5 -5
  298. package/dist/seo/index.js +43 -43
  299. package/dist/seo/index.js.map +1 -1
  300. package/dist/seo/index.mjs +9 -9
  301. package/dist/seo/index.mjs.map +1 -1
  302. package/dist/seo/routing.d.ts +9 -23
  303. package/dist/seo/routing.d.ts.map +1 -1
  304. package/dist/seo/server-api.d.ts +11 -5
  305. package/dist/seo/server-api.d.ts.map +1 -1
  306. package/dist/seo/server.js +18 -18
  307. package/dist/seo/server.mjs +2 -2
  308. package/dist/server/index.js +3 -3
  309. package/dist/server/index.mjs +2 -2
  310. package/dist/{server-api-HW4PL2L2.mjs → server-api-RG3ZL3DV.mjs} +3 -3
  311. package/dist/{server-api-HW4PL2L2.mjs.map → server-api-RG3ZL3DV.mjs.map} +1 -1
  312. package/dist/{server-api-DB2SIUP4.js → server-api-RYJQAUGO.js} +21 -21
  313. package/dist/{server-api-DB2SIUP4.js.map → server-api-RYJQAUGO.js.map} +1 -1
  314. package/dist/shared/reporting-gate.d.ts +43 -0
  315. package/dist/shared/reporting-gate.d.ts.map +1 -0
  316. package/dist/shared/version.d.ts +1 -1
  317. package/dist/shared/visual-viewport-gap.d.ts +52 -0
  318. package/dist/shared/visual-viewport-gap.d.ts.map +1 -0
  319. package/dist/shared/visual-viewport-gap.test.d.ts +2 -0
  320. package/dist/shared/visual-viewport-gap.test.d.ts.map +1 -0
  321. package/dist/signal/index.js +11 -11
  322. package/dist/signal/index.mjs +2 -2
  323. package/dist/sitemap/index.js +2 -2
  324. package/dist/sitemap/index.mjs +1 -1
  325. package/dist/sync/AddToCalendar.d.ts +19 -0
  326. package/dist/sync/AddToCalendar.d.ts.map +1 -0
  327. package/dist/sync/BookingWidget.d.ts.map +1 -1
  328. package/dist/sync/add-to-calendar.test.d.ts +2 -0
  329. package/dist/sync/add-to-calendar.test.d.ts.map +1 -0
  330. package/dist/sync/api-errors.test.d.ts +2 -0
  331. package/dist/sync/api-errors.test.d.ts.map +1 -0
  332. package/dist/sync/api.d.ts.map +1 -1
  333. package/dist/sync/index.js +17 -17
  334. package/dist/sync/index.mjs +4 -4
  335. package/dist/sync/types.d.ts +14 -0
  336. package/dist/sync/types.d.ts.map +1 -1
  337. package/dist/types.d.ts +9 -0
  338. package/dist/types.d.ts.map +1 -1
  339. package/package.json +4 -4
  340. package/skills/site-kit/SKILL.md +8 -3
  341. package/dist/AnalyticsProvider-2XIOMRCN.mjs +0 -11
  342. package/dist/AnalyticsProvider-Y2P2BPOI.js +0 -32
  343. package/dist/ChatWidget-2OFWPCWF.js +0 -20
  344. package/dist/ChatWidget-4AOGHYXQ.mjs +0 -11
  345. package/dist/EngageWidget-SFO2XRNG.mjs +0 -9
  346. package/dist/EngageWidget-T4KAAD3G.js +0 -18
  347. package/dist/ManagedForm-5G37EDJT.mjs +0 -14
  348. package/dist/ManagedForm-JCHGBBQW.js +0 -23
  349. package/dist/SitemapSync-3LUZWBTB.js +0 -18
  350. package/dist/SitemapSync-MYSTLJOM.mjs +0 -9
  351. package/dist/api-N5OLQXYN.js.map +0 -1
  352. package/dist/api-NTHZ6PAW.mjs.map +0 -1
  353. package/dist/chunk-2KIGFOPM.js.map +0 -1
  354. package/dist/chunk-3DPXOZAU.mjs.map +0 -1
  355. package/dist/chunk-4WQB2ORG.js.map +0 -1
  356. package/dist/chunk-7IPSQ5JR.js.map +0 -1
  357. package/dist/chunk-7U7C6XRI.mjs +0 -6
  358. package/dist/chunk-ACTLQ2RH.mjs.map +0 -1
  359. package/dist/chunk-AWFZIXCT.js.map +0 -1
  360. package/dist/chunk-B36PTS7B.mjs.map +0 -1
  361. package/dist/chunk-B4BFQSSS.mjs.map +0 -1
  362. package/dist/chunk-DQM5GR2P.mjs.map +0 -1
  363. package/dist/chunk-HMFFAUCD.js.map +0 -1
  364. package/dist/chunk-JJ26JKBJ.mjs.map +0 -1
  365. package/dist/chunk-KMGGAL2X.js.map +0 -1
  366. package/dist/chunk-L2LJQIM3.js.map +0 -1
  367. package/dist/chunk-N6AVWMIB.mjs.map +0 -1
  368. package/dist/chunk-NUH245XK.mjs.map +0 -1
  369. package/dist/chunk-NVSWTDWU.mjs +0 -25
  370. package/dist/chunk-NVSWTDWU.mjs.map +0 -1
  371. package/dist/chunk-OL2QBWAU.js +0 -29
  372. package/dist/chunk-OL2QBWAU.js.map +0 -1
  373. package/dist/chunk-OXZYP32B.js.map +0 -1
  374. package/dist/chunk-QWLL3B6U.js.map +0 -1
  375. package/dist/chunk-SJXGIUHP.mjs.map +0 -1
  376. package/dist/chunk-SZHKNGNR.mjs.map +0 -1
  377. package/dist/chunk-U53KN4SA.js.map +0 -1
  378. package/dist/chunk-UOLY4NXK.mjs.map +0 -1
  379. package/dist/chunk-UTOHMK52.js +0 -8
  380. package/dist/chunk-ZY5AVC4P.js.map +0 -1
  381. package/dist/cli/api/uptrade.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { getApiConfig } from './chunk-XWF7QPIP.mjs';
1
+ import { getApiConfig } from './chunk-GJ6NOLGC.mjs';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
 
4
4
  function HoneypotField({ name, value, onChange }) {
@@ -56,5 +56,5 @@ function NativeFallbackFields({ config, returnTo }) {
56
56
  }
57
57
 
58
58
  export { HoneypotField, NativeFallbackFields, nativeFormProps };
59
- //# sourceMappingURL=chunk-EBMPXFOP.mjs.map
60
- //# sourceMappingURL=chunk-EBMPXFOP.mjs.map
59
+ //# sourceMappingURL=chunk-LCSYJXIO.mjs.map
60
+ //# sourceMappingURL=chunk-LCSYJXIO.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/forms/HoneypotField.tsx","../src/forms/native-fallback.tsx"],"names":["jsx"],"mappings":";;;AAqCO,SAAS,aAAA,CAAc,EAAE,IAAA,EAAM,KAAA,EAAO,UAAS,EAAuB;AAC3E,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,KAAa,UAAA;AACxC,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,MAAA;AAAA,MACL,IAAA;AAAA,MACA,QAAA,EAAU,EAAA;AAAA,MACV,YAAA,EAAa,cAAA;AAAA,MACb,aAAA,EAAY,MAAA;AAAA,MACZ,KAAA,EAAK,IAAA;AAAA,MACL,kBAAA,EAAiB,EAAA;AAAA,MAGjB,gBAAA,EAAe,EAAA;AAAA,MACf,eAAA,EAAc,MAAA;AAAA,MACd,gBAAA,EAAe,OAAA;AAAA,MACf,eAAA,EAAc,EAAA;AAAA,MACd,KAAA,EAAO;AAAA,QACL,QAAA,EAAU,UAAA;AAAA,QACV,IAAA,EAAM,KAAA;AAAA,QACN,KAAA,EAAO,CAAA;AAAA,QACP,MAAA,EAAQ,CAAA;AAAA,QACR,QAAA,EAAU,QAAA;AAAA,QACV,OAAA,EAAS,CAAA;AAAA,QACT,UAAA,EAAY,QAAA;AAAA,QACZ,aAAA,EAAe;AAAA,OACjB;AAAA,MACC,GAAI,WAAA,GACD;AAAA,QACE,OAAO,KAAA,IAAS,EAAA;AAAA,QAChB,QAAA,EAAU,CAAC,CAAA,KAA2C;AACpD,UAAA,QAAA,CAAU,CAAA,CAAE,OAAO,KAAK,CAAA;AACxB,UAAA,IAAI,CAAA,CAAE,OAAO,KAAA,EAAO;AAElB,YAAA,OAAA,CAAQ,KAAK,4BAA4B,CAAA;AAAA,UAC3C;AAAA,QACF;AAAA,OACF,GACA,EAAE,YAAA,EAAc,EAAA;AAAG;AAAA,GACzB;AAEJ;ACjDA,SAAS,eAAe,MAAA,EAAuD;AAC7E,EAAA,OAAO,CAAC,CAAC,MAAA,EAAQ,YAAA,IAAgB,CAAC,MAAA,CAAO,aAAA;AAC3C;AAGO,SAAS,gBACd,MAAA,EACsC;AACtC,EAAA,IAAI,CAAC,cAAA,CAAe,MAAM,CAAA,SAAU,EAAC;AACrC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,YAAA,EAAa;AAChC,EAAA,OAAO,EAAE,MAAA,EAAQ,CAAA,EAAG,MAAM,CAAA,+BAAA,CAAA,EAAmC,QAAQ,MAAA,EAAO;AAC9E;AAaO,SAAS,oBAAA,CAAqB,EAAE,MAAA,EAAQ,QAAA,EAAS,EAA8B;AACpF,EAAA,IAAI,CAAC,cAAA,CAAe,MAAM,CAAA,EAAG,OAAO,IAAA;AACpC,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAA,GAAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,QAAA,EAAS,IAAA,EAAK,aAAY,KAAA,EAAO,MAAA,CAAQ,YAAA,EAAc,QAAA,EAAQ,IAAA,EAAC,CAAA;AAAA,IAC3E,QAAA,mBAAWA,GAAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,QAAA,EAAS,IAAA,EAAK,YAAA,EAAa,KAAA,EAAO,QAAA,EAAU,QAAA,EAAQ,IAAA,EAAC,CAAA,GAAK;AAAA,GAAA,EACpF,CAAA;AAEJ","file":"chunk-EBMPXFOP.mjs","sourcesContent":["/**\n * Single source of truth for the honeypot input — rendered by BOTH form\n * experiences (classic and stage) inside their <form>. The customRender path\n * deliberately gets none (documented limitation: custom renders lose the\n * honeypot, which is why alternate experiences must be render branches).\n *\n * Invariants (do not weaken any of these):\n * - `inert` blocks focus/interaction at the browser level, surviving hostile\n * site CSS that could defeat the inline styles.\n * - data-sk-honeypot gives site CSS a stable opt-OUT hook.\n * - Controlled input: bots filling via JS still fire React onChange, so the\n * value reaches submitForm's data payload.\n * - Name comes from config (`honeypot_field || DEFAULT_HONEYPOT_FIELD` from\n * the shared contract) — resolved by the caller, never forked here.\n * - The trap must be invisible to AUTOFILL as well as to people. A browser or\n * password manager filling a hidden input flags a real visitor as a bot, and\n * because the value is stripped server-side the mistake is undiagnosable\n * after the fact. `autocomplete=\"off\"` does not achieve this — it is the one\n * value Chrome deliberately ignores for contact/address autofill — so the\n * trap declares `new-password` (never offered saved contact data) plus the\n * documented per-manager opt-outs.\n */\n\nimport React from 'react'\n\nexport interface HoneypotFieldProps {\n name: string\n value?: string\n /**\n * Omit for STATIC mode — an uncontrolled trap a Server Component can render.\n * The trap's whole job is server-side (the value is read off the submission\n * and stripped), so it needs no client state to work; the controlled form is\n * only so the hydrated JSON path can read it back out of React state.\n */\n onChange?: (value: string) => void\n}\n\nexport function HoneypotField({ name, value, onChange }: HoneypotFieldProps) {\n const interactive = typeof onChange === 'function'\n return (\n <input\n type=\"text\"\n name={name}\n tabIndex={-1}\n autoComplete=\"new-password\"\n aria-hidden=\"true\"\n inert\n data-sk-honeypot=\"\"\n // Password-manager opt-outs: 1Password, LastPass, Dashlane, Bitwarden.\n // Each ignores its own attribute; none respects autocomplete alone.\n data-1p-ignore=\"\"\n data-lpignore=\"true\"\n data-form-type=\"other\"\n data-bwignore=\"\"\n style={{\n position: 'absolute',\n left: -9999,\n width: 1,\n height: 1,\n overflow: 'hidden',\n opacity: 0,\n visibility: 'hidden',\n pointerEvents: 'none',\n }}\n {...(interactive\n ? {\n value: value ?? '',\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange!(e.target.value)\n if (e.target.value) {\n // Bot detected\n console.warn('[Forms] Honeypot triggered')\n }\n },\n }\n : { defaultValue: '' })}\n />\n )\n}\n","'use client'\n\n/**\n * No-JS native submission fallback — the floor under every managed form.\n *\n * The classic form is the SSR/no-JS surface (experiences are post-hydration\n * chunks), so it alone carries a real `action`/`method` pointing at\n * sonor-api's POST /api/public/forms/submit-native. With JS running, the\n * form's onSubmit preventDefault()s and the JSON path wins; without JS the\n * browser performs an ordinary form-encoded POST and the lead still lands.\n *\n * Auth rides in the hidden `_sk_token` field: a signed, single-purpose\n * credential minted by the api-key-authenticated forms/config endpoint\n * (`native_token` in the response). No token in the config (older API, or no\n * signing secret) means no fallback — the form keeps its historical behavior\n * rather than pointing at an endpoint that will reject it.\n *\n * Multi-step forms are excluded: step navigation is JS, and a native POST of\n * step-1 fields alone fails whole-form validation server-side. Single-step\n * forms are the overwhelming lead-capture case.\n *\n * Single source of truth for the gating — the form attrs and the hidden\n * fields must always agree, so both read the same predicate.\n */\n\nimport React from 'react'\nimport type { ManagedFormConfig } from './types'\nimport { getApiConfig } from './submitForm'\n\nfunction nativeEligible(config: ManagedFormConfig | null | undefined): boolean {\n return !!config?.native_token && !config.is_multi_step\n}\n\n/** `action`/`method` for the classic <form> — empty when ineligible. */\nexport function nativeFormProps(\n config: ManagedFormConfig | null | undefined,\n): { action?: string; method?: 'post' } {\n if (!nativeEligible(config)) return {}\n const { apiUrl } = getApiConfig()\n return { action: `${apiUrl}/api/public/forms/submit-native`, method: 'post' }\n}\n\nexport interface NativeFallbackFieldsProps {\n config: ManagedFormConfig | null | undefined\n /**\n * Absolute URL the native 303 should land on (usually the page hosting the\n * form). Optional — without it the server falls back to the Referer origin,\n * which loses the path but still returns the visitor to the right site.\n */\n returnTo?: string\n}\n\n/** Hidden control fields the native endpoint reads (`_sk_*` namespace). */\nexport function NativeFallbackFields({ config, returnTo }: NativeFallbackFieldsProps) {\n if (!nativeEligible(config)) return null\n return (\n <>\n <input type=\"hidden\" name=\"_sk_token\" value={config!.native_token} readOnly />\n {returnTo ? <input type=\"hidden\" name=\"_sk_return\" value={returnTo} readOnly /> : null}\n </>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/forms/HoneypotField.tsx","../src/forms/native-fallback.tsx"],"names":["jsx"],"mappings":";;;AAqCO,SAAS,aAAA,CAAc,EAAE,IAAA,EAAM,KAAA,EAAO,UAAS,EAAuB;AAC3E,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,KAAa,UAAA;AACxC,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,MAAA;AAAA,MACL,IAAA;AAAA,MACA,QAAA,EAAU,EAAA;AAAA,MACV,YAAA,EAAa,cAAA;AAAA,MACb,aAAA,EAAY,MAAA;AAAA,MACZ,KAAA,EAAK,IAAA;AAAA,MACL,kBAAA,EAAiB,EAAA;AAAA,MAGjB,gBAAA,EAAe,EAAA;AAAA,MACf,eAAA,EAAc,MAAA;AAAA,MACd,gBAAA,EAAe,OAAA;AAAA,MACf,eAAA,EAAc,EAAA;AAAA,MACd,KAAA,EAAO;AAAA,QACL,QAAA,EAAU,UAAA;AAAA,QACV,IAAA,EAAM,KAAA;AAAA,QACN,KAAA,EAAO,CAAA;AAAA,QACP,MAAA,EAAQ,CAAA;AAAA,QACR,QAAA,EAAU,QAAA;AAAA,QACV,OAAA,EAAS,CAAA;AAAA,QACT,UAAA,EAAY,QAAA;AAAA,QACZ,aAAA,EAAe;AAAA,OACjB;AAAA,MACC,GAAI,WAAA,GACD;AAAA,QACE,OAAO,KAAA,IAAS,EAAA;AAAA,QAChB,QAAA,EAAU,CAAC,CAAA,KAA2C;AACpD,UAAA,QAAA,CAAU,CAAA,CAAE,OAAO,KAAK,CAAA;AACxB,UAAA,IAAI,CAAA,CAAE,OAAO,KAAA,EAAO;AAElB,YAAA,OAAA,CAAQ,KAAK,4BAA4B,CAAA;AAAA,UAC3C;AAAA,QACF;AAAA,OACF,GACA,EAAE,YAAA,EAAc,EAAA;AAAG;AAAA,GACzB;AAEJ;ACjDA,SAAS,eAAe,MAAA,EAAuD;AAC7E,EAAA,OAAO,CAAC,CAAC,MAAA,EAAQ,YAAA,IAAgB,CAAC,MAAA,CAAO,aAAA;AAC3C;AAGO,SAAS,gBACd,MAAA,EACsC;AACtC,EAAA,IAAI,CAAC,cAAA,CAAe,MAAM,CAAA,SAAU,EAAC;AACrC,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,YAAA,EAAa;AAChC,EAAA,OAAO,EAAE,MAAA,EAAQ,CAAA,EAAG,MAAM,CAAA,+BAAA,CAAA,EAAmC,QAAQ,MAAA,EAAO;AAC9E;AAaO,SAAS,oBAAA,CAAqB,EAAE,MAAA,EAAQ,QAAA,EAAS,EAA8B;AACpF,EAAA,IAAI,CAAC,cAAA,CAAe,MAAM,CAAA,EAAG,OAAO,IAAA;AACpC,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAA,GAAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,QAAA,EAAS,IAAA,EAAK,aAAY,KAAA,EAAO,MAAA,CAAQ,YAAA,EAAc,QAAA,EAAQ,IAAA,EAAC,CAAA;AAAA,IAC3E,QAAA,mBAAWA,GAAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,QAAA,EAAS,IAAA,EAAK,YAAA,EAAa,KAAA,EAAO,QAAA,EAAU,QAAA,EAAQ,IAAA,EAAC,CAAA,GAAK;AAAA,GAAA,EACpF,CAAA;AAEJ","file":"chunk-LCSYJXIO.mjs","sourcesContent":["/**\n * Single source of truth for the honeypot input — rendered by BOTH form\n * experiences (classic and stage) inside their <form>. The customRender path\n * deliberately gets none (documented limitation: custom renders lose the\n * honeypot, which is why alternate experiences must be render branches).\n *\n * Invariants (do not weaken any of these):\n * - `inert` blocks focus/interaction at the browser level, surviving hostile\n * site CSS that could defeat the inline styles.\n * - data-sk-honeypot gives site CSS a stable opt-OUT hook.\n * - Controlled input: bots filling via JS still fire React onChange, so the\n * value reaches submitForm's data payload.\n * - Name comes from config (`honeypot_field || DEFAULT_HONEYPOT_FIELD` from\n * the shared contract) — resolved by the caller, never forked here.\n * - The trap must be invisible to AUTOFILL as well as to people. A browser or\n * password manager filling a hidden input flags a real visitor as a bot, and\n * because the value is stripped server-side the mistake is undiagnosable\n * after the fact. `autocomplete=\"off\"` does not achieve this — it is the one\n * value Chrome deliberately ignores for contact/address autofill — so the\n * trap declares `new-password` (never offered saved contact data) plus the\n * documented per-manager opt-outs.\n */\n\nimport React from 'react'\n\nexport interface HoneypotFieldProps {\n name: string\n value?: string\n /**\n * Omit for STATIC mode — an uncontrolled trap a Server Component can render.\n * The trap's whole job is server-side (the value is read off the submission\n * and stripped), so it needs no client state to work; the controlled form is\n * only so the hydrated JSON path can read it back out of React state.\n */\n onChange?: (value: string) => void\n}\n\nexport function HoneypotField({ name, value, onChange }: HoneypotFieldProps) {\n const interactive = typeof onChange === 'function'\n return (\n <input\n type=\"text\"\n name={name}\n tabIndex={-1}\n autoComplete=\"new-password\"\n aria-hidden=\"true\"\n inert\n data-sk-honeypot=\"\"\n // Password-manager opt-outs: 1Password, LastPass, Dashlane, Bitwarden.\n // Each ignores its own attribute; none respects autocomplete alone.\n data-1p-ignore=\"\"\n data-lpignore=\"true\"\n data-form-type=\"other\"\n data-bwignore=\"\"\n style={{\n position: 'absolute',\n left: -9999,\n width: 1,\n height: 1,\n overflow: 'hidden',\n opacity: 0,\n visibility: 'hidden',\n pointerEvents: 'none',\n }}\n {...(interactive\n ? {\n value: value ?? '',\n onChange: (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange!(e.target.value)\n if (e.target.value) {\n // Bot detected\n console.warn('[Forms] Honeypot triggered')\n }\n },\n }\n : { defaultValue: '' })}\n />\n )\n}\n","'use client'\n\n/**\n * No-JS native submission fallback — the floor under every managed form.\n *\n * The classic form is the SSR/no-JS surface (experiences are post-hydration\n * chunks), so it alone carries a real `action`/`method` pointing at\n * sonor-api's POST /api/public/forms/submit-native. With JS running, the\n * form's onSubmit preventDefault()s and the JSON path wins; without JS the\n * browser performs an ordinary form-encoded POST and the lead still lands.\n *\n * Auth rides in the hidden `_sk_token` field: a signed, single-purpose\n * credential minted by the api-key-authenticated forms/config endpoint\n * (`native_token` in the response). No token in the config (older API, or no\n * signing secret) means no fallback — the form keeps its historical behavior\n * rather than pointing at an endpoint that will reject it.\n *\n * Multi-step forms are excluded: step navigation is JS, and a native POST of\n * step-1 fields alone fails whole-form validation server-side. Single-step\n * forms are the overwhelming lead-capture case.\n *\n * Single source of truth for the gating — the form attrs and the hidden\n * fields must always agree, so both read the same predicate.\n */\n\nimport React from 'react'\nimport type { ManagedFormConfig } from './types'\nimport { getApiConfig } from './submitForm'\n\nfunction nativeEligible(config: ManagedFormConfig | null | undefined): boolean {\n return !!config?.native_token && !config.is_multi_step\n}\n\n/** `action`/`method` for the classic <form> — empty when ineligible. */\nexport function nativeFormProps(\n config: ManagedFormConfig | null | undefined,\n): { action?: string; method?: 'post' } {\n if (!nativeEligible(config)) return {}\n const { apiUrl } = getApiConfig()\n return { action: `${apiUrl}/api/public/forms/submit-native`, method: 'post' }\n}\n\nexport interface NativeFallbackFieldsProps {\n config: ManagedFormConfig | null | undefined\n /**\n * Absolute URL the native 303 should land on (usually the page hosting the\n * form). Optional — without it the server falls back to the Referer origin,\n * which loses the path but still returns the visitor to the right site.\n */\n returnTo?: string\n}\n\n/** Hidden control fields the native endpoint reads (`_sk_*` namespace). */\nexport function NativeFallbackFields({ config, returnTo }: NativeFallbackFieldsProps) {\n if (!nativeEligible(config)) return null\n return (\n <>\n <input type=\"hidden\" name=\"_sk_token\" value={config!.native_token} readOnly />\n {returnTo ? <input type=\"hidden\" name=\"_sk_return\" value={returnTo} readOnly /> : null}\n </>\n )\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkZLPXFV5Y_js = require('./chunk-ZLPXFV5Y.js');
5
- var chunkOXZYP32B_js = require('./chunk-OXZYP32B.js');
4
+ var chunk5KIO6FXE_js = require('./chunk-5KIO6FXE.js');
5
+ var chunkSYGGZZMU_js = require('./chunk-SYGGZZMU.js');
6
6
  var chunkOZ3FU4BT_js = require('./chunk-OZ3FU4BT.js');
7
7
  var chunkHGNSJXWT_js = require('./chunk-HGNSJXWT.js');
8
- var chunkLBS4PRC7_js = require('./chunk-LBS4PRC7.js');
8
+ var chunkXK5AIWQG_js = require('./chunk-XK5AIWQG.js');
9
9
  var chunkRC4WWQXR_js = require('./chunk-RC4WWQXR.js');
10
10
  var React = require('react');
11
11
  var dynamic = require('next/dynamic');
@@ -17,15 +17,15 @@ var React__default = /*#__PURE__*/_interopDefault(React);
17
17
  var dynamic__default = /*#__PURE__*/_interopDefault(dynamic);
18
18
 
19
19
  var LazyAnalyticsProvider = dynamic__default.default(
20
- () => import('./AnalyticsProvider-Y2P2BPOI.js').then((m) => ({ default: m.AnalyticsProvider })),
20
+ () => import('./AnalyticsProvider-6PXC7UDP.js').then((m) => ({ default: m.AnalyticsProvider })),
21
21
  { ssr: false }
22
22
  );
23
23
  var LazyEngageWidget = dynamic__default.default(
24
- () => import('./EngageWidget-T4KAAD3G.js').then((m) => ({ default: m.EngageWidget })),
24
+ () => import('./EngageWidget-Z7RC2INM.js').then((m) => ({ default: m.EngageWidget })),
25
25
  { ssr: false }
26
26
  );
27
27
  var LazySitemapSync = dynamic__default.default(
28
- () => import('./SitemapSync-3LUZWBTB.js').then((m) => ({ default: m.SitemapSync })),
28
+ () => import('./SitemapSync-XK4JKCS7.js').then((m) => ({ default: m.SitemapSync })),
29
29
  { ssr: false }
30
30
  );
31
31
  function SiteKitClientProviders({
@@ -45,7 +45,7 @@ function SiteKitClientProviders({
45
45
  const modulesReady = chunkHGNSJXWT_js.useDeferredActivation(defer);
46
46
  const analyticsConfig = typeof analytics === "object" ? analytics : {};
47
47
  const site = chunkOZ3FU4BT_js.resolveSiteHost(analyticsConfig.site);
48
- chunkZLPXFV5Y_js.publishSiteCredential({ apiKey, apiUrl, site, debug, mapsBrowserKey });
48
+ chunk5KIO6FXE_js.publishSiteCredential({ apiKey, apiUrl, site, debug, mapsBrowserKey });
49
49
  const [visitorId] = React.useState(() => chunkRC4WWQXR_js.getOrCreateVisitorId());
50
50
  const [sessionId] = React.useState(() => chunkRC4WWQXR_js.getOrCreateSessionId());
51
51
  const pageMetadataRef = React.useRef(null);
@@ -57,7 +57,7 @@ function SiteKitClientProviders({
57
57
  const signalConfig = typeof signal === "object" ? signal : {};
58
58
  siblings.push(
59
59
  /* @__PURE__ */ jsxRuntime.jsx(
60
- chunkLBS4PRC7_js.SignalBridge,
60
+ chunkXK5AIWQG_js.SignalBridge,
61
61
  {
62
62
  enabled: true,
63
63
  realtime: signalConfig.realtime !== false,
@@ -86,6 +86,7 @@ function SiteKitClientProviders({
86
86
  sessionTimeout: analyticsConfig.sessionDuration,
87
87
  excludePaths: analyticsConfig.excludePaths,
88
88
  allowInFrame: analyticsConfig.allowInFrame === true,
89
+ allowLocalhost: analyticsConfig.allowLocalhost === true,
89
90
  debug,
90
91
  externalVisitorId: visitorId,
91
92
  externalSessionId: sessionId,
@@ -103,7 +104,10 @@ function SiteKitClientProviders({
103
104
  apiUrl,
104
105
  apiKey,
105
106
  projectId,
107
+ allowInFrame: analyticsConfig.allowInFrame === true,
108
+ allowLocalhost: analyticsConfig.allowLocalhost === true,
106
109
  position: engageConfig.position || "bottom-right",
110
+ offsetBottom: engageConfig.offsetBottom,
107
111
  zIndex: engageConfig.zIndex,
108
112
  chatEnabled: engageConfig.chatEnabled !== false
109
113
  }
@@ -112,7 +116,14 @@ function SiteKitClientProviders({
112
116
  }
113
117
  if (sitemapSync) {
114
118
  siblings.push(
115
- /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: modulesReady && /* @__PURE__ */ jsxRuntime.jsx(LazySitemapSync, { debug }) }, "sk-sitemap")
119
+ /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: modulesReady && /* @__PURE__ */ jsxRuntime.jsx(
120
+ LazySitemapSync,
121
+ {
122
+ debug,
123
+ allowInFrame: analyticsConfig.allowInFrame === true,
124
+ allowLocalhost: analyticsConfig.allowLocalhost === true
125
+ }
126
+ ) }, "sk-sitemap")
116
127
  );
117
128
  }
118
129
  if (fleet) {
@@ -123,12 +134,14 @@ function SiteKitClientProviders({
123
134
  if (sitemapSync) activeModules.push("sitemapSync");
124
135
  siblings.push(
125
136
  /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: modulesReady && /* @__PURE__ */ jsxRuntime.jsx(
126
- chunkOXZYP32B_js.FleetHeartbeat,
137
+ chunkSYGGZZMU_js.FleetHeartbeat,
127
138
  {
128
139
  apiUrl,
129
140
  apiKey,
130
141
  site,
131
142
  modules: activeModules,
143
+ allowInFrame: analyticsConfig.allowInFrame === true,
144
+ allowLocalhost: analyticsConfig.allowLocalhost === true,
132
145
  defer: false,
133
146
  debug
134
147
  }
@@ -142,5 +155,5 @@ function SiteKitClientProviders({
142
155
  }
143
156
 
144
157
  exports.SiteKitClientProviders = SiteKitClientProviders;
145
- //# sourceMappingURL=chunk-AWFZIXCT.js.map
146
- //# sourceMappingURL=chunk-AWFZIXCT.js.map
158
+ //# sourceMappingURL=chunk-N2PGTPWN.js.map
159
+ //# sourceMappingURL=chunk-N2PGTPWN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/layout/SiteKitClientProviders.tsx"],"names":["dynamic","useDeferredActivation","resolveSiteHost","publishSiteCredential","useState","getOrCreateVisitorId","getOrCreateSessionId","useRef","useCallback","jsx","SignalBridge","React","Suspense","FleetHeartbeat","jsxs","Fragment"],"mappings":"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","file":"chunk-N2PGTPWN.js","sourcesContent":["'use client'\n\n/**\n * SiteKitClientProviders — Client Island\n *\n * This is the 'use client' boundary for SiteKitLayout.\n * It composes the client-only providers (Analytics, Engage, Signal, SitemapSync)\n * that require React context or browser APIs.\n *\n * All modules are lazy-loaded via next/dynamic so their JS is only downloaded\n * when the feature is enabled — keeping the initial bundle lightweight.\n *\n * All modules share a unified identity (visitor ID + session ID) read from\n * the storage-backed singleton (shared/identity), ensuring consistent\n * tracking across Analytics, Signal, and Engage.\n *\n * 4.0 INVARIANT — CHILDREN ARE NEVER WRAPPED. Every module here renders as a\n * childless sibling AFTER {children}; nothing provides context around page\n * content. That makes the prerender-bailout / remount-flash class of bug\n * structurally impossible. Do not reintroduce a wrapper.\n *\n * Props are passed down from the server-side SiteKitLayout component,\n * which reads env vars at render time.\n */\n\nimport React, { Suspense, useCallback, useRef, useState, type ReactNode } from 'react'\nimport dynamic from 'next/dynamic'\nimport {\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\n// Defer non-critical module mounting until the page is quiet: the lazy\n// modules below are dynamic(ssr:false) and never render on the server, but\n// rendering them during hydration still kicks off their chunk downloads +\n// mount effects inside the critical startup window. useDeferredActivation\n// holds them until window.load + idle or first interaction — the same\n// strategy as the hand-rolled per-site deferrals this replaces (upforge\n// `deferred-analytics.tsx`, TPS `DeferredAnalytics.tsx`). The hook is public\n// (`@sonordev/site-kit/client`) so sites can reuse it for their own scripts.\nimport { useDeferredActivation } from '../shared/defer'\n// Single source of truth for seeding the token manager + the __SITE_KIT_*\n// globals — shared with the public `SiteKitCredential` component that\n// non-core layouts (agency-site-kit) use. Do not re-inline it here.\nimport { publishSiteCredential, resolveSiteHost } from '../shared/publishCredential'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\n// Lazy-load feature modules — JS only downloaded when feature is enabled\nconst LazyAnalyticsProvider = dynamic(\n () => import('../analytics/AnalyticsProvider').then(m => ({ default: m.AnalyticsProvider })),\n { ssr: false },\n)\nconst LazyEngageWidget = dynamic(\n () => import('../engage/EngageWidget').then(m => ({ default: m.EngageWidget })),\n { ssr: false },\n)\nconst LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n// SignalBridge is imported STATICALLY, not via dynamic(ssr:false): it is a\n// tiny SSR-safe context shell that renders children immediately and\n// lazy-loads its machinery (SignalCore) as a childless sibling internally.\n// Wrapping children in a dynamic(ssr:false) component was the old SSR-bailout\n// failure mode — do not reintroduce it.\nimport { SignalBridge } from '../signal/SignalBridge'\n// Fleet heartbeat: a deferred, CHILDLESS SIBLING (like Analytics/Engage) that\n// reports this site's kit version + active modules once per session, so the\n// platform can see version drift across the fleet. Tiny and SSR-safe — renders\n// null until the shared idle gate fires; never wraps page content.\nimport { FleetHeartbeat } from '../fleet/FleetHeartbeat'\nimport type { FleetModule } from '../fleet/contract'\n\nexport interface SiteKitClientProvidersProps {\n children: ReactNode\n apiKey: string\n apiUrl: string\n projectId?: string\n analytics?: boolean | AnalyticsConfig\n engage?: boolean | EngageConfig\n signal?: boolean | SignalConfig\n /**\n * Runtime SitemapSync from the visitor's browser. Default FALSE — sitemap\n * registration belongs to build time and to sonor-api's nightly reconciler,\n * not to whoever happens to load the page. See SiteKitLayout for the full\n * reasoning; in short, its guards live in session/localStorage, so every new\n * visitor missed them and re-POSTed the whole sitemap.\n */\n sitemapSync?: boolean\n /**\n * Fleet heartbeat — reports kit version + active modules to Sonor once per\n * session so the platform can track version drift and key state across every\n * site. Default true. Deferred exactly like Analytics; never in the hydration\n * path, carries no visitor data.\n */\n fleet?: boolean\n /**\n * Defer Analytics / Engage / SitemapSync until window load + idle or first\n * interaction (default true). Pass false to restore legacy eager mounting\n * on hydration. SignalBridge is never deferred — it must apply experiment\n * variants as early as possible.\n */\n defer?: boolean\n debug?: boolean\n /** Browser-safe Google Maps key, resolved server-side by SiteKitLayout. */\n mapsBrowserKey?: string\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = false,\n fleet = true,\n defer = true,\n debug = false,\n mapsBrowserKey,\n}: SiteKitClientProvidersProps) {\n // One shared activation gate for all deferred siblings, so they mount in a\n // single commit instead of staggered re-renders.\n const modulesReady = useDeferredActivation(defer)\n // Hoist analytics config so the `site` dimension is resolvable up here.\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n\n // Resolve the sub-site identifier — the dimension that lets one Sonor project\n // host many sites (e.g. truepowersystems.com + ohiopowerstudies.com under one\n // TPS project). Precedence lives in resolveSiteHost (shared contract):\n // explicit `analytics.site` > NEXT_PUBLIC_SITE_URL host > window.location.host.\n // Needed as a local too — SignalBridge and the analytics config read it below.\n const site = resolveSiteHost(analyticsConfig.site)\n\n // Seed the token manager + publish the window globals modules read from.\n // No-op on the server; runs during render so it lands before child effects.\n publishSiteCredential({ apiKey, apiUrl, site, debug, mapsBrowserKey })\n\n // Unified identity — single source of truth for all modules\n const [visitorId] = useState(() => getOrCreateVisitorId())\n const [sessionId] = useState(() => getOrCreateSessionId())\n\n // Page metadata bridge: Analytics writes, Signal reads\n const pageMetadataRef = useRef<Record<string, unknown> | null>(null)\n const onPageMetadata = useCallback((metadata: Record<string, unknown>) => {\n pageMetadataRef.current = metadata\n }, [])\n\n // Children render FIRST and are never re-parented. Siblings accumulate after.\n const siblings: ReactNode[] = []\n\n // SignalBridge — childless sibling (4.0: useSignal reads the module store,\n // so it no longer needs to wrap anything). Not gated on modulesReady:\n // experiment variants must apply as early as possible.\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n siblings.push(\n <SignalBridge\n key=\"sk-signal\"\n enabled\n realtime={signalConfig.realtime !== false}\n experiments={signalConfig.experiments !== false}\n behaviorTracking={signalConfig.behaviorTracking !== false}\n visitorId={visitorId}\n sessionId={sessionId}\n pageMetadataRef={pageMetadataRef}\n />,\n )\n }\n\n // Add Analytics if enabled (renders alongside, doesn't wrap).\n //\n // CRITICAL: LazyAnalyticsProvider is dynamic(..., { ssr: false }). Wrapping\n // {content} inside an ssr:false component makes the entire page tree skip\n // server rendering — the route de-opts to 100% client rendering and the\n // hero / LCP element only paints after hydration (mobile LCP ~4s, Lighthouse\n // ~85). Analytics tracks via effects + a metadata ref, so it never needs to\n // wrap page content — mount it as a childless sibling, exactly like Engage.\n // Each deferred sibling is appended as `{modulesReady && <Module/>}` so the\n // children slot never moves in the tree — flipping ready only mounts the\n // sibling, it never remounts page content.\n if (analytics) {\n siblings.push(\n <React.Fragment key=\"sk-analytics\">\n {modulesReady && (\n <Suspense fallback={null}>\n <LazyAnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n sessionTimeout={analyticsConfig.sessionDuration}\n excludePaths={analyticsConfig.excludePaths}\n // Off by default: a cross-origin embed of this site reports\n // nothing (see analytics/send-gate.ts). Opt in per site.\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n />\n </Suspense>\n )}\n </React.Fragment>,\n )\n }\n\n // Engage widget — childless sibling\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n siblings.push(\n <React.Fragment key=\"sk-engage\">\n {modulesReady && (\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n position={engageConfig.position || 'bottom-right'}\n offsetBottom={engageConfig.offsetBottom}\n zIndex={engageConfig.zIndex}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n )}\n </React.Fragment>,\n )\n }\n\n // SitemapSync — childless sibling\n if (sitemapSync) {\n siblings.push(\n <React.Fragment key=\"sk-sitemap\">\n {modulesReady && (\n <LazySitemapSync\n debug={debug}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n />\n )}\n </React.Fragment>,\n )\n }\n\n // Fleet heartbeat — childless sibling on the same modulesReady idle gate.\n // Reports the modules actually enabled on THIS layout (honest client-observable\n // set) so the platform can answer \"which version / modules is each site\n // running\". defer={false}: the modulesReady gate already handled deferral, so\n // the heartbeat fires on mount (still bounded to once per session internally).\n if (fleet) {\n const activeModules: FleetModule[] = []\n if (analytics) activeModules.push('analytics')\n if (engage) activeModules.push('engage')\n if (signal) activeModules.push('signal')\n if (sitemapSync) activeModules.push('sitemapSync')\n siblings.push(\n <React.Fragment key=\"sk-fleet\">\n {modulesReady && (\n <FleetHeartbeat\n apiUrl={apiUrl}\n apiKey={apiKey}\n site={site}\n modules={activeModules}\n allowInFrame={analyticsConfig.allowInFrame === true}\n allowLocalhost={analyticsConfig.allowLocalhost === true}\n defer={false}\n debug={debug}\n />\n )}\n </React.Fragment>,\n )\n }\n\n return (\n <>\n {children}\n {siblings}\n </>\n )\n}\n"]}
@@ -0,0 +1,39 @@
1
+ 'use client';
2
+ import { useEffect } from 'react';
3
+
4
+ // src/shared/visual-viewport-gap.ts
5
+ var VISUAL_VIEWPORT_GAP_PROPERTY = "--sk-vv-layout-gap";
6
+ function measureVisualViewportGap(win) {
7
+ const vv = win.visualViewport;
8
+ if (!vv) return 0;
9
+ return Math.max(0, Math.round(win.innerHeight - vv.offsetTop - vv.height));
10
+ }
11
+ function useVisualViewportGap() {
12
+ useEffect(() => {
13
+ const root = document.documentElement;
14
+ const vv = window.visualViewport;
15
+ const sync = () => {
16
+ const next = `${measureVisualViewportGap(window)}px`;
17
+ if (root.style.getPropertyValue(VISUAL_VIEWPORT_GAP_PROPERTY) === next) return;
18
+ root.style.setProperty(VISUAL_VIEWPORT_GAP_PROPERTY, next);
19
+ };
20
+ sync();
21
+ vv?.addEventListener("resize", sync);
22
+ vv?.addEventListener("scroll", sync);
23
+ window.addEventListener("resize", sync);
24
+ return () => {
25
+ vv?.removeEventListener("resize", sync);
26
+ vv?.removeEventListener("scroll", sync);
27
+ window.removeEventListener("resize", sync);
28
+ root.style.removeProperty(VISUAL_VIEWPORT_GAP_PROPERTY);
29
+ };
30
+ }, []);
31
+ }
32
+ function VisualViewportGap() {
33
+ useVisualViewportGap();
34
+ return null;
35
+ }
36
+
37
+ export { VISUAL_VIEWPORT_GAP_PROPERTY, VisualViewportGap, useVisualViewportGap };
38
+ //# sourceMappingURL=chunk-NSWO43XW.mjs.map
39
+ //# sourceMappingURL=chunk-NSWO43XW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/visual-viewport-gap.ts"],"names":[],"mappings":";;;AA+BO,IAAM,4BAAA,GAA+B;AAOrC,SAAS,yBACd,GAAA,EACQ;AACR,EAAA,MAAM,KAAK,GAAA,CAAI,cAAA;AACf,EAAA,IAAI,CAAC,IAAI,OAAO,CAAA;AAChB,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,WAAA,GAAc,EAAA,CAAG,SAAA,GAAY,EAAA,CAAG,MAAM,CAAC,CAAA;AAC3E;AAMO,SAAS,oBAAA,GAA6B;AAC3C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,OAAO,QAAA,CAAS,eAAA;AACtB,IAAA,MAAM,KAAK,MAAA,CAAO,cAAA;AAElB,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,MAAM,IAAA,GAAO,CAAA,EAAG,wBAAA,CAAyB,MAAM,CAAC,CAAA,EAAA,CAAA;AAMhD,MAAA,IAAI,IAAA,CAAK,KAAA,CAAM,gBAAA,CAAiB,4BAA4B,MAAM,IAAA,EAAM;AACxE,MAAA,IAAA,CAAK,KAAA,CAAM,WAAA,CAAY,4BAAA,EAA8B,IAAI,CAAA;AAAA,IAC3D,CAAA;AAEA,IAAA,IAAA,EAAK;AACL,IAAA,EAAA,EAAI,gBAAA,CAAiB,UAAU,IAAI,CAAA;AACnC,IAAA,EAAA,EAAI,gBAAA,CAAiB,UAAU,IAAI,CAAA;AACnC,IAAA,MAAA,CAAO,gBAAA,CAAiB,UAAU,IAAI,CAAA;AAEtC,IAAA,OAAO,MAAM;AACX,MAAA,EAAA,EAAI,mBAAA,CAAoB,UAAU,IAAI,CAAA;AACtC,MAAA,EAAA,EAAI,mBAAA,CAAoB,UAAU,IAAI,CAAA;AACtC,MAAA,MAAA,CAAO,mBAAA,CAAoB,UAAU,IAAI,CAAA;AACzC,MAAA,IAAA,CAAK,KAAA,CAAM,eAAe,4BAA4B,CAAA;AAAA,IACxD,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AACP;AAcO,SAAS,iBAAA,GAA0B;AACxC,EAAA,oBAAA,EAAqB;AACrB,EAAA,OAAO,IAAA;AACT","file":"chunk-NSWO43XW.mjs","sourcesContent":["/**\n * @sonordev/site-kit — visual viewport gap\n *\n * Single source of truth for measuring how far the layout viewport extends\n * below the visual viewport and publishing it as `--sk-vv-layout-gap` on\n * <html>. Moved into the kit from queencityriverboats.com and\n * destinyyachtcharters.com, which each carried a byte-identical copy.\n *\n * On a phone the two viewports can disagree (browser chrome, in-app browsers,\n * pinch zoom, an on-screen keyboard), and `position: fixed; bottom: …` is\n * measured against the LAYOUT viewport. The difference is how far a fixed\n * bottom element sits below what the visitor can actually see. Adding the\n * property to a `bottom` calc puts it back on screen:\n *\n * bottom: calc(24px + env(safe-area-inset-bottom, 0px) + var(--sk-vv-layout-gap, 0px));\n *\n * The Echo launcher and chat popup already include it (see\n * engage/launcher-placement.ts), so mounting the tracker is all a site needs\n * for those; the property is also there for the site's own fixed UI.\n *\n * Opt-in on purpose. The gap also grows to the keyboard's height while a\n * field has focus, which lifts every element that reads it above the\n * keyboard. That is what the two sites above want; it is not a default to\n * impose on the fleet.\n */\n\n'use client'\n\nimport { useEffect } from 'react'\n\n/** The custom property the gap is published on, in px. Unset when no tracker is mounted. */\nexport const VISUAL_VIEWPORT_GAP_PROPERTY = '--sk-vv-layout-gap'\n\n/**\n * Whole pixels between the bottom of the visual viewport and the bottom of\n * the layout viewport. 0 when the browser has no VisualViewport API, and\n * never negative.\n */\nexport function measureVisualViewportGap(\n win: Pick<Window, 'innerHeight' | 'visualViewport'>,\n): number {\n const vv = win.visualViewport\n if (!vv) return 0\n return Math.max(0, Math.round(win.innerHeight - vv.offsetTop - vv.height))\n}\n\n/**\n * Keep `--sk-vv-layout-gap` on <html> current for as long as the calling\n * component is mounted, and remove it on unmount.\n */\nexport function useVisualViewportGap(): void {\n useEffect(() => {\n const root = document.documentElement\n const vv = window.visualViewport\n\n const sync = () => {\n const next = `${measureVisualViewportGap(window)}px`\n // A custom property on <html> invalidates style for the whole document,\n // and visualViewport fires resize/scroll continuously during a pinch or\n // a toolbar animation. Only write when the value actually moved.\n // Compared against the live inline value rather than a cached copy, so\n // anything else that wrote or removed it is corrected on the next event.\n if (root.style.getPropertyValue(VISUAL_VIEWPORT_GAP_PROPERTY) === next) return\n root.style.setProperty(VISUAL_VIEWPORT_GAP_PROPERTY, next)\n }\n\n sync()\n vv?.addEventListener('resize', sync)\n vv?.addEventListener('scroll', sync)\n window.addEventListener('resize', sync)\n\n return () => {\n vv?.removeEventListener('resize', sync)\n vv?.removeEventListener('scroll', sync)\n window.removeEventListener('resize', sync)\n root.style.removeProperty(VISUAL_VIEWPORT_GAP_PROPERTY)\n }\n }, [])\n}\n\n/**\n * Childless component form of `useVisualViewportGap`, for a server layout:\n *\n * ```tsx\n * import { VisualViewportGap } from '@sonordev/site-kit/client'\n *\n * <SiteKitLayout>\n * <VisualViewportGap />\n * {children}\n * </SiteKitLayout>\n * ```\n */\nexport function VisualViewportGap(): null {\n useVisualViewportGap()\n return null\n}\n"]}
@@ -255,20 +255,24 @@ async function generateLLMsTxt(options) {
255
255
  sections.push(faq);
256
256
  sectionNames.push("faq");
257
257
  }
258
- if (includePages && data.pages?.length > 0) {
258
+ const renderOptional = optionalPagePaths.length > 0 && Boolean(baseUrl);
259
+ const optionalKeys = renderOptional ? new Set(optionalPagePaths.map(normalizeLlmsPagePath)) : null;
260
+ const indexPages = optionalKeys ? (data.pages ?? []).filter((p) => !optionalKeys.has(normalizeLlmsPagePath(p.path))) : data.pages ?? [];
261
+ if (includePages && indexPages.length > 0) {
259
262
  const pages = generatePagesSection(
260
- data.pages.slice(0, maxPages),
263
+ indexPages.slice(0, maxPages),
261
264
  baseUrl,
262
265
  pageListNotesFromPublicSummaryOnly
263
266
  );
264
267
  sections.push(pages);
265
268
  sectionNames.push("pages");
266
269
  }
267
- if (optionalPagePaths.length > 0 && baseUrl) {
270
+ if (renderOptional) {
268
271
  const opt = generateOptionalPagesSection(
269
272
  optionalPagePaths,
270
273
  data.pages || [],
271
- baseUrl
274
+ baseUrl,
275
+ pageListNotesFromPublicSummaryOnly
272
276
  );
273
277
  if (opt) {
274
278
  sections.push(opt);
@@ -290,7 +294,7 @@ async function generateLLMsTxt(options) {
290
294
  if (includeEntities) {
291
295
  attemptedSections.push("knowledge-graph");
292
296
  optionalFetches.push(
293
- import('./server-api-DB2SIUP4.js').then(async ({ getEntities, getPrimaryEntity }) => {
297
+ import('./server-api-RYJQAUGO.js').then(async ({ getEntities, getPrimaryEntity }) => {
294
298
  const [entities, primaryEntity] = await Promise.all([
295
299
  getEntities().then((e) => e.slice(0, maxEntities)),
296
300
  getPrimaryEntity()
@@ -537,36 +541,46 @@ function pageListNote(page, publicSummaryOnly) {
537
541
  if (page.description) return page.description.replace(/[\[\]\r\n]/g, " ").trim();
538
542
  return void 0;
539
543
  }
544
+ function normalizeLlmsPagePath(path) {
545
+ const withLeading = path.startsWith("/") ? path : `/${path}`;
546
+ return withLeading.replace(/\/$/, "") || "/";
547
+ }
548
+ function formatPageLine(page, baseUrl, publicSummaryOnly) {
549
+ const url = page.path.startsWith("http") ? page.path : `${baseUrl}${page.path}`;
550
+ const note = pageListNote(page, publicSummaryOnly);
551
+ return note ? `- [${page.title}](${url}): ${note}` : `- [${page.title}](${url})`;
552
+ }
540
553
  function generatePagesSection(pages, baseUrl, publicSummaryOnly) {
541
554
  const lines = [];
542
555
  lines.push("## Site Pages");
543
556
  lines.push("");
544
557
  for (const page of pages) {
545
- const url = page.path.startsWith("http") ? page.path : `${baseUrl}${page.path}`;
546
- const note = pageListNote(page, publicSummaryOnly);
547
- if (note) {
548
- lines.push(`- [${page.title}](${url}): ${note}`);
549
- } else {
550
- lines.push(`- [${page.title}](${url})`);
551
- }
558
+ lines.push(formatPageLine(page, baseUrl, publicSummaryOnly));
552
559
  }
553
560
  return lines.join("\n");
554
561
  }
555
- function generateOptionalPagesSection(paths, pages, baseUrl) {
556
- const normalizedBase = baseUrl.replace(/\/$/, "");
557
- const byPath = new Map(pages.map((p) => [p.path.replace(/\/$/, "") || "/", p]));
562
+ function generateOptionalPagesSection(paths, pages, baseUrl, publicSummaryOnly) {
563
+ const byPath = /* @__PURE__ */ new Map();
564
+ for (const page of pages) {
565
+ const key = normalizeLlmsPagePath(page.path);
566
+ if (!byPath.has(key)) byPath.set(key, page);
567
+ }
558
568
  const lines = ["## Optional", ""];
559
- let any = false;
569
+ const seen = /* @__PURE__ */ new Set();
560
570
  for (const raw of paths) {
571
+ const key = normalizeLlmsPagePath(raw);
572
+ if (seen.has(key)) continue;
573
+ seen.add(key);
574
+ const match = byPath.get(key);
575
+ if (match) {
576
+ lines.push(formatPageLine(match, baseUrl, publicSummaryOnly));
577
+ continue;
578
+ }
561
579
  const p = raw.startsWith("/") ? raw : `/${raw}`;
562
- const norm = p.replace(/\/$/, "") || "/";
563
- const match = byPath.get(norm) || byPath.get(`${norm}/`);
564
- const title = match?.title || norm.split("/").filter(Boolean).pop() || norm;
565
- const url = `${normalizedBase}${p.endsWith("/") ? p : `${p}/`}`;
566
- lines.push(`- [${title}](${url})`);
567
- any = true;
568
- }
569
- return any ? lines.join("\n") : null;
580
+ const title = key.split("/").filter(Boolean).pop() || key;
581
+ lines.push(`- [${title}](${baseUrl}${p.endsWith("/") ? p : `${p}/`})`);
582
+ }
583
+ return seen.size > 0 ? lines.join("\n") : null;
570
584
  }
571
585
  function generateEntitySection(entities, primaryEntity, detailed) {
572
586
  const lines = [];
@@ -714,5 +728,5 @@ exports.getOptimizedLLMsTxt = getOptimizedLLMsTxt;
714
728
  exports.getPageSummaries = getPageSummaries;
715
729
  exports.getServices = getServices;
716
730
  exports.writeLLMsTxtToPublic = writeLLMsTxtToPublic;
717
- //# sourceMappingURL=chunk-KMGGAL2X.js.map
718
- //# sourceMappingURL=chunk-KMGGAL2X.js.map
731
+ //# sourceMappingURL=chunk-NZSFOZJV.js.map
732
+ //# sourceMappingURL=chunk-NZSFOZJV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/llms/api.ts","../src/llms/humanize-industry.ts","../src/llms/generateLLMsTxt.ts","../src/llms/writeLLMsTxt.ts"],"names":["resolveSiteHost","cache","LLM_GEO_CONTRACT_VERSION","sanitizePrimaryLanguageTag","sanitizeLlmsDisclaimerLine","sanitizeLlmsPublicSummary","join","existsSync","mkdirSync","writeFileSync","renameSync","unlinkSync"],"mappings":"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","file":"chunk-NZSFOZJV.js","sourcesContent":["/**\n * @sonordev/site-kit/llms - API Functions\n * \n * Data fetching for LLM visibility content.\n * Pulls from Signal knowledge base and project data.\n */\n\nimport { cache } from 'react'\nimport { LLM_GEO_CONTRACT_VERSION } from './contract'\nimport { resolveSiteHost } from '../sites/resolve'\nimport type { LLMsDataResponse, LLMBusinessInfo, LLMContactInfo, LLMService, LLMFAQItem, LLMPageSummary } from './types'\n\n// ============================================\n// API Config\n// ============================================\n\nfunction getApiConfig() {\n // Use site-kit globals if available, otherwise fall back to env vars\n const apiUrl = (typeof window !== 'undefined' && (window as any).__SITE_KIT_API_URL__)\n || process.env.SONOR_API_URL\n || 'https://api.sonor.io'\n\n const apiKey = (typeof window !== 'undefined' && (window as any).__SITE_KIT_API_KEY__)\n || process.env.SONOR_API_KEY\n || ''\n \n return { apiUrl, apiKey }\n}\n\n/**\n * Append the sub-site host to an endpoint. `site` scopes every seo_pages read\n * on the Sonor side to THIS host — see `withSite` callers below and the\n * multi-site notes on `getLLMsData`.\n *\n * Resolution (explicit → NEXT_PUBLIC_SITE_URL host → window.location.host) is\n * the shared one from `sites/resolve`, so the value matches what the browser\n * publishes as `__SITE_KIT_SITE__` and what SitemapSync tags rows with.\n */\nfunction withSite(endpoint: string, site?: string): string {\n const host = resolveSiteHost(site)\n if (!host) return endpoint\n return `${endpoint}${endpoint.includes('?') ? '&' : '?'}site=${encodeURIComponent(host)}`\n}\n\nasync function apiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getApiConfig()\n \n if (!apiKey) {\n console.error('@sonordev/llms: No API key configured. Set SONOR_API_KEY.')\n return null\n }\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 3600 }, // Next.js fetch cache\n } as RequestInit)\n \n if (!response.ok) {\n console.error(`@sonordev/llms: API error: ${response.statusText}`)\n return null\n }\n\n const json = await response.json()\n return json\n } catch (error) {\n console.error('@sonordev/llms: Network error:', error)\n return null\n }\n}\n\n// ============================================\n// Cached Data Fetchers\n// ============================================\n\n/**\n * Fetch all LLM visibility data for a project - cached per request\n * This is the main data source for llms.txt generation\n *\n * @param projectId - Optional project ID (API key identifies project if omitted)\n * @param site - Sub-site host. One Sonor project can host many domains, and\n * seo_pages then holds one row PER HOST for shared paths like `/` and\n * `/terms`. Without this the API returns an arbitrary sibling's row, so a\n * site describes its neighbours instead of itself. Omit to resolve from\n * NEXT_PUBLIC_SITE_URL (the build-time source of truth).\n */\nexport const getLLMsData = cache(async (\n projectId?: string,\n site?: string\n): Promise<LLMsDataResponse | null> => {\n const data = await apiGet<LLMsDataResponse>(withSite(`/api/public/llms/data`, site))\n if (\n data?.meta &&\n data.meta.contract_version != null &&\n data.meta.contract_version !== LLM_GEO_CONTRACT_VERSION &&\n typeof process !== 'undefined' &&\n process.env.NODE_ENV !== 'production'\n ) {\n console.warn(\n `[site-kit/llms] API meta.contract_version (${data.meta.contract_version}) !== site-kit LLM_GEO_CONTRACT_VERSION (${LLM_GEO_CONTRACT_VERSION}).`,\n )\n }\n return data\n})\n\n/**\n * Fetch business info only - cached per request\n */\nexport const getBusinessInfo = cache(async (\n projectId?: string\n): Promise<LLMBusinessInfo | null> => {\n const result = await apiGet<{ business: LLMBusinessInfo }>(`/api/public/llms/business`)\n return result?.business || null\n})\n\n/**\n * Fetch services list - cached per request\n */\nexport const getServices = cache(async (\n projectId?: string,\n site?: string\n): Promise<LLMService[]> => {\n const result = await apiGet<{ services: LLMService[] }>(withSite(`/api/public/llms/services`, site))\n return result?.services || []\n})\n\n/**\n * Fetch FAQ items - cached per request\n */\nexport const getFAQItems = cache(async (\n projectId?: string,\n limit?: number\n): Promise<LLMFAQItem[]> => {\n const endpoint = limit \n ? `/api/public/llms/faq?limit=${limit}`\n : '/api/public/llms/faq'\n const result = await apiGet<{ faq: LLMFAQItem[] }>(endpoint)\n return result?.faq || []\n})\n\n/**\n * Fetch page summaries for sitemap - cached per request\n */\nexport const getPageSummaries = cache(async (\n projectId?: string,\n limit?: number,\n site?: string\n): Promise<LLMPageSummary[]> => {\n const endpoint = limit \n ? `/api/public/llms/pages?limit=${limit}`\n : '/api/public/llms/pages'\n const result = await apiGet<{ pages: LLMPageSummary[] }>(withSite(endpoint, site))\n return result?.pages || []\n})\n\n/**\n * Fetch AI-optimized llms.txt markdown from Portal API (build-time)\n * Used by writeLLMsTxtToPublic for static file generation\n */\nexport async function getOptimizedLLMsTxt(options?: {\n full?: boolean\n /** Matches Portal GET /api/public/llms/txt?publicSummaryOnly=true */\n publicSummaryOnly?: boolean\n /**\n * Sub-site host — scopes the page index to THIS domain on multi-site\n * projects. Omit to resolve from NEXT_PUBLIC_SITE_URL. See getLLMsData.\n */\n site?: string\n apiUrl?: string\n apiKey?: string\n}): Promise<string | null> {\n const apiUrl = options?.apiUrl\n || (typeof process !== 'undefined' && process.env?.SONOR_API_URL)\n || 'https://api.sonor.io'\n const apiKey = options?.apiKey\n || (typeof process !== 'undefined' && process.env?.SONOR_API_KEY)\n || ''\n\n if (!apiKey) {\n console.error('@sonordev/llms: No API key configured for getOptimizedLLMsTxt')\n return null\n }\n\n const params = new URLSearchParams()\n if (options?.full) params.set('full', 'true')\n if (options?.publicSummaryOnly) params.set('publicSummaryOnly', 'true')\n const site = resolveSiteHost(options?.site)\n if (site) params.set('site', site)\n const qs = params.toString()\n const endpoint = `/api/public/llms/txt${qs ? `?${qs}` : ''}`\n\n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'text/plain',\n 'x-api-key': apiKey,\n },\n })\n\n if (!response.ok) {\n console.error(`@sonordev/llms: Optimized txt API error: ${response.status} ${response.statusText}`)\n return null\n }\n\n return await response.text()\n } catch (error) {\n console.error('@sonordev/llms: Failed to fetch optimized llms.txt:', error)\n return null\n }\n}\n","/**\n * Turn a stored industry slug into display prose.\n *\n * `business.industry` comes from a fixed enum column (professional_services,\n * home_services, …) and llms.txt is served to AI crawlers verbatim, so\n * printing the raw slug reads as a database leak rather than a description.\n */\nexport function humanizeIndustry(industry: string): string {\n const spaced = industry.replace(/[_-]+/g, ' ').trim()\n if (!spaced) return industry\n return spaced.charAt(0).toUpperCase() + spaced.slice(1)\n}\n","/**\n * @sonordev/site-kit/llms - llms.txt Generator\n * \n * Generates llms.txt content following the llms.txt specification.\n * https://llmstxt.org/\n * \n * The llms.txt file provides a markdown-formatted overview of a website\n * specifically designed for LLM consumption. It helps AI systems understand\n * what a business does, what services it offers, and how to answer questions.\n */\n\nimport { getLLMsData } from './api'\nimport type {\n GenerateLLMSTxtOptions,\n LLMSTxtContent,\n LLMsDataResponse,\n LLMBusinessInfo,\n LLMContactInfo,\n LLMService,\n LLMFAQItem,\n LLMPageSummary,\n LLMPortfolioItem,\n} from './types'\nimport type { SEOEntity } from '../seo/types'\nimport type { LLMsPayloadMeta } from './contract'\nimport {\n LLM_GEO_CONTRACT_VERSION,\n sanitizeLlmsDisclaimerLine,\n sanitizeLlmsPublicSummary,\n sanitizePrimaryLanguageTag,\n} from './contract'\nimport { humanizeIndustry } from './humanize-industry'\n\nfunction mergeLlmsMeta(\n fallback: LLMsPayloadMeta | null | undefined,\n primary: LLMsPayloadMeta | null | undefined,\n): LLMsPayloadMeta | undefined {\n if (!primary && !fallback) return undefined\n if (!primary) return fallback ?? undefined\n if (!fallback) return primary\n return {\n contract_version: primary.contract_version ?? fallback.contract_version,\n last_updated: primary.last_updated ?? fallback.last_updated ?? null,\n primary_language: primary.primary_language ?? fallback.primary_language ?? null,\n llms_disclaimer: primary.llms_disclaimer ?? fallback.llms_disclaimer ?? null,\n }\n}\n\n/**\n * Single source of truth for the llms.txt link base (site origin).\n * Precedence: explicit `baseUrl` option → Portal/local `business.website` →\n * NEXT_PUBLIC_SITE_URL → SITE_URL. Intentionally never derived from request\n * headers — touching the Request would force the /llms.txt route dynamic and\n * break static prerendering on consumer sites.\n */\nfunction resolveBaseUrl(\n optionBaseUrl: string | undefined,\n businessWebsite: string | undefined | null,\n): string {\n const candidate =\n optionBaseUrl ||\n businessWebsite ||\n process.env.NEXT_PUBLIC_SITE_URL ||\n process.env.SITE_URL ||\n ''\n return candidate.trim().replace(/\\/+$/, '')\n}\n\n/**\n * Merge Portal data with local data. Portal fields take precedence; local fills gaps when Portal is empty.\n */\nfunction mergeLLMsData(\n portal: Partial<LLMsDataResponse> | null,\n local: LLMsDataResponse | null\n): LLMsDataResponse | null {\n if (!local) return portal as LLMsDataResponse | null\n if (!portal) return local\n return {\n meta: mergeLlmsMeta(local.meta, portal.meta),\n business: portal.business ?? local.business,\n contact: portal.contact ?? local.contact,\n services: (portal.services?.length ? portal.services : local.services) ?? [],\n faq: (portal.faq?.length ? portal.faq : local.faq) ?? [],\n pages: (portal.pages?.length ? portal.pages : local.pages) ?? [],\n portfolio: (portal.portfolio?.length ? portal.portfolio : local.portfolio) ?? [],\n }\n}\n\n/**\n * Generate llms.txt content from Portal data\n * \n * @example\n * ```ts\n * // app/llms.txt/route.ts\n * import { generateLLMsTxt } from '@sonordev/site-kit/llms'\n * \n * export async function GET() {\n * const { markdown } = await generateLLMsTxt({\n * projectId: process.env.SONOR_API_KEY!\n * })\n * \n * return new Response(markdown, {\n * headers: { 'Content-Type': 'text/plain; charset=utf-8' }\n * })\n * }\n * ```\n */\nexport async function generateLLMsTxt(\n options: GenerateLLMSTxtOptions\n): Promise<LLMSTxtContent> {\n const {\n projectId,\n baseUrl: baseUrlOption,\n site,\n getLocalData,\n includeBusinessInfo = true,\n includeServices = true,\n includeFAQ = true,\n includePages = true,\n includeContact = true,\n includePortfolio = true,\n includeEntities = true,\n maxFAQItems = 20,\n maxPages = 50,\n maxPortfolioItems = 20,\n maxEntities = 50,\n maxArticlesPerCluster = 5,\n customSections = [],\n optionalPagePaths = [],\n linkToFullLlms = false,\n fullLlmsTxtPath = '/llms-full.txt',\n pageListNotesFromPublicSummaryOnly = false,\n headerPrimaryLanguage,\n headerDisclaimer,\n } = options\n\n // Fetch from Portal first, scoped to THIS sub-site so a multi-site project\n // describes the host being built rather than an arbitrary sibling.\n let data = await getLLMsData(projectId, site)\n\n // Use local data when Portal returns null or empty services\n const useLocal = getLocalData && (!data || !data.services?.length)\n if (useLocal && getLocalData) {\n try {\n const local = await getLocalData()\n data = mergeLLMsData(data ?? null, local)\n } catch (err) {\n console.warn('[site-kit] getLocalData failed:', err)\n }\n }\n \n if (!data) {\n // Return minimal content if no data\n return {\n markdown: '# Website\\n\\n> Information not available.',\n metadata: {\n generated_at: new Date().toISOString(),\n project_id: projectId || '',\n sections: [],\n }\n }\n }\n\n const headerMeta = buildHeaderMeta(\n data.meta,\n headerPrimaryLanguage,\n headerDisclaimer,\n )\n\n const baseUrl = resolveBaseUrl(baseUrlOption, data.business?.website)\n\n const sections: string[] = []\n const sectionNames: string[] = []\n const attemptedSections: string[] = []\n const failedSections: string[] = []\n\n // ========================================\n // Header Section (H1 + blockquote summary)\n // ========================================\n if (includeBusinessInfo && data.business) {\n const header = generateHeaderSection(data.business, headerMeta, baseUrl)\n sections.push(header)\n sectionNames.push('header')\n }\n\n // ========================================\n // About Section\n // ========================================\n if (includeBusinessInfo && data.business?.description) {\n const about = generateAboutSection(data.business)\n sections.push(about)\n sectionNames.push('about')\n }\n\n // ========================================\n // Services Section\n // ========================================\n if (includeServices && data.services?.length > 0) {\n const services = generateServicesSection(data.services)\n sections.push(services)\n sectionNames.push('services')\n }\n\n // ========================================\n // Portfolio / Case Studies Section\n // ========================================\n if (includePortfolio) {\n let portfolioItems = data.portfolio || []\n\n // If LLMs data didn't include portfolio, fetch directly from the portfolio endpoint\n if (portfolioItems.length === 0) {\n attemptedSections.push('portfolio')\n try {\n const apiUrl = process.env.SONOR_API_URL || 'https://api.sonor.io'\n const apiKey = process.env.SONOR_API_KEY || ''\n if (apiKey) {\n const response = await fetch(`${apiUrl}/api/public/portfolio/items`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n })\n if (response.ok) {\n const result = await response.json()\n const items = result?.portfolioItems || result?.items || result || []\n portfolioItems = items.filter((item: any) => item.status === 'published')\n }\n }\n } catch (err) {\n console.warn('[site-kit/llms] Portfolio section failed:', err)\n failedSections.push('portfolio')\n }\n }\n\n if (portfolioItems.length > 0) {\n const portfolio = generatePortfolioSection(\n portfolioItems.slice(0, maxPortfolioItems),\n baseUrl\n )\n sections.push(portfolio)\n sectionNames.push('portfolio')\n }\n }\n\n // ========================================\n // Contact Section\n // ========================================\n if (includeContact && data.contact) {\n const contact = generateContactSection(data.contact)\n sections.push(contact)\n sectionNames.push('contact')\n }\n\n // ========================================\n // FAQ Section\n // ========================================\n if (includeFAQ && data.faq?.length > 0) {\n const faq = generateFAQSection(data.faq.slice(0, maxFAQItems))\n sections.push(faq)\n sectionNames.push('faq')\n }\n\n // ========================================\n // Pages Section (sitemap-like index)\n // ========================================\n // `## Optional` needs a base URL to render. Only when it will render are the\n // demoted pages pulled out of `## Site Pages`; otherwise they'd vanish from\n // the file instead of moving.\n const renderOptional = optionalPagePaths.length > 0 && Boolean(baseUrl)\n const optionalKeys = renderOptional\n ? new Set(optionalPagePaths.map(normalizeLlmsPagePath))\n : null\n // Filter BEFORE applying maxPages: moving a page to Optional frees a slot in\n // the index for the next page instead of using one up.\n const indexPages = optionalKeys\n ? (data.pages ?? []).filter(p => !optionalKeys.has(normalizeLlmsPagePath(p.path)))\n : (data.pages ?? [])\n\n if (includePages && indexPages.length > 0) {\n const pages = generatePagesSection(\n indexPages.slice(0, maxPages),\n baseUrl,\n pageListNotesFromPublicSummaryOnly,\n )\n sections.push(pages)\n sectionNames.push('pages')\n }\n\n if (renderOptional) {\n const opt = generateOptionalPagesSection(\n optionalPagePaths,\n data.pages || [],\n baseUrl,\n pageListNotesFromPublicSummaryOnly,\n )\n if (opt) {\n sections.push(opt)\n sectionNames.push('optional')\n }\n }\n\n if (linkToFullLlms && baseUrl) {\n const fullPath = fullLlmsTxtPath.startsWith('/') ? fullLlmsTxtPath : `/${fullLlmsTxtPath}`\n const fullUrl = fullPath.startsWith('http') ? fullPath : `${baseUrl}${fullPath}`\n sections.push(\n `## Full context\\n\\n- [llms-full.txt](${fullUrl}): Expanded page index and FAQ for large-context systems.`,\n )\n sectionNames.push('full-context')\n }\n\n // ========================================\n // Knowledge Graph + Topic Clusters (parallel)\n // ========================================\n {\n type OptionalResult =\n | { kind: 'entities'; entities: SEOEntity[]; primaryEntity: SEOEntity | null }\n | { kind: 'clusters'; clusters: any[] }\n\n const optionalFetches: Promise<OptionalResult | null>[] = []\n\n if (includeEntities) {\n attemptedSections.push('knowledge-graph')\n optionalFetches.push(\n import('../seo/server-api')\n .then(async ({ getEntities, getPrimaryEntity }) => {\n const [entities, primaryEntity] = await Promise.all([\n getEntities().then(e => e.slice(0, maxEntities)),\n getPrimaryEntity(),\n ])\n return { kind: 'entities' as const, entities, primaryEntity }\n })\n .catch((err) => {\n console.warn('[site-kit/llms] Knowledge graph section failed:', err)\n failedSections.push('knowledge-graph')\n return null\n }),\n )\n }\n\n attemptedSections.push('topic-clusters')\n optionalFetches.push(\n import('../blog/server-core')\n .then(async ({ getTopicClusters }) => {\n const clusters = await getTopicClusters()\n return { kind: 'clusters' as const, clusters }\n })\n .catch((err) => {\n console.warn('[site-kit/llms] Topic clusters section failed:', err)\n failedSections.push('topic-clusters')\n return null\n }),\n )\n\n const settled = await Promise.all(optionalFetches)\n\n for (const result of settled) {\n if (!result) continue\n\n if (result.kind === 'entities') {\n if (result.entities.length > 0 || result.primaryEntity) {\n const entitySection = generateEntitySection(result.entities, result.primaryEntity, false)\n sections.push(entitySection)\n sectionNames.push('knowledge-graph')\n }\n }\n\n if (result.kind === 'clusters' && result.clusters.length > 0) {\n const clusterLines: string[] = ['## Topic Clusters', '']\n clusterLines.push('Organized content collections providing comprehensive coverage of key topics.', '')\n for (const cluster of result.clusters) {\n clusterLines.push(`### ${cluster.cluster_name}`)\n clusterLines.push(`Topic: ${cluster.core_topic}`)\n if (cluster.geo_target) clusterLines.push(`Area: ${cluster.geo_target}`)\n clusterLines.push(`Articles: ${cluster.article_count}`)\n if (cluster.target_service_page) {\n clusterLines.push(`Service page: ${baseUrl}${cluster.target_service_page}`)\n }\n\n // Enriched: list pillar page and recent articles\n if (cluster.pillar) {\n const pillarUrl = cluster.pillar.slug ? `${baseUrl}/blog/${cluster.pillar.slug}` : ''\n clusterLines.push(`Pillar: [${cluster.pillar.title || cluster.cluster_name}](${pillarUrl})`)\n }\n const supports = (cluster.supports || []) as any[]\n if (supports.length > 0) {\n const sorted = [...supports]\n .sort((a, b) => (b.published_at || '').localeCompare(a.published_at || ''))\n .slice(0, maxArticlesPerCluster)\n for (const article of sorted) {\n const articleUrl = article.slug ? `${baseUrl}/blog/${article.slug}` : ''\n const dateStr = article.published_at\n ? ` (${new Date(article.published_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })})`\n : ''\n clusterLines.push(`- [${article.title}](${articleUrl})${dateStr}`)\n }\n }\n\n clusterLines.push('')\n }\n sections.push(clusterLines.join('\\n'))\n sectionNames.push('topic-clusters')\n }\n }\n }\n\n // ========================================\n // Custom Sections\n // ========================================\n for (const custom of customSections) {\n sections.push(`## ${custom.title}\\n\\n${custom.content}`)\n sectionNames.push(custom.title.toLowerCase().replace(/\\s+/g, '-'))\n }\n\n return {\n markdown: sections.join('\\n\\n---\\n\\n'),\n metadata: {\n generated_at: new Date().toISOString(),\n project_id: projectId || '',\n sections: sectionNames,\n attempted_sections: attemptedSections.length ? attemptedSections : undefined,\n failed_sections: failedSections.length ? failedSections : undefined,\n }\n }\n}\n\n/**\n * Generate llms-full.txt with comprehensive knowledge dump\n * Use this for AI systems that can handle larger context\n */\nexport async function generateLLMsFullTxt(\n options: GenerateLLMSTxtOptions\n): Promise<LLMSTxtContent> {\n return generateLLMsTxt({\n ...options,\n includeBusinessInfo: true,\n includeServices: true,\n includeFAQ: true,\n includePages: true,\n includeContact: true,\n includePortfolio: true,\n includeEntities: true,\n maxFAQItems: 100,\n maxPages: 200,\n maxPortfolioItems: 50,\n maxEntities: 200,\n })\n}\n\n// ============================================\n// Section Generators\n// ============================================\n\nfunction buildHeaderMeta(\n base: LLMsPayloadMeta | null | undefined,\n primaryLanguageOverride?: string,\n disclaimerOverride?: string,\n): LLMsPayloadMeta | undefined {\n if (primaryLanguageOverride === undefined && disclaimerOverride === undefined) {\n return base ?? undefined\n }\n const merged: LLMsPayloadMeta = {\n contract_version: base?.contract_version ?? LLM_GEO_CONTRACT_VERSION,\n last_updated: base?.last_updated ?? null,\n primary_language: base?.primary_language ?? null,\n llms_disclaimer: base?.llms_disclaimer ?? null,\n }\n if (primaryLanguageOverride !== undefined) {\n const pl = sanitizePrimaryLanguageTag(primaryLanguageOverride)\n merged.primary_language = pl ?? merged.primary_language\n }\n if (disclaimerOverride !== undefined) {\n const d = sanitizeLlmsDisclaimerLine(disclaimerOverride)\n merged.llms_disclaimer = d ?? merged.llms_disclaimer\n }\n return merged\n}\n\nfunction generateHeaderSection(\n business: LLMBusinessInfo,\n meta?: LLMsPayloadMeta | null,\n resolvedBaseUrl?: string,\n): string {\n const lines: string[] = []\n \n // H1 with business name\n lines.push(`# ${business.name}`)\n lines.push('')\n \n // Blockquote summary (per llms.txt spec)\n const summary =\n business.tagline || business.description?.split('.')[0] || business.name\n lines.push(`> ${summary}`)\n if (meta?.last_updated) {\n lines.push(`> Content index last updated: ${meta.last_updated}`)\n }\n if (meta?.primary_language) {\n lines.push(`> Primary language: ${meta.primary_language}`)\n }\n if (meta?.llms_disclaimer) {\n lines.push(`> ${meta.llms_disclaimer}`)\n }\n \n if (business.industry) {\n lines.push('')\n lines.push(`**Industry:** ${humanizeIndustry(business.industry)}`)\n }\n \n if (business.service_area) {\n lines.push(`**Service Area:** ${business.service_area}`)\n }\n \n const website = business.website || resolvedBaseUrl\n if (website) {\n lines.push(`**Website:** ${website}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateAboutSection(business: LLMBusinessInfo): string {\n const lines: string[] = []\n \n lines.push('## About')\n lines.push('')\n lines.push(business.description)\n \n if (business.founded) {\n lines.push('')\n lines.push(`Established: ${business.founded}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateServicesSection(services: LLMService[]): string {\n const lines: string[] = []\n \n lines.push('## Services')\n lines.push('')\n \n for (const service of services) {\n if (service.url) {\n lines.push(`- **[${service.name}](${service.url})**: ${service.description}`)\n } else {\n lines.push(`- **${service.name}**: ${service.description}`)\n }\n }\n\n return lines.join('\\n')\n}\n\nfunction generatePortfolioSection(items: LLMPortfolioItem[], baseUrl: string): string {\n const lines: string[] = []\n\n lines.push('## Portfolio & Case Studies')\n lines.push('')\n\n for (const item of items) {\n const url = item.live_url || (item.slug ? `${baseUrl}/portfolio/${item.slug}` : '')\n\n if (url) {\n lines.push(`### [${item.title}](${url})`)\n } else {\n lines.push(`### ${item.title}`)\n }\n lines.push('')\n\n if (item.description) {\n lines.push(item.description)\n lines.push('')\n }\n\n const meta: string[] = []\n if (item.category) {\n meta.push(`**Category:** ${item.category}`)\n }\n if (item.services?.length) {\n meta.push(`**Services:** ${item.services.join(', ')}`)\n }\n if (item.live_url) {\n meta.push(`**Live Site:** ${item.live_url}`)\n }\n\n if (meta.length > 0) {\n lines.push(meta.join(' | '))\n lines.push('')\n }\n }\n\n return lines.join('\\n').trim()\n}\n\nfunction generateContactSection(contact: LLMContactInfo): string {\n const lines: string[] = []\n \n lines.push('## Contact Information')\n lines.push('')\n \n if (contact.phone) {\n lines.push(`- **Phone:** ${contact.phone}`)\n }\n if (contact.email) {\n lines.push(`- **Email:** ${contact.email}`)\n }\n if (contact.address || contact.city) {\n const addressParts = [\n contact.address,\n contact.city,\n contact.state,\n contact.postal_code,\n contact.country\n ].filter(Boolean)\n lines.push(`- **Address:** ${addressParts.join(', ')}`)\n }\n if (contact.hours) {\n lines.push(`- **Hours:** ${contact.hours}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateFAQSection(faq: LLMFAQItem[]): string {\n const lines: string[] = []\n \n lines.push('## Frequently Asked Questions')\n lines.push('')\n \n for (const item of faq) {\n lines.push(`### ${item.question}`)\n lines.push('')\n lines.push(item.answer)\n lines.push('')\n }\n\n return lines.join('\\n').trim()\n}\n\nfunction pageListNote(\n page: LLMPageSummary,\n publicSummaryOnly: boolean,\n): string | undefined {\n const pub = sanitizeLlmsPublicSummary(page.llms_public_summary)\n if (pub) return pub\n if (publicSummaryOnly) return undefined\n if (page.description) return page.description.replace(/[\\[\\]\\r\\n]/g, ' ').trim()\n return undefined\n}\n\n/**\n * Single source of truth for matching an `optionalPagePaths` entry to a page:\n * leading slash added, one trailing slash ignored, empty → `/`. Used both to\n * pull demoted pages out of `## Site Pages` and to find them for `## Optional`,\n * so the two sections can't disagree about which page a path means.\n */\nfunction normalizeLlmsPagePath(path: string): string {\n const withLeading = path.startsWith('/') ? path : `/${path}`\n return withLeading.replace(/\\/$/, '') || '/'\n}\n\n/**\n * The `- [title](url): note` line for a known page. Shared by `## Site Pages`\n * and `## Optional` so a page moved to Optional keeps the URL and note it had\n * in the index. Moving a page doesn't change where it links.\n */\nfunction formatPageLine(\n page: LLMPageSummary,\n baseUrl: string,\n publicSummaryOnly: boolean,\n): string {\n const url = page.path.startsWith('http') ? page.path : `${baseUrl}${page.path}`\n const note = pageListNote(page, publicSummaryOnly)\n return note ? `- [${page.title}](${url}): ${note}` : `- [${page.title}](${url})`\n}\n\nfunction generatePagesSection(\n pages: LLMPageSummary[],\n baseUrl: string,\n publicSummaryOnly: boolean,\n): string {\n const lines: string[] = []\n\n lines.push('## Site Pages')\n lines.push('')\n\n for (const page of pages) {\n lines.push(formatPageLine(page, baseUrl, publicSummaryOnly))\n }\n\n return lines.join('\\n')\n}\n\nfunction generateOptionalPagesSection(\n paths: string[],\n pages: LLMPageSummary[],\n baseUrl: string,\n publicSummaryOnly: boolean,\n): string | null {\n // First row wins, matching the index order the API already prioritised.\n const byPath = new Map<string, LLMPageSummary>()\n for (const page of pages) {\n const key = normalizeLlmsPagePath(page.path)\n if (!byPath.has(key)) byPath.set(key, page)\n }\n const lines: string[] = ['## Optional', '']\n // `/privacy` and `/privacy/` are one page, so they get one line.\n const seen = new Set<string>()\n for (const raw of paths) {\n const key = normalizeLlmsPagePath(raw)\n if (seen.has(key)) continue\n seen.add(key)\n const match = byPath.get(key)\n if (match) {\n lines.push(formatPageLine(match, baseUrl, publicSummaryOnly))\n continue\n }\n // Not in the page list, so all we have is the path as the caller wrote it.\n const p = raw.startsWith('/') ? raw : `/${raw}`\n const title = key.split('/').filter(Boolean).pop() || key\n lines.push(`- [${title}](${baseUrl}${p.endsWith('/') ? p : `${p}/`})`)\n }\n return seen.size > 0 ? lines.join('\\n') : null\n}\n\nfunction generateEntitySection(\n entities: SEOEntity[],\n primaryEntity: SEOEntity | null,\n detailed: boolean\n): string {\n const lines: string[] = []\n\n lines.push('## Knowledge Graph')\n lines.push('')\n\n // Primary entity first\n if (primaryEntity) {\n lines.push(`### ${primaryEntity.name} (Primary)`)\n lines.push('')\n lines.push(`- **Type:** ${primaryEntity.entity_type}`)\n if (primaryEntity.schema_type) {\n lines.push(`- **Schema:** ${primaryEntity.schema_type}`)\n }\n if (detailed && primaryEntity.knows_about?.length) {\n lines.push(`- **Knows About:** ${primaryEntity.knows_about.join(', ')}`)\n }\n if (detailed && primaryEntity.same_as?.length) {\n lines.push(`- **Same As:** ${primaryEntity.same_as.join(', ')}`)\n }\n lines.push('')\n }\n\n // Group remaining entities by type\n const grouped = new Map<string, SEOEntity[]>()\n for (const entity of entities) {\n if (primaryEntity && entity.id === primaryEntity.id) continue\n const type = entity.entity_type\n if (!grouped.has(type)) grouped.set(type, [])\n grouped.get(type)!.push(entity)\n }\n\n for (const [type, group] of grouped) {\n const label = type.charAt(0).toUpperCase() + type.slice(1) + 's'\n lines.push(`### ${label}`)\n lines.push('')\n for (const entity of group) {\n if (detailed) {\n lines.push(`- **${entity.name}**`)\n if (entity.knows_about?.length) {\n lines.push(` - Knows About: ${entity.knows_about.join(', ')}`)\n }\n if (entity.same_as?.length) {\n lines.push(` - Same As: ${entity.same_as.join(', ')}`)\n }\n } else {\n lines.push(`- ${entity.name}`)\n }\n }\n lines.push('')\n }\n\n return lines.join('\\n').trim()\n}\n\nexport default generateLLMsTxt\n","/**\n * @sonordev/site-kit/llms - Build-Time Write\n *\n * Fetches AI-optimized llms.txt from Portal API and writes to public/llms.txt\n * at build time. Integrates with sitemap flow when optimizedLLMsTxt is enabled.\n */\n\nimport { writeFileSync, mkdirSync, existsSync, renameSync, unlinkSync } from 'fs'\nimport { join } from 'path'\nimport { getOptimizedLLMsTxt } from './api'\nimport { generateLLMsTxt, generateLLMsFullTxt } from './generateLLMsTxt'\nimport type { LLMsDataResponse, LLMSTxtContent } from './types'\n\nexport interface LLMsCustomSection {\n title: string\n content: string\n}\n\nexport interface WriteLLMsTxtOptions {\n /** Output directory (default: public, relative to cwd) */\n outputDir?: string\n /** Write llms-full.txt as well */\n full?: boolean\n /** Portal API URL */\n apiUrl?: string\n /** Portal API key */\n apiKey?: string\n /** Fallback to non-optimized when API fails */\n fallbackToLocal?: boolean\n /**\n * Sub-site host this build belongs to (e.g. `bd-charlotte.com`). Scopes the\n * page index to THIS domain: one Sonor project can host many domains, and\n * seo_pages then holds one row PER HOST for shared paths like `/` and\n * `/terms`. Without it the API resolves an arbitrary sibling's row, so each\n * build described whichever neighbour happened to sync last. Omit to resolve\n * from NEXT_PUBLIC_SITE_URL via the shared `resolveSiteHost`.\n */\n site?: string\n /** When Portal returns empty services/faq/pages, use this to supply local site data */\n getLocalData?: () => Promise<LLMsDataResponse | null>\n /** Forward to GET /api/public/llms/txt and align local fallback with site-kit strict page notes */\n publicSummaryOnly?: boolean\n /**\n * Site-authored sections appended to llms-full.txt (never llms.txt — that\n * file stays a compact index). Applied on BOTH content paths: appended to\n * the Portal-optimized markdown, and forwarded to the local generator's\n * customSections on fallback. A function form is resolved at write time so\n * sites can build sections from local data (e.g. a verified citation\n * registry → a \"Sourced facts\" section via formatSourcedFactsSection).\n * Sections are only ever appended to real base content — they can never\n * cause a customs-only file to be written.\n */\n customSections?:\n | LLMsCustomSection[]\n | (() => Promise<LLMsCustomSection[] | null> | LLMsCustomSection[] | null)\n}\n\n/**\n * Fetch optimized llms.txt from Portal and write to public/llms.txt\n * Called at build time after sitemap sync (when optimizedLLMsTxt is enabled)\n *\n * Never persists a failure stub: when neither the Portal API nor local data\n * yields real content, the write is skipped entirely so a previously\n * generated (or committed) file keeps serving.\n */\nexport async function writeLLMsTxtToPublic(\n options: WriteLLMsTxtOptions = {}\n): Promise<{ success: boolean; path: string; optimized: boolean }> {\n const {\n outputDir = 'public',\n full = false,\n apiUrl,\n apiKey,\n fallbackToLocal = true,\n site,\n getLocalData,\n publicSummaryOnly,\n customSections,\n } = options\n\n const cwd = typeof process !== 'undefined' ? process.cwd() : '.'\n const outPath = join(cwd, outputDir)\n const llmsPath = join(outPath, 'llms.txt')\n const llmsFullPath = join(outPath, 'llms-full.txt')\n\n // Ensure output directory exists\n if (!existsSync(outPath)) {\n mkdirSync(outPath, { recursive: true })\n }\n\n const apiOptions = { apiUrl, apiKey, publicSummaryOnly, site }\n\n const genOpts = {\n site,\n getLocalData,\n pageListNotesFromPublicSummaryOnly: !!publicSummaryOnly,\n }\n\n // Fetch optimized content\n let markdown = toWritableMarkdown(await getOptimizedLLMsTxt({ ...apiOptions, full: false }))\n let optimized = !!markdown\n\n if (!markdown && fallbackToLocal) {\n console.warn('[site-kit] Optimized llms.txt unavailable, using local generation')\n const result = await generateLLMsTxt(genOpts)\n markdown = toWritableMarkdown(result.markdown, result.metadata)\n }\n\n if (!markdown) {\n console.warn(\n `[site-kit] llms.txt unavailable (Portal fetch failed, no local data) — skipped write, keeping any existing file at ${llmsPath}`\n )\n return { success: false, path: llmsPath, optimized: false }\n }\n\n atomicWriteSync(llmsPath, markdown)\n console.log(`[site-kit] Wrote llms.txt to ${llmsPath}`)\n\n if (full) {\n const sections = await resolveCustomSections(customSections)\n\n let fullMarkdown = toWritableMarkdown(await getOptimizedLLMsTxt({ ...apiOptions, full: true }))\n if (fullMarkdown && sections.length > 0) {\n // Portal path returns finished markdown — append the site's sections.\n fullMarkdown = appendCustomSections(fullMarkdown, sections)\n }\n if (!fullMarkdown && fallbackToLocal) {\n // Local path — the generator appends customSections itself.\n const result = await generateLLMsFullTxt({ ...genOpts, customSections: sections })\n fullMarkdown = toWritableMarkdown(result.markdown, result.metadata)\n }\n if (fullMarkdown) {\n atomicWriteSync(llmsFullPath, fullMarkdown)\n console.log(`[site-kit] Wrote llms-full.txt to ${llmsFullPath}`)\n } else {\n console.warn(\n `[site-kit] llms-full.txt unavailable — skipped write, keeping any existing file at ${llmsFullPath}`\n )\n }\n }\n\n return { success: true, path: llmsPath, optimized }\n}\n\n/**\n * Single source of truth for \"is this real llms.txt content that may be\n * persisted?\" — applied to both the optimized Portal response and the\n * local-generation fallback (llms.txt and llms-full.txt).\n *\n * generateLLMsTxt returns an \"Information not available.\" stub with zero\n * metadata.sections when the Portal fetch and local data both fail. Stubs and\n * empty responses must never reach disk: consumer route handlers serve\n * public/llms.txt with preferStatic, so a single failed build would replace a\n * good file and keep serving the stub to AI crawlers until the next\n * successful build.\n */\nfunction toWritableMarkdown(\n markdown: string | null | undefined,\n metadata?: LLMSTxtContent['metadata'],\n): string | null {\n if (!markdown || !markdown.trim()) return null\n if (metadata && metadata.sections.length === 0) return null\n return markdown\n}\n\n/**\n * Resolve the customSections option (array or factory) defensively: a\n * throwing/rejecting factory or malformed entries must never break the\n * write of the base file — the sections are an enhancement, not a gate.\n */\nasync function resolveCustomSections(\n input: WriteLLMsTxtOptions['customSections'],\n): Promise<LLMsCustomSection[]> {\n if (!input) return []\n try {\n const raw = typeof input === 'function' ? await input() : input\n if (!Array.isArray(raw)) return []\n return raw.filter(\n (s): s is LLMsCustomSection =>\n !!s && typeof s.title === 'string' && !!s.title.trim() &&\n typeof s.content === 'string' && !!s.content.trim(),\n )\n } catch (err) {\n console.warn('[site-kit] llms customSections factory failed — sections skipped:', err)\n return []\n }\n}\n\n/** Append site sections in the generator's own section format. */\nfunction appendCustomSections(markdown: string, sections: LLMsCustomSection[]): string {\n const blocks = sections.map((s) => `## ${s.title}\\n\\n${s.content}`)\n return `${markdown.replace(/\\s+$/, '')}\\n\\n---\\n\\n${blocks.join('\\n\\n---\\n\\n')}\\n`\n}\n\n/**\n * Atomic write: write to .tmp then rename (POSIX atomic).\n * Prevents corrupted files on crash or disk-full.\n */\nfunction atomicWriteSync(filePath: string, content: string): void {\n const tmp = `${filePath}.tmp`\n try {\n writeFileSync(tmp, content, 'utf-8')\n renameSync(tmp, filePath)\n } catch (err) {\n // Clean up temp file on failure\n try { unlinkSync(tmp) } catch { /* ignore */ }\n throw err\n }\n}\n"]}