@sonordev/site-kit 5.6.0 → 5.8.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 (632) hide show
  1. package/README.md +3 -3
  2. package/agent-manifest.json +24 -4
  3. package/dist/AnalyticsProvider-OCXRNIVE.js +33 -0
  4. package/dist/{AnalyticsProvider-6PXC7UDP.js.map → AnalyticsProvider-OCXRNIVE.js.map} +1 -1
  5. package/dist/AnalyticsProvider-ZAUONQCX.mjs +12 -0
  6. package/dist/{AnalyticsProvider-FVQIYSLY.mjs.map → AnalyticsProvider-ZAUONQCX.mjs.map} +1 -1
  7. package/dist/{BlogViewTracker-S4HSRCW7.js → BlogViewTracker-HK5C7PU6.js} +14 -11
  8. package/dist/BlogViewTracker-HK5C7PU6.js.map +1 -0
  9. package/dist/{BlogViewTracker-ZUGLBOVI.mjs → BlogViewTracker-KXRZHN3U.mjs} +13 -10
  10. package/dist/BlogViewTracker-KXRZHN3U.mjs.map +1 -0
  11. package/dist/ChatWidget-3OW5LY37.js +24 -0
  12. package/dist/{ChatWidget-2TQWCXWP.js.map → ChatWidget-3OW5LY37.js.map} +1 -1
  13. package/dist/ChatWidget-54GVS27I.mjs +15 -0
  14. package/dist/{ChatWidget-DG52ZIE6.mjs.map → ChatWidget-54GVS27I.mjs.map} +1 -1
  15. package/dist/EngageWidget-7EUP76WE.mjs +12 -0
  16. package/dist/{EngageWidget-2VUJADIU.mjs.map → EngageWidget-7EUP76WE.mjs.map} +1 -1
  17. package/dist/EngageWidget-DDP5UFA4.js +21 -0
  18. package/dist/{EngageWidget-Z7RC2INM.js.map → EngageWidget-DDP5UFA4.js.map} +1 -1
  19. package/dist/{FileField-FSQ7W3A5.mjs → FileField-IQLN6E3C.mjs} +5 -5
  20. package/dist/{FileField-FSQ7W3A5.mjs.map → FileField-IQLN6E3C.mjs.map} +1 -1
  21. package/dist/{FileField-UOQHL25J.js → FileField-SBPL4JHP.js} +6 -6
  22. package/dist/{FileField-UOQHL25J.js.map → FileField-SBPL4JHP.js.map} +1 -1
  23. package/dist/{FormSpotlight-RHL5FWM2.mjs → FormSpotlight-E2LKKHGV.mjs} +11 -7
  24. package/dist/FormSpotlight-E2LKKHGV.mjs.map +1 -0
  25. package/dist/{FormSpotlight-TED32NHP.js → FormSpotlight-YTACNE57.js} +25 -21
  26. package/dist/FormSpotlight-YTACNE57.js.map +1 -0
  27. package/dist/{FormStage-PFEBKHGY.js → FormStage-S277U2CP.js} +20 -15
  28. package/dist/FormStage-S277U2CP.js.map +1 -0
  29. package/dist/{FormStage-DINIRFOX.mjs → FormStage-YSBN5XKL.mjs} +9 -4
  30. package/dist/FormStage-YSBN5XKL.mjs.map +1 -0
  31. package/dist/ManagedForm-I3QVRQ53.mjs +16 -0
  32. package/dist/{ManagedForm-545YAUFC.mjs.map → ManagedForm-I3QVRQ53.mjs.map} +1 -1
  33. package/dist/ManagedForm-TSYKQFLJ.js +25 -0
  34. package/dist/{ManagedForm-43WLCUAK.js.map → ManagedForm-TSYKQFLJ.js.map} +1 -1
  35. package/dist/{ManagedNewsletterForm-ZPY5RRKX.mjs → ManagedNewsletterForm-T3YRAWKZ.mjs} +9 -7
  36. package/dist/ManagedNewsletterForm-T3YRAWKZ.mjs.map +1 -0
  37. package/dist/{ManagedNewsletterForm-I3QN57HB.js → ManagedNewsletterForm-YSOPPKS6.js} +10 -8
  38. package/dist/ManagedNewsletterForm-YSOPPKS6.js.map +1 -0
  39. package/dist/{SignalCore-EEH5IM4U.mjs → SignalCore-PPSIQ4BW.mjs} +8 -14
  40. package/dist/SignalCore-PPSIQ4BW.mjs.map +1 -0
  41. package/dist/{SignalCore-M4AXIMV4.js → SignalCore-SUZH3XWZ.js} +14 -20
  42. package/dist/SignalCore-SUZH3XWZ.js.map +1 -0
  43. package/dist/SitemapSync-HSHCOKCL.mjs +9 -0
  44. package/dist/{SitemapSync-46G7LVZS.mjs.map → SitemapSync-HSHCOKCL.mjs.map} +1 -1
  45. package/dist/SitemapSync-LH6UVP4P.js +18 -0
  46. package/dist/{SitemapSync-XK4JKCS7.js.map → SitemapSync-LH6UVP4P.js.map} +1 -1
  47. package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
  48. package/dist/analytics/index.js +10 -9
  49. package/dist/analytics/index.mjs +5 -4
  50. package/dist/blog/BlogLayout.d.ts +3 -1
  51. package/dist/blog/BlogLayout.d.ts.map +1 -1
  52. package/dist/blog/BlogList.d.ts +7 -1
  53. package/dist/blog/BlogList.d.ts.map +1 -1
  54. package/dist/blog/BlogPost.d.ts +20 -1
  55. package/dist/blog/BlogPost.d.ts.map +1 -1
  56. package/dist/blog/BlogSidebar.d.ts +3 -1
  57. package/dist/blog/BlogSidebar.d.ts.map +1 -1
  58. package/dist/blog/BlogViewTracker.d.ts +8 -2
  59. package/dist/blog/BlogViewTracker.d.ts.map +1 -1
  60. package/dist/blog/ClusterLandingPage.d.ts +3 -1
  61. package/dist/blog/ClusterLandingPage.d.ts.map +1 -1
  62. package/dist/blog/ClusterNavigation.d.ts +5 -2
  63. package/dist/blog/ClusterNavigation.d.ts.map +1 -1
  64. package/dist/blog/RelatedPosts.d.ts +3 -1
  65. package/dist/blog/RelatedPosts.d.ts.map +1 -1
  66. package/dist/blog/index.d.ts +1 -1
  67. package/dist/blog/index.d.ts.map +1 -1
  68. package/dist/blog/index.js +40 -31
  69. package/dist/blog/index.js.map +1 -1
  70. package/dist/blog/index.mjs +11 -6
  71. package/dist/blog/index.mjs.map +1 -1
  72. package/dist/blog/metadata-images.test.d.ts +2 -0
  73. package/dist/blog/metadata-images.test.d.ts.map +1 -0
  74. package/dist/blog/not-found.test.d.ts +2 -0
  75. package/dist/blog/not-found.test.d.ts.map +1 -0
  76. package/dist/blog/processBlogHtml.d.ts +19 -2
  77. package/dist/blog/processBlogHtml.d.ts.map +1 -1
  78. package/dist/blog/public-reads.d.ts +27 -0
  79. package/dist/blog/public-reads.d.ts.map +1 -0
  80. package/dist/blog/server-core.d.ts +107 -16
  81. package/dist/blog/server-core.d.ts.map +1 -1
  82. package/dist/blog/server-ui.js +29 -23
  83. package/dist/blog/server-ui.js.map +1 -1
  84. package/dist/blog/server-ui.mjs +12 -6
  85. package/dist/blog/server-ui.mjs.map +1 -1
  86. package/dist/blog/server.d.ts +107 -16
  87. package/dist/blog/server.d.ts.map +1 -1
  88. package/dist/blog/server.js +54 -47
  89. package/dist/blog/server.mjs +5 -2
  90. package/dist/blog/site-scope.test.d.ts +2 -0
  91. package/dist/blog/site-scope.test.d.ts.map +1 -0
  92. package/dist/blog/static-params.test.d.ts +2 -0
  93. package/dist/blog/static-params.test.d.ts.map +1 -0
  94. package/dist/brand/extract-brand-profile.d.ts +36 -2
  95. package/dist/brand/extract-brand-profile.d.ts.map +1 -1
  96. package/dist/brand/extract-brand-profile.test.d.ts +2 -0
  97. package/dist/brand/extract-brand-profile.test.d.ts.map +1 -0
  98. package/dist/{chunk-B64AZC6P.js → chunk-2FQG2AHJ.js} +60 -35
  99. package/dist/chunk-2FQG2AHJ.js.map +1 -0
  100. package/dist/{chunk-N2PGTPWN.js → chunk-2OQWLXDO.js} +13 -13
  101. package/dist/{chunk-N2PGTPWN.js.map → chunk-2OQWLXDO.js.map} +1 -1
  102. package/dist/{chunk-T5VTQUNF.js → chunk-2SCDUVFJ.js} +10 -10
  103. package/dist/{chunk-T5VTQUNF.js.map → chunk-2SCDUVFJ.js.map} +1 -1
  104. package/dist/{chunk-S4RC6VAQ.js → chunk-35ERUUH3.js} +6 -6
  105. package/dist/{chunk-S4RC6VAQ.js.map → chunk-35ERUUH3.js.map} +1 -1
  106. package/dist/{chunk-VHZ4LHQT.mjs → chunk-3AUFD7KR.mjs} +3 -3
  107. package/dist/{chunk-VHZ4LHQT.mjs.map → chunk-3AUFD7KR.mjs.map} +1 -1
  108. package/dist/{chunk-DHIWR7CG.js → chunk-3BVCF4ZF.js} +4 -4
  109. package/dist/{chunk-DHIWR7CG.js.map → chunk-3BVCF4ZF.js.map} +1 -1
  110. package/dist/{chunk-EEQYKMGH.mjs → chunk-3EY5E35M.mjs} +57 -86
  111. package/dist/chunk-3EY5E35M.mjs.map +1 -0
  112. package/dist/{chunk-JNABXCLY.mjs → chunk-3SLFT453.mjs} +5 -5
  113. package/dist/{chunk-JNABXCLY.mjs.map → chunk-3SLFT453.mjs.map} +1 -1
  114. package/dist/{chunk-AJQI3WTN.mjs → chunk-4L7OHRWB.mjs} +12 -9
  115. package/dist/chunk-4L7OHRWB.mjs.map +1 -0
  116. package/dist/chunk-4LYW6PMU.mjs +72 -0
  117. package/dist/chunk-4LYW6PMU.mjs.map +1 -0
  118. package/dist/{chunk-R3KTBKSW.js → chunk-4OS6M3V4.js} +6 -12
  119. package/dist/chunk-4OS6M3V4.js.map +1 -0
  120. package/dist/{chunk-AY7JBGYC.js → chunk-4RY7JETY.js} +14 -14
  121. package/dist/{chunk-AY7JBGYC.js.map → chunk-4RY7JETY.js.map} +1 -1
  122. package/dist/chunk-4TLFZ6NR.mjs +16 -0
  123. package/dist/chunk-4TLFZ6NR.mjs.map +1 -0
  124. package/dist/{chunk-4B4S56WJ.mjs → chunk-5B4J3IBX.mjs} +75 -21
  125. package/dist/chunk-5B4J3IBX.mjs.map +1 -0
  126. package/dist/chunk-5O7JSWT6.js +8 -0
  127. package/dist/{chunk-KSL3WA2I.js.map → chunk-5O7JSWT6.js.map} +1 -1
  128. package/dist/chunk-5SANRSX3.mjs +17 -0
  129. package/dist/chunk-5SANRSX3.mjs.map +1 -0
  130. package/dist/{chunk-LCSYJXIO.mjs → chunk-5WGMXSCB.mjs} +3 -3
  131. package/dist/{chunk-LCSYJXIO.mjs.map → chunk-5WGMXSCB.mjs.map} +1 -1
  132. package/dist/chunk-5XFFUP6D.js +100 -0
  133. package/dist/chunk-5XFFUP6D.js.map +1 -0
  134. package/dist/{chunk-AHZR4VGY.mjs → chunk-6HFFTGFP.mjs} +50 -26
  135. package/dist/chunk-6HFFTGFP.mjs.map +1 -0
  136. package/dist/{chunk-USKIL6V6.mjs → chunk-6SBTHS6C.mjs} +3 -3
  137. package/dist/{chunk-USKIL6V6.mjs.map → chunk-6SBTHS6C.mjs.map} +1 -1
  138. package/dist/{chunk-NZSFOZJV.js → chunk-7TC3GRXQ.js} +73 -38
  139. package/dist/chunk-7TC3GRXQ.js.map +1 -0
  140. package/dist/{chunk-HIHAXEPD.mjs → chunk-7THZOAUR.mjs} +4 -4
  141. package/dist/{chunk-HIHAXEPD.mjs.map → chunk-7THZOAUR.mjs.map} +1 -1
  142. package/dist/{chunk-YCI36ZUS.mjs → chunk-AOWJP25J.mjs} +4 -4
  143. package/dist/{chunk-YCI36ZUS.mjs.map → chunk-AOWJP25J.mjs.map} +1 -1
  144. package/dist/{chunk-H44XZUOV.mjs → chunk-B2VFMPVJ.mjs} +4 -4
  145. package/dist/{chunk-H44XZUOV.mjs.map → chunk-B2VFMPVJ.mjs.map} +1 -1
  146. package/dist/{chunk-OA7KKOAK.mjs → chunk-B35OJ7FR.mjs} +4 -4
  147. package/dist/{chunk-OA7KKOAK.mjs.map → chunk-B35OJ7FR.mjs.map} +1 -1
  148. package/dist/{chunk-XR32C47O.js → chunk-BER36QXU.js} +9 -9
  149. package/dist/{chunk-XR32C47O.js.map → chunk-BER36QXU.js.map} +1 -1
  150. package/dist/{chunk-7C7XO5HX.mjs → chunk-BFZNLTWK.mjs} +3 -3
  151. package/dist/{chunk-7C7XO5HX.mjs.map → chunk-BFZNLTWK.mjs.map} +1 -1
  152. package/dist/chunk-BQP6JIE2.mjs +28 -0
  153. package/dist/chunk-BQP6JIE2.mjs.map +1 -0
  154. package/dist/{chunk-5KIO6FXE.js → chunk-C3WU45JT.js} +7 -7
  155. package/dist/{chunk-5KIO6FXE.js.map → chunk-C3WU45JT.js.map} +1 -1
  156. package/dist/chunk-CUNZAD46.js +53 -0
  157. package/dist/chunk-CUNZAD46.js.map +1 -0
  158. package/dist/chunk-CXAXZFFW.js +157 -0
  159. package/dist/chunk-CXAXZFFW.js.map +1 -0
  160. package/dist/{chunk-H4OBGC43.mjs → chunk-DA7IANFG.mjs} +14 -3
  161. package/dist/chunk-DA7IANFG.mjs.map +1 -0
  162. package/dist/{chunk-BWSMUSDB.js → chunk-EIW6YEPY.js} +8 -8
  163. package/dist/{chunk-BWSMUSDB.js.map → chunk-EIW6YEPY.js.map} +1 -1
  164. package/dist/{chunk-UU47DGHE.js → chunk-F6SKG34N.js} +8 -13
  165. package/dist/chunk-F6SKG34N.js.map +1 -0
  166. package/dist/{chunk-LC7AM4J5.js → chunk-FHPW7XVH.js} +77 -20
  167. package/dist/chunk-FHPW7XVH.js.map +1 -0
  168. package/dist/{chunk-JNRHTZL4.js → chunk-FVW6FT6L.js} +73 -29
  169. package/dist/chunk-FVW6FT6L.js.map +1 -0
  170. package/dist/{chunk-KY6M76JW.js → chunk-GNDWTXLU.js} +56 -177
  171. package/dist/chunk-GNDWTXLU.js.map +1 -0
  172. package/dist/{chunk-OZ3FU4BT.js → chunk-H5NBFNND.js} +2 -2
  173. package/dist/chunk-H5NBFNND.js.map +1 -0
  174. package/dist/{chunk-SYGGZZMU.js → chunk-HAKD27AZ.js} +7 -7
  175. package/dist/{chunk-SYGGZZMU.js.map → chunk-HAKD27AZ.js.map} +1 -1
  176. package/dist/chunk-HCN3IKMW.mjs +106 -0
  177. package/dist/chunk-HCN3IKMW.mjs.map +1 -0
  178. package/dist/{chunk-QNPVVWR7.mjs → chunk-HCX343AS.mjs} +4 -4
  179. package/dist/{chunk-QNPVVWR7.mjs.map → chunk-HCX343AS.mjs.map} +1 -1
  180. package/dist/{chunk-C2MSD2UM.mjs → chunk-HEOQT5SM.mjs} +216 -103
  181. package/dist/chunk-HEOQT5SM.mjs.map +1 -0
  182. package/dist/{chunk-RU54J2PY.mjs → chunk-HOJ4J4X2.mjs} +30 -12
  183. package/dist/chunk-HOJ4J4X2.mjs.map +1 -0
  184. package/dist/{chunk-H3D3ZGOJ.js → chunk-HQOHB6QF.js} +15 -15
  185. package/dist/{chunk-H3D3ZGOJ.js.map → chunk-HQOHB6QF.js.map} +1 -1
  186. package/dist/chunk-HRMGITUZ.mjs +6 -0
  187. package/dist/{chunk-DQUBETXH.mjs.map → chunk-HRMGITUZ.mjs.map} +1 -1
  188. package/dist/{chunk-7AUDKXY5.mjs → chunk-HYVEIP2N.mjs} +3 -3
  189. package/dist/{chunk-7AUDKXY5.mjs.map → chunk-HYVEIP2N.mjs.map} +1 -1
  190. package/dist/{chunk-46BMNWE6.js → chunk-I3ND4XYW.js} +12 -9
  191. package/dist/chunk-I3ND4XYW.js.map +1 -0
  192. package/dist/{chunk-53KMRZT7.js → chunk-JDTU2RWC.js} +3 -3
  193. package/dist/{chunk-53KMRZT7.js.map → chunk-JDTU2RWC.js.map} +1 -1
  194. package/dist/{chunk-GZJE23Y5.mjs → chunk-JLVCWC6A.mjs} +2 -2
  195. package/dist/chunk-JLVCWC6A.mjs.map +1 -0
  196. package/dist/chunk-K4TCEAUX.js +52 -0
  197. package/dist/chunk-K4TCEAUX.js.map +1 -0
  198. package/dist/chunk-KV7XXLJV.mjs +30 -0
  199. package/dist/chunk-KV7XXLJV.mjs.map +1 -0
  200. package/dist/{chunk-5UFDHGFE.mjs → chunk-L24RDT6Q.mjs} +3 -3
  201. package/dist/{chunk-5UFDHGFE.mjs.map → chunk-L24RDT6Q.mjs.map} +1 -1
  202. package/dist/{chunk-JE5DWAE6.js → chunk-LBZGYF3B.js} +4 -4
  203. package/dist/{chunk-JE5DWAE6.js.map → chunk-LBZGYF3B.js.map} +1 -1
  204. package/dist/{chunk-746RKQHA.js → chunk-LMEUYRRR.js} +93 -121
  205. package/dist/chunk-LMEUYRRR.js.map +1 -0
  206. package/dist/chunk-LVGSOW2F.js +32 -0
  207. package/dist/chunk-LVGSOW2F.js.map +1 -0
  208. package/dist/{chunk-KPKQKFT4.js → chunk-M45AL7EA.js} +37 -19
  209. package/dist/chunk-M45AL7EA.js.map +1 -0
  210. package/dist/{chunk-XK5AIWQG.js → chunk-MHX6TOAS.js} +3 -3
  211. package/dist/{chunk-XK5AIWQG.js.map → chunk-MHX6TOAS.js.map} +1 -1
  212. package/dist/chunk-MLVHVKFT.mjs +148 -0
  213. package/dist/chunk-MLVHVKFT.mjs.map +1 -0
  214. package/dist/{chunk-RIYAMYLV.mjs → chunk-N2NZBPQ5.mjs} +4 -10
  215. package/dist/chunk-N2NZBPQ5.mjs.map +1 -0
  216. package/dist/chunk-NRBITVDK.js +114 -0
  217. package/dist/chunk-NRBITVDK.js.map +1 -0
  218. package/dist/{chunk-IYCLN3XS.mjs → chunk-O4YBWJHP.mjs} +6 -11
  219. package/dist/chunk-O4YBWJHP.mjs.map +1 -0
  220. package/dist/{chunk-5KIEZHVK.mjs → chunk-O5ZSGBQD.mjs} +4 -4
  221. package/dist/{chunk-5KIEZHVK.mjs.map → chunk-O5ZSGBQD.mjs.map} +1 -1
  222. package/dist/{chunk-TP7H6BSK.mjs → chunk-OE7CTIOU.mjs} +73 -30
  223. package/dist/chunk-OE7CTIOU.mjs.map +1 -0
  224. package/dist/{chunk-UJ6CHZAI.mjs → chunk-OEW2LFOV.js} +169 -25
  225. package/dist/chunk-OEW2LFOV.js.map +1 -0
  226. package/dist/chunk-P4Y75QSU.js +19 -0
  227. package/dist/chunk-P4Y75QSU.js.map +1 -0
  228. package/dist/{chunk-6OP5XSMM.mjs → chunk-PK2OTGW5.mjs} +6 -12
  229. package/dist/chunk-PK2OTGW5.mjs.map +1 -0
  230. package/dist/{chunk-OC7AO7XS.js → chunk-PRTXAIIC.js} +15 -15
  231. package/dist/{chunk-OC7AO7XS.js.map → chunk-PRTXAIIC.js.map} +1 -1
  232. package/dist/{chunk-K2V3ZW36.mjs → chunk-PUAXHYBL.mjs} +3 -3
  233. package/dist/{chunk-K2V3ZW36.mjs.map → chunk-PUAXHYBL.mjs.map} +1 -1
  234. package/dist/chunk-QRHVMTHF.mjs +94 -0
  235. package/dist/chunk-QRHVMTHF.mjs.map +1 -0
  236. package/dist/{chunk-BZLIOT7Q.js → chunk-QTJTDQYR.js} +76 -111
  237. package/dist/chunk-QTJTDQYR.js.map +1 -0
  238. package/dist/{chunk-GJ6NOLGC.mjs → chunk-QVHVL7EX.mjs} +3 -3
  239. package/dist/{chunk-GJ6NOLGC.mjs.map → chunk-QVHVL7EX.mjs.map} +1 -1
  240. package/dist/chunk-R7GHP3FY.js +81 -0
  241. package/dist/chunk-R7GHP3FY.js.map +1 -0
  242. package/dist/chunk-SEP5D4MI.js +116 -0
  243. package/dist/chunk-SEP5D4MI.js.map +1 -0
  244. package/dist/{chunk-GPLCPMVD.mjs → chunk-TXMVU4EY.mjs} +62 -97
  245. package/dist/chunk-TXMVU4EY.mjs.map +1 -0
  246. package/dist/chunk-U2V542EO.mjs +98 -0
  247. package/dist/chunk-U2V542EO.mjs.map +1 -0
  248. package/dist/{chunk-YYN4YZYZ.js → chunk-UWHCHYCX.js} +4 -4
  249. package/dist/{chunk-YYN4YZYZ.js.map → chunk-UWHCHYCX.js.map} +1 -1
  250. package/dist/{chunk-473WDGQZ.mjs → chunk-VJ74275U.mjs} +38 -156
  251. package/dist/chunk-VJ74275U.mjs.map +1 -0
  252. package/dist/{chunk-H7274TKR.mjs → chunk-VJV7WUR2.mjs} +12 -4
  253. package/dist/chunk-VJV7WUR2.mjs.map +1 -0
  254. package/dist/{chunk-CQS5ZYI6.mjs → chunk-VYL6IHJA.mjs} +9 -9
  255. package/dist/{chunk-CQS5ZYI6.mjs.map → chunk-VYL6IHJA.mjs.map} +1 -1
  256. package/dist/{chunk-5B4FABFK.js → chunk-WS7MH3GD.js} +14 -2
  257. package/dist/chunk-WS7MH3GD.js.map +1 -0
  258. package/dist/{chunk-IPV2TUAT.js → chunk-XA2GJFVM.js} +12 -4
  259. package/dist/chunk-XA2GJFVM.js.map +1 -0
  260. package/dist/chunk-XBX2K3GA.js +33 -0
  261. package/dist/chunk-XBX2K3GA.js.map +1 -0
  262. package/dist/{chunk-X5TCH7VZ.js → chunk-XCYKM2SA.js} +6 -13
  263. package/dist/chunk-XCYKM2SA.js.map +1 -0
  264. package/dist/{chunk-6CJP7BFM.js → chunk-XZO5I4RS.mjs} +147 -20
  265. package/dist/chunk-XZO5I4RS.mjs.map +1 -0
  266. package/dist/chunk-Y5QZPUL3.mjs +47 -0
  267. package/dist/chunk-Y5QZPUL3.mjs.map +1 -0
  268. package/dist/{chunk-B6O7D5U4.js → chunk-YECDJDDD.js} +10 -10
  269. package/dist/{chunk-B6O7D5U4.js.map → chunk-YECDJDDD.js.map} +1 -1
  270. package/dist/chunk-YN7QHLWF.js +19 -0
  271. package/dist/chunk-YN7QHLWF.js.map +1 -0
  272. package/dist/chunk-YU7QZ3PP.mjs +45 -0
  273. package/dist/chunk-YU7QZ3PP.mjs.map +1 -0
  274. package/dist/{chunk-CQRLKNHQ.js → chunk-ZEOC26LZ.js} +223 -110
  275. package/dist/chunk-ZEOC26LZ.js.map +1 -0
  276. package/dist/{chunk-AEARU24Q.mjs → chunk-ZVI7MBVF.mjs} +73 -38
  277. package/dist/chunk-ZVI7MBVF.mjs.map +1 -0
  278. package/dist/cli/agent/checks.d.ts +15 -1
  279. package/dist/cli/agent/checks.d.ts.map +1 -1
  280. package/dist/cli/agent/sitemap-trailing-slash.test.d.ts +2 -0
  281. package/dist/cli/agent/sitemap-trailing-slash.test.d.ts.map +1 -0
  282. package/dist/cli/commands/api-routes.d.ts.map +1 -1
  283. package/dist/cli/commands/doctor.d.ts.map +1 -1
  284. package/dist/cli/commands/geo.d.ts +4 -0
  285. package/dist/cli/commands/geo.d.ts.map +1 -1
  286. package/dist/cli/commands/geo.test.d.ts +2 -0
  287. package/dist/cli/commands/geo.test.d.ts.map +1 -0
  288. package/dist/cli/commands/og.d.ts +31 -4
  289. package/dist/cli/commands/og.d.ts.map +1 -1
  290. package/dist/cli/commands/scaffold.d.ts +1 -2
  291. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  292. package/dist/cli/commands/sync.d.ts.map +1 -1
  293. package/dist/cli/generators/index.d.ts +5 -0
  294. package/dist/cli/generators/index.d.ts.map +1 -1
  295. package/dist/cli/generators/index.test.d.ts +2 -0
  296. package/dist/cli/generators/index.test.d.ts.map +1 -0
  297. package/dist/cli/index.js +921 -466
  298. package/dist/cli/index.js.map +1 -1
  299. package/dist/cli/index.mjs +862 -407
  300. package/dist/cli/index.mjs.map +1 -1
  301. package/dist/client/index.js +6 -6
  302. package/dist/client/index.mjs +5 -5
  303. package/dist/commerce/CheckoutForm.d.ts.map +1 -1
  304. package/dist/commerce/ProductDetail.d.ts.map +1 -1
  305. package/dist/commerce/api.d.ts +14 -0
  306. package/dist/commerce/api.d.ts.map +1 -1
  307. package/dist/commerce/discount-checkout.test.d.ts +2 -0
  308. package/dist/commerce/discount-checkout.test.d.ts.map +1 -0
  309. package/dist/commerce/index.d.ts +1 -1
  310. package/dist/commerce/index.d.ts.map +1 -1
  311. package/dist/commerce/index.js +61 -56
  312. package/dist/commerce/index.mjs +6 -5
  313. package/dist/config/index.js +3 -3
  314. package/dist/config/index.mjs +1 -1
  315. package/dist/discover-CYXYKHZ2.mjs +4 -0
  316. package/dist/{discover-BEJRYNFF.mjs.map → discover-CYXYKHZ2.mjs.map} +1 -1
  317. package/dist/discover-NGEPXZOD.js +21 -0
  318. package/dist/{discover-WVDYDUJX.js.map → discover-NGEPXZOD.js.map} +1 -1
  319. package/dist/engage/index.js +12 -10
  320. package/dist/engage/index.js.map +1 -1
  321. package/dist/engage/index.mjs +9 -7
  322. package/dist/engage/index.mjs.map +1 -1
  323. package/dist/fleet/index.js +8 -8
  324. package/dist/fleet/index.mjs +4 -4
  325. package/dist/forms/FormClient.d.ts.map +1 -1
  326. package/dist/forms/FormField.d.ts +7 -1
  327. package/dist/forms/FormField.d.ts.map +1 -1
  328. package/dist/forms/FormSpotlight.d.ts +1 -1
  329. package/dist/forms/FormSpotlight.d.ts.map +1 -1
  330. package/dist/forms/FormStage.d.ts +1 -1
  331. package/dist/forms/FormStage.d.ts.map +1 -1
  332. package/dist/forms/experience-plan.d.ts +0 -1
  333. package/dist/forms/experience-plan.d.ts.map +1 -1
  334. package/dist/forms/field-interactions.d.ts +63 -0
  335. package/dist/forms/field-interactions.d.ts.map +1 -0
  336. package/dist/forms/field-interactions.test.d.ts +8 -0
  337. package/dist/forms/field-interactions.test.d.ts.map +1 -0
  338. package/dist/forms/field-rules.d.ts +41 -0
  339. package/dist/forms/field-rules.d.ts.map +1 -0
  340. package/dist/forms/field-rules.test.d.ts +8 -0
  341. package/dist/forms/field-rules.test.d.ts.map +1 -0
  342. package/dist/forms/form-field-focus.test.d.ts +8 -0
  343. package/dist/forms/form-field-focus.test.d.ts.map +1 -0
  344. package/dist/forms/index.js +25 -23
  345. package/dist/forms/index.js.map +1 -1
  346. package/dist/forms/index.mjs +13 -11
  347. package/dist/forms/index.mjs.map +1 -1
  348. package/dist/forms/server.js +11 -11
  349. package/dist/forms/server.mjs +9 -9
  350. package/dist/forms/static.js +8 -8
  351. package/dist/forms/static.mjs +7 -7
  352. package/dist/forms/tracking-session.d.ts +48 -3
  353. package/dist/forms/tracking-session.d.ts.map +1 -1
  354. package/dist/forms/types.d.ts +11 -0
  355. package/dist/forms/types.d.ts.map +1 -1
  356. package/dist/forms/useForm.d.ts +8 -0
  357. package/dist/forms/useForm.d.ts.map +1 -1
  358. package/dist/forms/useFormTracking.d.ts +29 -4
  359. package/dist/forms/useFormTracking.d.ts.map +1 -1
  360. package/dist/images/index.js +11 -11
  361. package/dist/images/index.mjs +4 -4
  362. package/dist/index.js +72 -68
  363. package/dist/index.js.map +1 -1
  364. package/dist/index.mjs +14 -10
  365. package/dist/index.mjs.map +1 -1
  366. package/dist/layout/client.js +10 -10
  367. package/dist/layout/client.mjs +9 -9
  368. package/dist/layout/index.js +13 -12
  369. package/dist/layout/index.js.map +1 -1
  370. package/dist/layout/index.mjs +11 -10
  371. package/dist/layout/index.mjs.map +1 -1
  372. package/dist/llms/aiRobots.d.ts +24 -5
  373. package/dist/llms/aiRobots.d.ts.map +1 -1
  374. package/dist/llms/api.d.ts +8 -3
  375. package/dist/llms/api.d.ts.map +1 -1
  376. package/dist/llms/discovery-headers.d.ts +24 -0
  377. package/dist/llms/discovery-headers.d.ts.map +1 -1
  378. package/dist/llms/generateLLMsTxt.d.ts.map +1 -1
  379. package/dist/llms/handlers.d.ts +20 -2
  380. package/dist/llms/handlers.d.ts.map +1 -1
  381. package/dist/llms/index.d.ts +2 -2
  382. package/dist/llms/index.d.ts.map +1 -1
  383. package/dist/llms/index.js +54 -98
  384. package/dist/llms/index.js.map +1 -1
  385. package/dist/llms/index.mjs +20 -83
  386. package/dist/llms/index.mjs.map +1 -1
  387. package/dist/llms/links.d.ts +26 -0
  388. package/dist/llms/links.d.ts.map +1 -0
  389. package/dist/llms/links.test.d.ts +2 -0
  390. package/dist/llms/links.test.d.ts.map +1 -0
  391. package/dist/llms/types.d.ts +15 -0
  392. package/dist/llms/types.d.ts.map +1 -1
  393. package/dist/llms/wiring.d.ts +103 -0
  394. package/dist/llms/wiring.d.ts.map +1 -0
  395. package/dist/llms/wiring.test.d.ts +2 -0
  396. package/dist/llms/wiring.test.d.ts.map +1 -0
  397. package/dist/llms/writeLLMsTxt.d.ts +9 -0
  398. package/dist/llms/writeLLMsTxt.d.ts.map +1 -1
  399. package/dist/maps/index.js +5 -5
  400. package/dist/maps/index.mjs +3 -3
  401. package/dist/motion/gsap.d.ts +54 -0
  402. package/dist/motion/gsap.d.ts.map +1 -1
  403. package/dist/motion/gsap.js +34 -4
  404. package/dist/motion/gsap.js.map +1 -1
  405. package/dist/motion/gsap.mjs +33 -5
  406. package/dist/motion/gsap.mjs.map +1 -1
  407. package/dist/motion/gsap.test.d.ts +2 -0
  408. package/dist/motion/gsap.test.d.ts.map +1 -0
  409. package/dist/og/config.d.ts +6 -0
  410. package/dist/og/config.d.ts.map +1 -1
  411. package/dist/og/contrast.d.ts +33 -0
  412. package/dist/og/contrast.d.ts.map +1 -0
  413. package/dist/og/index.d.ts +2 -0
  414. package/dist/og/index.d.ts.map +1 -1
  415. package/dist/og/index.js +26 -8
  416. package/dist/og/index.mjs +3 -1
  417. package/dist/og/pages.d.ts +101 -0
  418. package/dist/og/pages.d.ts.map +1 -1
  419. package/dist/og/route-copy.d.ts +34 -0
  420. package/dist/og/route-copy.d.ts.map +1 -0
  421. package/dist/og/route-fit.d.ts +77 -0
  422. package/dist/og/route-fit.d.ts.map +1 -0
  423. package/dist/og/route.d.ts +80 -20
  424. package/dist/og/route.d.ts.map +1 -1
  425. package/dist/og/route.js +195 -25
  426. package/dist/og/route.js.map +1 -1
  427. package/dist/og/route.mjs +193 -26
  428. package/dist/og/route.mjs.map +1 -1
  429. package/dist/og/route.test.d.ts +2 -0
  430. package/dist/og/route.test.d.ts.map +1 -0
  431. package/dist/og/template.d.ts.map +1 -1
  432. package/dist/og/wiring.d.ts +48 -4
  433. package/dist/og/wiring.d.ts.map +1 -1
  434. package/dist/proxy/index.d.ts +16 -11
  435. package/dist/proxy/index.d.ts.map +1 -1
  436. package/dist/proxy/index.js +15 -10
  437. package/dist/proxy/index.js.map +1 -1
  438. package/dist/proxy/index.mjs +12 -7
  439. package/dist/proxy/index.mjs.map +1 -1
  440. package/dist/proxy/llms-discovery.test.d.ts +2 -0
  441. package/dist/proxy/llms-discovery.test.d.ts.map +1 -0
  442. package/dist/redirects/index.d.ts +25 -1
  443. package/dist/redirects/index.d.ts.map +1 -1
  444. package/dist/redirects/index.js +11 -8
  445. package/dist/redirects/index.mjs +4 -1
  446. package/dist/redirects/index.test.d.ts +2 -0
  447. package/dist/redirects/index.test.d.ts.map +1 -0
  448. package/dist/redirects/not-found.d.ts +14 -29
  449. package/dist/redirects/not-found.d.ts.map +1 -1
  450. package/dist/redirects/not-found.js +15 -5
  451. package/dist/redirects/not-found.js.map +1 -1
  452. package/dist/redirects/not-found.mjs +11 -1
  453. package/dist/redirects/not-found.mjs.map +1 -1
  454. package/dist/robots/index.d.ts +7 -1
  455. package/dist/robots/index.d.ts.map +1 -1
  456. package/dist/robots/index.js +27 -1
  457. package/dist/robots/index.js.map +1 -1
  458. package/dist/robots/index.mjs +4 -1
  459. package/dist/robots/index.mjs.map +1 -1
  460. package/dist/robots/index.test.d.ts +2 -0
  461. package/dist/robots/index.test.d.ts.map +1 -0
  462. package/dist/robots/next-internals.d.ts +22 -0
  463. package/dist/robots/next-internals.d.ts.map +1 -0
  464. package/dist/search/index.js +4 -4
  465. package/dist/search/index.mjs +3 -3
  466. package/dist/seo/ManagedContent.d.ts +4 -2
  467. package/dist/seo/ManagedContent.d.ts.map +1 -1
  468. package/dist/seo/ManagedFAQ.d.ts.map +1 -1
  469. package/dist/seo/ManagedInternalLinks.d.ts.map +1 -1
  470. package/dist/seo/ManagedSchema.d.ts.map +1 -1
  471. package/dist/seo/client.js +6 -6
  472. package/dist/seo/client.mjs +5 -5
  473. package/dist/seo/getManagedMetadata.d.ts.map +1 -1
  474. package/dist/seo/getManagedMetadata.test.d.ts +2 -0
  475. package/dist/seo/getManagedMetadata.test.d.ts.map +1 -0
  476. package/dist/seo/index.js +59 -49
  477. package/dist/seo/index.js.map +1 -1
  478. package/dist/seo/index.mjs +29 -19
  479. package/dist/seo/index.mjs.map +1 -1
  480. package/dist/seo/managed-schema-filter.test.d.ts +2 -0
  481. package/dist/seo/managed-schema-filter.test.d.ts.map +1 -0
  482. package/dist/seo/register-sitemap-cli-impl.d.ts +32 -0
  483. package/dist/seo/register-sitemap-cli-impl.d.ts.map +1 -1
  484. package/dist/seo/register-sitemap-cli.d.ts +7 -0
  485. package/dist/seo/register-sitemap-cli.d.ts.map +1 -1
  486. package/dist/seo/register-sitemap-cli.js +273 -56
  487. package/dist/seo/register-sitemap-cli.js.map +1 -1
  488. package/dist/seo/register-sitemap-cli.mjs +269 -52
  489. package/dist/seo/register-sitemap-cli.mjs.map +1 -1
  490. package/dist/seo/register-sitemap-request.d.ts +36 -0
  491. package/dist/seo/register-sitemap-request.d.ts.map +1 -0
  492. package/dist/seo/register-sitemap-request.test.d.ts +2 -0
  493. package/dist/seo/register-sitemap-request.test.d.ts.map +1 -0
  494. package/dist/seo/routing.d.ts +2 -0
  495. package/dist/seo/routing.d.ts.map +1 -1
  496. package/dist/seo/schema-filter.d.ts +43 -0
  497. package/dist/seo/schema-filter.d.ts.map +1 -0
  498. package/dist/seo/schema-filter.test.d.ts +2 -0
  499. package/dist/seo/schema-filter.test.d.ts.map +1 -0
  500. package/dist/seo/server-api.d.ts +15 -2
  501. package/dist/seo/server-api.d.ts.map +1 -1
  502. package/dist/seo/server.js +23 -18
  503. package/dist/seo/server.mjs +7 -2
  504. package/dist/seo/site-scope.test.d.ts +2 -0
  505. package/dist/seo/site-scope.test.d.ts.map +1 -0
  506. package/dist/seo/types.d.ts +30 -0
  507. package/dist/seo/types.d.ts.map +1 -1
  508. package/dist/seo-meta/contract.d.ts +60 -0
  509. package/dist/seo-meta/contract.d.ts.map +1 -0
  510. package/dist/seo-meta/contract.js +41 -0
  511. package/dist/seo-meta/contract.js.map +1 -0
  512. package/dist/seo-meta/contract.mjs +4 -0
  513. package/dist/seo-meta/contract.mjs.map +1 -0
  514. package/dist/seo-meta/contract.test.d.ts +2 -0
  515. package/dist/seo-meta/contract.test.d.ts.map +1 -0
  516. package/dist/server/index.js +4 -3
  517. package/dist/server/index.mjs +3 -2
  518. package/dist/server/mint-site-token.d.ts +2 -32
  519. package/dist/server/mint-site-token.d.ts.map +1 -1
  520. package/dist/{server-api-RG3ZL3DV.mjs → server-api-A2EFCTZX.mjs} +7 -3
  521. package/dist/{server-api-RG3ZL3DV.mjs.map → server-api-A2EFCTZX.mjs.map} +1 -1
  522. package/dist/{server-api-RYJQAUGO.js → server-api-IWTZ7C3O.js} +25 -21
  523. package/dist/{server-api-RYJQAUGO.js.map → server-api-IWTZ7C3O.js.map} +1 -1
  524. package/dist/shared/build-entries.d.ts +2 -0
  525. package/dist/shared/build-entries.d.ts.map +1 -1
  526. package/dist/shared/fresh-fetch.d.ts +64 -0
  527. package/dist/shared/fresh-fetch.d.ts.map +1 -0
  528. package/dist/shared/fresh-fetch.test.d.ts +2 -0
  529. package/dist/shared/fresh-fetch.test.d.ts.map +1 -0
  530. package/dist/shared/next-files.d.ts +42 -0
  531. package/dist/shared/next-files.d.ts.map +1 -0
  532. package/dist/shared/next-files.test.d.ts +2 -0
  533. package/dist/shared/next-files.test.d.ts.map +1 -0
  534. package/dist/shared/page-leave.d.ts +27 -0
  535. package/dist/shared/page-leave.d.ts.map +1 -0
  536. package/dist/shared/page-leave.test.d.ts +2 -0
  537. package/dist/shared/page-leave.test.d.ts.map +1 -0
  538. package/dist/shared/source-graph.d.ts +63 -0
  539. package/dist/shared/source-graph.d.ts.map +1 -0
  540. package/dist/shared/source-graph.test.d.ts +2 -0
  541. package/dist/shared/source-graph.test.d.ts.map +1 -0
  542. package/dist/shared/version.d.ts +1 -1
  543. package/dist/signal/SignalCore.d.ts.map +1 -1
  544. package/dist/signal/index.js +11 -11
  545. package/dist/signal/index.mjs +2 -2
  546. package/dist/sitemap/discover.d.ts.map +1 -1
  547. package/dist/sitemap/index.d.ts +25 -5
  548. package/dist/sitemap/index.d.ts.map +1 -1
  549. package/dist/sitemap/index.js +54 -51
  550. package/dist/sitemap/index.js.map +1 -1
  551. package/dist/sitemap/index.mjs +39 -36
  552. package/dist/sitemap/index.mjs.map +1 -1
  553. package/dist/sitemap/shared.d.ts +65 -0
  554. package/dist/sitemap/shared.d.ts.map +1 -1
  555. package/dist/sitemap/trailing-slash.test.d.ts +2 -0
  556. package/dist/sitemap/trailing-slash.test.d.ts.map +1 -0
  557. package/dist/sites/resolve.d.ts.map +1 -1
  558. package/dist/sites/site-param.d.ts +16 -0
  559. package/dist/sites/site-param.d.ts.map +1 -0
  560. package/dist/sync/index.js +17 -17
  561. package/dist/sync/index.mjs +4 -4
  562. package/dist/writeLLMsTxt-CQ7A4AAL.js +20 -0
  563. package/dist/writeLLMsTxt-CQ7A4AAL.js.map +1 -0
  564. package/dist/writeLLMsTxt-NX5MSPYX.mjs +11 -0
  565. package/dist/writeLLMsTxt-NX5MSPYX.mjs.map +1 -0
  566. package/package.json +25 -22
  567. package/dist/AnalyticsProvider-6PXC7UDP.js +0 -32
  568. package/dist/AnalyticsProvider-FVQIYSLY.mjs +0 -11
  569. package/dist/BlogViewTracker-S4HSRCW7.js.map +0 -1
  570. package/dist/BlogViewTracker-ZUGLBOVI.mjs.map +0 -1
  571. package/dist/ChatWidget-2TQWCXWP.js +0 -22
  572. package/dist/ChatWidget-DG52ZIE6.mjs +0 -13
  573. package/dist/EngageWidget-2VUJADIU.mjs +0 -12
  574. package/dist/EngageWidget-Z7RC2INM.js +0 -21
  575. package/dist/FormSpotlight-RHL5FWM2.mjs.map +0 -1
  576. package/dist/FormSpotlight-TED32NHP.js.map +0 -1
  577. package/dist/FormStage-DINIRFOX.mjs.map +0 -1
  578. package/dist/FormStage-PFEBKHGY.js.map +0 -1
  579. package/dist/ManagedForm-43WLCUAK.js +0 -23
  580. package/dist/ManagedForm-545YAUFC.mjs +0 -14
  581. package/dist/ManagedNewsletterForm-I3QN57HB.js.map +0 -1
  582. package/dist/ManagedNewsletterForm-ZPY5RRKX.mjs.map +0 -1
  583. package/dist/SignalCore-EEH5IM4U.mjs.map +0 -1
  584. package/dist/SignalCore-M4AXIMV4.js.map +0 -1
  585. package/dist/SitemapSync-46G7LVZS.mjs +0 -9
  586. package/dist/SitemapSync-XK4JKCS7.js +0 -18
  587. package/dist/chunk-46BMNWE6.js.map +0 -1
  588. package/dist/chunk-473WDGQZ.mjs.map +0 -1
  589. package/dist/chunk-4B4S56WJ.mjs.map +0 -1
  590. package/dist/chunk-5B4FABFK.js.map +0 -1
  591. package/dist/chunk-6CJP7BFM.js.map +0 -1
  592. package/dist/chunk-6OP5XSMM.mjs.map +0 -1
  593. package/dist/chunk-746RKQHA.js.map +0 -1
  594. package/dist/chunk-AEARU24Q.mjs.map +0 -1
  595. package/dist/chunk-AHZR4VGY.mjs.map +0 -1
  596. package/dist/chunk-AJQI3WTN.mjs.map +0 -1
  597. package/dist/chunk-B64AZC6P.js.map +0 -1
  598. package/dist/chunk-BZLIOT7Q.js.map +0 -1
  599. package/dist/chunk-C2MSD2UM.mjs.map +0 -1
  600. package/dist/chunk-CQRLKNHQ.js.map +0 -1
  601. package/dist/chunk-DQUBETXH.mjs +0 -6
  602. package/dist/chunk-EEQYKMGH.mjs.map +0 -1
  603. package/dist/chunk-GPLCPMVD.mjs.map +0 -1
  604. package/dist/chunk-GZJE23Y5.mjs.map +0 -1
  605. package/dist/chunk-H4OBGC43.mjs.map +0 -1
  606. package/dist/chunk-H7274TKR.mjs.map +0 -1
  607. package/dist/chunk-IPV2TUAT.js.map +0 -1
  608. package/dist/chunk-IYCLN3XS.mjs.map +0 -1
  609. package/dist/chunk-JEOKDUPQ.js +0 -45
  610. package/dist/chunk-JEOKDUPQ.js.map +0 -1
  611. package/dist/chunk-JNRHTZL4.js.map +0 -1
  612. package/dist/chunk-KPKQKFT4.js.map +0 -1
  613. package/dist/chunk-KSL3WA2I.js +0 -8
  614. package/dist/chunk-KY6M76JW.js.map +0 -1
  615. package/dist/chunk-LC7AM4J5.js.map +0 -1
  616. package/dist/chunk-LOS5D6B3.js +0 -72
  617. package/dist/chunk-LOS5D6B3.js.map +0 -1
  618. package/dist/chunk-NZSFOZJV.js.map +0 -1
  619. package/dist/chunk-OZ3FU4BT.js.map +0 -1
  620. package/dist/chunk-QJU6HBSK.mjs +0 -39
  621. package/dist/chunk-QJU6HBSK.mjs.map +0 -1
  622. package/dist/chunk-R3KTBKSW.js.map +0 -1
  623. package/dist/chunk-RIYAMYLV.mjs.map +0 -1
  624. package/dist/chunk-RU54J2PY.mjs.map +0 -1
  625. package/dist/chunk-TP7H6BSK.mjs.map +0 -1
  626. package/dist/chunk-UJ6CHZAI.mjs.map +0 -1
  627. package/dist/chunk-UU47DGHE.js.map +0 -1
  628. package/dist/chunk-X5TCH7VZ.js.map +0 -1
  629. package/dist/chunk-XIJ4F6IE.mjs +0 -63
  630. package/dist/chunk-XIJ4F6IE.mjs.map +0 -1
  631. package/dist/discover-BEJRYNFF.mjs +0 -4
  632. package/dist/discover-WVDYDUJX.js +0 -21
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/llms/discovery-headers.ts"],"names":[],"mappings":";;;AAKA,IAAM,aAAA,GAAgB,wBAAA;AAGtB,SAAS,aAAa,GAAA,EAA4B;AAChD,EAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,GAAG,GAAG,OAAO,IAAA;AAClC,EAAA,OAAO,GAAA;AACT;AA2BO,SAAS,wBAAwB,OAAA,EAA4D;AAClG,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC9C,EAAA,MAAM,IAAA,GAAO,QAAQ,QAAA,IAAY,WAAA;AACjC,EAAA,MAAM,eAAe,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,GAAI,IAAA,GAAO,IAAI,IAAI,CAAA,CAAA;AAC3D,EAAA,MAAM,OAAA,GAAU,CAAA,EAAG,IAAI,CAAA,EAAG,YAAY,CAAA,CAAA;AACtC,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,oBAAA,KAAyB,KAAA,GAAQ,EAAA,GAAK,aAAA;AAE3D,EAAA,MAAM,WAAqB,CAAC,CAAA,CAAA,EAAI,OAAO,CAAA,oBAAA,EAAuB,IAAI,CAAA,CAAE,CAAA;AAEpE,EAAA,KAAA,MAAW,GAAA,IAAO,OAAA,CAAQ,kBAAA,IAAsB,EAAC,EAAG;AAClD,IAAA,MAAM,EAAA,GAAK,YAAA,CAAa,GAAA,CAAI,QAAQ,CAAA;AACpC,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,GAAA,CAAI,IAAA,EAAM;AACtB,IAAA,QAAA,CAAS,IAAA,CAAK,IAAI,GAAA,CAAI,IAAI,iCAAiC,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAAA,EACzE;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA,CAAS,IAAA,CAAK,IAAI;AAAA,GAC1B;AACF;AA0BO,SAAS,uBAAuB,GAAA,EAAgC;AACrE,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,MAAA,CAAO,WAAA,EAAY;AACtC,EAAA,IAAI,MAAA,KAAW,KAAA,IAAS,MAAA,KAAW,MAAA,EAAQ,OAAO,KAAA;AAClD,EAAA,IAAI,GAAA,CAAI,KAAK,OAAO,KAAA;AACpB,EAAA,IAAI,GAAA,CAAI,aAAa,MAAA,IAAU,GAAA,CAAI,SAAS,UAAA,CAAW,OAAO,GAAG,OAAO,KAAA;AACxE,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,CAAS,KAAA,CAAM,IAAI,QAAA,CAAS,WAAA,CAAY,GAAG,CAAA,GAAI,CAAC,CAAA;AACjE,EAAA,IAAI,IAAA,CAAK,SAAS,GAAG,CAAA,IAAK,CAAC,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA,EAAG,OAAO,KAAA;AAC1D,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAK;AAChC,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,OAAO,4CAAA,CAA6C,KAAK,MAAM,CAAA;AACjE","file":"chunk-WS7MH3GD.js","sourcesContent":["/**\n * Opt-in HTTP headers linking HTML documents to /llms.txt for crawler discovery.\n * `rel=\"describedby\"` is IANA-registered (RFC 8288).\n */\n\nconst TYPE_MARKDOWN = '; type=\"text/markdown\"'\n\n/** Safe subset for `hreflang` (BCP 47 tags, no quotes/semicolons). */\nfunction safeHreflang(tag: string): string | null {\n if (!/^[\\w-]+$/.test(tag)) return null\n return tag\n}\n\nexport interface LlmsLanguageAlternate {\n /** BCP 47 tag, e.g. `fr` or `en-US` */\n hreflang: string\n /** Absolute URL to that locale’s llms.txt (or equivalent) */\n href: string\n}\n\nexport interface AiDiscoveryHeadersOptions {\n /** Canonical site origin, e.g. https://example.com (no trailing slash) */\n siteUrl: string\n /** Path to llms.txt (default `/llms.txt`) */\n llmsPath?: string\n /**\n * When true (default), append `type=\"text/markdown\"` on Link targets so crawlers\n * can treat the resource as markdown text.\n */\n includeTypeParameter?: boolean\n /** Optional `rel=\"alternate\"` links for multilingual llms.txt (or per-locale equivalents). */\n languageAlternates?: LlmsLanguageAlternate[]\n}\n\n/**\n * Returns header map suitable for Next.js `headers()` merge.\n * Prefer this over visible footer links for machine-facing discovery.\n */\nexport function buildAiDiscoveryHeaders(options: AiDiscoveryHeadersOptions): Record<string, string> {\n const base = options.siteUrl.replace(/\\/$/, '')\n const path = options.llmsPath || '/llms.txt'\n const resolvedPath = path.startsWith('/') ? path : `/${path}`\n const llmsUrl = `${base}${resolvedPath}`\n const type = options.includeTypeParameter === false ? '' : TYPE_MARKDOWN\n\n const segments: string[] = [`<${llmsUrl}>; rel=\"describedby\"${type}`]\n\n for (const alt of options.languageAlternates ?? []) {\n const hl = safeHreflang(alt.hreflang)\n if (!hl || !alt.href) continue\n segments.push(`<${alt.href}>; rel=\"alternate\"; hreflang=\"${hl}\"${type}`)\n }\n\n return {\n Link: segments.join(', '),\n }\n}\n\nexport interface DiscoveryRequest {\n method: string\n pathname: string\n /** The Accept header, or null when the request sent none. */\n accept: string | null\n /** Next's `RSC` request header: a client-side navigation payload, not a page. */\n rsc?: string | null\n}\n\n/**\n * Does this request get the `Link: rel=\"describedby\"` discovery header?\n *\n * Any request that could be for an HTML page. It used to take only requests\n * whose Accept header named text/html or `*` + `/*`, which skipped every\n * request that sends no Accept header at all: curl, link checkers, and a good\n * share of crawlers and AI fetchers, which are exactly who the header is for.\n * A missing Accept header means \"anything\", so it counts (RFC 9110 §12.5.1).\n *\n * Skipped: methods other than GET and HEAD; an Accept header that names\n * types but no HTML (`application/json`, `image/*`); file-like paths\n * (`/llms.txt`, `/sitemap.xml`, `/feed.xml`: a `.` in the last segment,\n * except `.html`); `/api/` routes; and Next's RSC navigation requests.\n * Static assets never reach the proxy (its matcher excludes them).\n */\nexport function wantsLlmsDiscoveryLink(req: DiscoveryRequest): boolean {\n const method = req.method.toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') return false\n if (req.rsc) return false\n if (req.pathname === '/api' || req.pathname.startsWith('/api/')) return false\n const last = req.pathname.slice(req.pathname.lastIndexOf('/') + 1)\n if (last.includes('.') && !/\\.html?$/i.test(last)) return false\n const accept = req.accept?.trim()\n if (!accept) return true\n return /text\\/html|application\\/xhtml\\+xml|\\*\\/\\*/i.test(accept)\n}\n"]}
@@ -228,7 +228,7 @@ function normalizeOptions(options) {
228
228
  }
229
229
  return [];
230
230
  }
231
- function FormField({ field, value, error, onChange, classPrefix = "sk-form", showValid, controls }) {
231
+ function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix = "sk-form", showValid, controls }) {
232
232
  const interactive = typeof onChange === "function";
233
233
  const emit = (v) => onChange?.(v);
234
234
  const bind = (v) => interactive ? { value: v, onChange: (e) => emit(e.target.value) } : { defaultValue: v || void 0 };
@@ -281,7 +281,15 @@ function FormField({ field, value, error, onChange, classPrefix = "sk-form", sho
281
281
  }
282
282
  const hideLabel = !!field.hide_label;
283
283
  const effectivePlaceholder = hideLabel ? field.label : field.placeholder;
284
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${classPrefix}__field ${classPrefix}__field--${field.field_type}`, children: [
284
+ const focusProps = interactive && (onFocus || onBlur) ? {
285
+ onFocus: (e) => {
286
+ if (!e.currentTarget.contains(e.relatedTarget)) onFocus?.();
287
+ },
288
+ onBlur: (e) => {
289
+ if (!e.currentTarget.contains(e.relatedTarget)) onBlur?.();
290
+ }
291
+ } : {};
292
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${classPrefix}__field ${classPrefix}__field--${field.field_type}`, ...focusProps, children: [
285
293
  /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: `${classPrefix}__label`, style: { ...labelStyle, ...hideLabel ? { position: "absolute", width: 1, height: 1, padding: 0, margin: -1, overflow: "hidden", clip: "rect(0,0,0,0)", whiteSpace: "nowrap", border: 0 } : {} }, children: [
286
294
  field.label,
287
295
  field.is_required && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--sk-error, #dc2626)" }, children: " *" })
@@ -529,5 +537,5 @@ function FormField({ field, value, error, onChange, classPrefix = "sk-form", sho
529
537
  exports.DelightStyles = DelightStyles;
530
538
  exports.FormField = FormField;
531
539
  exports.FormMomentum = FormMomentum;
532
- //# sourceMappingURL=chunk-IPV2TUAT.js.map
533
- //# sourceMappingURL=chunk-IPV2TUAT.js.map
540
+ //# sourceMappingURL=chunk-XA2GJFVM.js.map
541
+ //# sourceMappingURL=chunk-XA2GJFVM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/forms/delight.tsx","../src/forms/FormField.tsx"],"names":["jsx","jsxs"],"mappings":"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","file":"chunk-XA2GJFVM.js","sourcesContent":["'use client'\n\n/**\n * Form delight primitives — the interaction layer that makes filling a form\n * feel like progress instead of paperwork. Forms capture the lead; this is\n * conversion surface, not decoration.\n *\n * The bar: AAA-game onboarding. Nothing on screen is inert — the focused\n * field is lit, completing a field LOCKS IN, progress reads like a meter you\n * want to fill, and when the last requirement clears the submit button wakes\n * up. The arc: aura -> lock-in tick -> bar surges -> READY -> press start ->\n * celebration.\n *\n * - FieldValidTick: a check that draws itself the moment a field becomes\n * valid (touched + non-empty + no error), with a ripple ring. The field\n * wrap also flashes a one-shot lock-in ring via [data-sk-valid].\n * - FormMomentum: a fields-completed meter (not steps) — endowed progress;\n * people finish bars they've started. Live sheen, advance flash, leading-\n * edge spark, \"N of M\" label that flips to READY and charges the bar.\n * - [data-sk-ready] (set by FormClient when every required field validates\n * on the final step) wakes the submit button: pop, then breathing glow.\n *\n * Same construction rules as FormCelebration: zero deps, one deduped style\n * tag, data-sk-part on everything, --sk-primary theming, reduced-motion\n * collapses animation to instant states.\n *\n * Contrast guarantee: forms routinely live in sections painted with the\n * brand color itself, where pure --sk-primary chrome is invisible (found\n * live: fill rgb(173,29,37) on section rgb(173,29,37)). Everything here\n * mixes toward currentColor — the section's text color must contrast with\n * the section background, so the mix guarantees the chrome does too.\n */\n\nimport React from 'react'\n\nconst STYLE_ID = 'sk-delight-css'\n\nconst CSS = `\n/* Every frame must carry the centering translateY: the animation fills both\n directions, so a keyframe transform of scale() alone REPLACES the rule's\n translateY(-50%) and drops the tick half its height below center. */\n@keyframes sk-tick-in {\n 0% { transform: translateY(-50%) scale(.3); opacity: 0 }\n 70% { transform: translateY(-50%) scale(1.15) }\n 100% { transform: translateY(-50%) scale(1); opacity: 1 }\n}\n@keyframes sk-tick-draw { to { stroke-dashoffset: 0 } }\n@keyframes sk-tick-ring { 0% { transform: scale(.5); opacity: .7 } 100% { transform: scale(2.2); opacity: 0 } }\n@keyframes sk-lock-in { 0% { opacity: .85; transform: scale(.985) } 100% { opacity: 0; transform: scale(1.012) } }\n@keyframes sk-momentum-sheen { 0% { transform: translateX(-120%) } 100% { transform: translateX(360%) } }\n@keyframes sk-momentum-flash { 0% { opacity: .55 } 100% { opacity: 0 } }\n@keyframes sk-spark-pulse {\n 0%, 100% { box-shadow: 0 0 4px 1px color-mix(in srgb, var(--sk-primary, #2563eb) 60%, currentColor) }\n 50% { box-shadow: 0 0 11px 2px color-mix(in srgb, var(--sk-primary, #2563eb) 60%, currentColor) }\n}\n@keyframes sk-fill-charge {\n 0%, 100% { box-shadow: 0 0 5px 0 color-mix(in srgb, var(--sk-primary, #2563eb) 55%, currentColor) }\n 50% { box-shadow: 0 0 13px 2px color-mix(in srgb, var(--sk-primary, #2563eb) 55%, currentColor) }\n}\n@keyframes sk-label-pop { 0% { transform: scale(.8) } 60% { transform: scale(1.15) } 100% { transform: scale(1) } }\n@keyframes sk-btn-wake { 0% { transform: scale(1) } 40% { transform: scale(1.04) } 100% { transform: scale(1) } }\n@keyframes sk-btn-breathe {\n 0%, 100% { filter: drop-shadow(0 0 0 transparent) }\n 50% { filter: drop-shadow(0 0 9px color-mix(in srgb, var(--sk-primary, #2563eb) 60%, currentColor)) }\n}\n@keyframes sk-submit-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .6 } }\n\n/* ---- Field: aura, lift, lock-in, tick ---- */\n/* Flex, not the default inline formatting context: an <input> is inline-block,\n so the wrapper would be a few px taller than the input (baseline descender\n gap) and the absolutely-centered tick would sit visibly low. */\n[data-sk-part=\"field-input-wrap\"] { display: flex; align-items: center; transition: transform .18s ease; }\n[data-sk-part=\"field-input-wrap\"]:focus-within { transform: translateY(-2px); }\n/* Focus aura — the active field is the lit one. Glow-only pseudo (its own\n box is transparent), so it never occludes the input. */\n[data-sk-part=\"field-input-wrap\"]::before {\n content: ''; position: absolute; inset: -3px;\n border-radius: calc(var(--sk-input-radius, 6px) + 3px);\n box-shadow: 0 0 16px color-mix(in srgb, var(--sk-primary, #2563eb) 55%, currentColor);\n opacity: 0; transition: opacity .25s ease; pointer-events: none;\n}\n[data-sk-part=\"field-input-wrap\"]:focus-within::before { opacity: .5; }\n/* One-shot lock-in ring when the field validates ([data-sk-valid] appears). */\n[data-sk-part=\"field-input-wrap\"]::after {\n content: ''; position: absolute; inset: 0;\n border-radius: var(--sk-input-radius, 6px);\n border: 2px solid color-mix(in srgb, var(--sk-primary, #2563eb) 72%, currentColor);\n opacity: 0; pointer-events: none;\n}\n[data-sk-part=\"field-input-wrap\"][data-sk-valid=\"true\"]::after { animation: sk-lock-in .55s ease-out both; }\n.sk-tick {\n position: absolute; right: 10px; top: 50%; transform: translateY(-50%);\n width: 20px; height: 20px; border-radius: 50%;\n background: color-mix(in srgb, var(--sk-primary, #2563eb) 72%, currentColor);\n display: flex; align-items: center; justify-content: center;\n animation: sk-tick-in .28s cubic-bezier(.22,1.4,.36,1) both;\n pointer-events: none;\n}\n.sk-tick::after {\n content: ''; position: absolute; inset: 0; border-radius: 50%;\n border: 2px solid color-mix(in srgb, var(--sk-primary, #2563eb) 72%, currentColor);\n animation: sk-tick-ring .55s ease-out .06s both;\n}\n.sk-tick path { stroke-dasharray: 14; stroke-dashoffset: 14; animation: sk-tick-draw .22s ease-out .12s forwards; }\n\n/* ---- Momentum meter ---- */\n.sk-momentum { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; }\n.sk-momentum-track {\n flex: 1; position: relative; height: 8px; border-radius: 999px;\n background: color-mix(in srgb, currentColor 14%, transparent);\n}\n.sk-momentum-fill {\n position: relative; overflow: hidden;\n height: 100%; border-radius: 999px;\n background: color-mix(in srgb, var(--sk-primary, #2563eb) 72%, currentColor);\n transition: width .45s cubic-bezier(.22,1,.36,1);\n}\n/* Continuous sheen sweep — the bar reads as live, not static chrome. */\n.sk-momentum-fill::after {\n content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 45%;\n background: linear-gradient(105deg, transparent, rgba(255,255,255,.4), transparent);\n animation: sk-momentum-sheen 2.6s ease-in-out infinite;\n}\n/* One-shot white flash on each advance (keyed remount restarts it). */\n.sk-momentum-flash {\n position: absolute; inset: 0; border-radius: 999px;\n background: #fff; opacity: 0;\n animation: sk-momentum-flash .5s ease-out;\n}\n/* Leading-edge spark rides the fill tip. */\n.sk-momentum-spark {\n position: absolute; top: 50%; width: 10px; height: 10px; margin-top: -5px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--sk-primary, #2563eb) 55%, currentColor);\n animation: sk-spark-pulse 1.6s ease-in-out infinite;\n transition: left .45s cubic-bezier(.22,1,.36,1);\n pointer-events: none;\n}\n.sk-momentum[data-sk-momentum=\"0\"] .sk-momentum-spark { opacity: 0; }\n.sk-momentum-label {\n font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;\n opacity: .75; font-variant-numeric: tabular-nums; white-space: nowrap;\n}\n/* Charged state: every requirement met — bar glows, sheen accelerates,\n label flips to READY in brand. */\n.sk-momentum[data-sk-complete=\"true\"] .sk-momentum-fill { animation: sk-fill-charge 1.8s ease-in-out infinite; }\n.sk-momentum[data-sk-complete=\"true\"] .sk-momentum-fill::after { animation-duration: 1.4s; }\n.sk-momentum[data-sk-complete=\"true\"] .sk-momentum-label {\n opacity: 1;\n color: color-mix(in srgb, var(--sk-primary, #2563eb) 60%, currentColor);\n animation: sk-label-pop .4s cubic-bezier(.22,1.4,.36,1);\n}\n\n/* ---- DatePicker: the calendar morphs out of its tile and morphs back in\n on selection (container-transform), and the picked date stamps in. ---- */\n@keyframes sk-cal-out { 0% { opacity: 0; transform: scale(.92) translateY(-8px) } 100% { opacity: 1; transform: scale(1) translateY(0) } }\n@keyframes sk-cal-in { 0% { opacity: 1; transform: scale(1) translateY(0) } 100% { opacity: 0; transform: scale(.94) translateY(-6px) } }\n@keyframes sk-cal-stamp { 0% { transform: scale(.9) } 60% { transform: scale(1.06) } 100% { transform: scale(1) } }\n.sk-datepicker__pop { transform-origin: top center; animation: sk-cal-out .28s cubic-bezier(.22,1.4,.36,1) both; }\n.sk-datepicker__pop[data-sk-closing=\"true\"] { animation: sk-cal-in .18s ease-in both; }\n.sk-datepicker__value--stamp { display: inline-block; animation: sk-cal-stamp .3s cubic-bezier(.22,1.4,.36,1); }\n\n/* ---- Submit: wake on ready, pulse while submitting ---- */\n.sk-form__btn--submit { transition: transform .12s ease; }\n.sk-form__btn--submit:active { transform: scale(.97); }\n[data-sk-ready=\"true\"] .sk-form__btn--submit {\n animation: sk-btn-wake .5s cubic-bezier(.22,1.4,.36,1),\n sk-btn-breathe 2.4s ease-in-out .5s infinite;\n}\n[data-sk-state=\"submitting\"] .sk-form__btn--submit { animation: sk-submit-pulse 1.1s ease-in-out infinite; }\n[data-sk-state=\"submitting\"] .sk-momentum-fill::after { animation-duration: .8s; }\n\n@media (prefers-reduced-motion: reduce) {\n .sk-datepicker__pop { animation: none }\n .sk-datepicker__pop[data-sk-closing=\"true\"] { animation: none }\n .sk-datepicker__value--stamp { animation: none }\n .sk-tick { animation: none }\n .sk-tick::after { animation: none; opacity: 0 }\n .sk-tick path { animation: none; stroke-dashoffset: 0 }\n [data-sk-part=\"field-input-wrap\"] { transition: none }\n [data-sk-part=\"field-input-wrap\"]:focus-within { transform: none }\n [data-sk-part=\"field-input-wrap\"]::before { transition: none }\n [data-sk-part=\"field-input-wrap\"][data-sk-valid=\"true\"]::after { animation: none }\n .sk-momentum-fill { transition: none }\n .sk-momentum-fill::after { animation: none; opacity: 0 }\n .sk-momentum-flash { animation: none }\n .sk-momentum-spark { animation: none; transition: none }\n .sk-momentum[data-sk-complete=\"true\"] .sk-momentum-fill { animation: none }\n .sk-momentum[data-sk-complete=\"true\"] .sk-momentum-label { animation: none }\n .sk-form__btn--submit { transition: none }\n [data-sk-ready=\"true\"] .sk-form__btn--submit { animation: none }\n [data-sk-state=\"submitting\"] .sk-form__btn--submit { animation: none }\n}\n`\n\nexport function DelightStyles() {\n return <style id={STYLE_ID} dangerouslySetInnerHTML={{ __html: CSS }} />\n}\n\n/** Draw-in check shown inside a field wrapper once the value validates. */\nexport function FieldValidTick() {\n return (\n <span className=\"sk-tick\" data-sk-part=\"field-valid-tick\" aria-hidden=\"true\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M3.5 8.5l3 3 6-6.5\"\n stroke=\"var(--sk-form-success-check, #fff)\"\n strokeWidth=\"2.4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n )\n}\n\nexport interface FormMomentumProps {\n /** Completed required+visible fields. */\n done: number\n /** Total required+visible fields. */\n total: number\n}\n\n/**\n * Fields-completed meter. Hidden when there is nothing to measure (0-1\n * required fields) — a bar that fills in one keystroke reads as noise.\n */\nexport function FormMomentum({ done, total }: FormMomentumProps) {\n if (total < 2) return null\n const pct = Math.round((Math.min(done, total) / total) * 100)\n const ready = done >= total\n return (\n <div\n className=\"sk-momentum\"\n data-sk-part=\"momentum\"\n data-sk-momentum={pct}\n data-sk-complete={ready ? 'true' : undefined}\n role=\"progressbar\"\n aria-valuenow={done}\n aria-valuemin={0}\n aria-valuemax={total}\n aria-label=\"Form progress\"\n >\n <div className=\"sk-momentum-track\" data-sk-part=\"momentum-track\">\n <div className=\"sk-momentum-fill\" data-sk-part=\"momentum-fill\" style={{ width: `${pct}%` }}>\n {/* keyed by pct: remounts on every advance, replaying the flash */}\n <span key={pct} className=\"sk-momentum-flash\" data-sk-part=\"momentum-flash\" aria-hidden=\"true\" />\n </div>\n <span\n className=\"sk-momentum-spark\"\n data-sk-part=\"momentum-spark\"\n style={{ left: `calc(${pct}% - 5px)` }}\n aria-hidden=\"true\"\n />\n </div>\n <span className=\"sk-momentum-label\" data-sk-part=\"momentum-label\" aria-hidden=\"true\">\n {ready ? 'Ready' : `${done} of ${total}`}\n </span>\n </div>\n )\n}\n","/**\n * @sonordev/site-kit/forms - Form Field Component\n *\n * Renders individual form fields based on type.\n *\n * Styling Options:\n * 1. Use CSS variables to customize the default styles\n * 2. Use the `className` prop on ManagedForm for scoped styles\n * 3. Use the custom render function for complete control\n *\n * CSS Variables (set these in your stylesheet or import brand.css):\n * --sk-input-bg: #ffffff\n * --sk-input-text: #111827 (pairs with --sk-input-bg; falls back to\n * --sk-text-primary, so a themed site is covered)\n * --sk-input-border: #d1d5db\n * --sk-input-border-w: 1px\n * --sk-input-border-focus: #2563eb\n * --sk-input-border-error: #dc2626\n * --sk-input-radius: 0.375rem\n * --sk-input-padding: 10px 12px\n * --sk-label-color: inherit\n * --sk-label-weight: 500\n * --sk-error: #dc2626\n * --sk-text-tertiary: #6b7280\n * --sk-font-size: 16px\n */\n\nimport React from 'react'\nimport { FieldValidTick } from './delight'\nimport type { FormField as FormFieldType } from './types'\n\ninterface FormFieldProps {\n /** Render the valid-state tick (touched + validated). Text-like fields only. */\n showValid?: boolean\n field: FormFieldType\n value?: unknown\n error?: string\n /**\n * Omit to render STATIC mode: uncontrolled native controls with\n * `defaultValue`, no React state, no event handlers. That is what lets a\n * Server Component render a complete, submittable form with zero client\n * JavaScript (see StaticForm.tsx). Pass a handler for the usual controlled\n * behaviour once the enhancement hydrates.\n *\n * The two modes MUST emit the same element/class structure — the\n * enhancement replaces the shell in place, and a mismatch shows up as a\n * visible jump. field-parity.test.tsx pins this.\n */\n onChange?: (value: unknown) => void\n /**\n * Focus entered / left this field, for form analytics (`field_interactions`).\n * Interactive mode only; static mode renders no handlers of any kind.\n */\n onFocus?: () => void\n onBlur?: () => void\n /** Optional class name prefix for custom styling */\n classPrefix?: string\n /**\n * Client-only controls, injected by FormClient. DatePicker and FileField\n * carry hooks; importing them here would pull them into this module's chunk\n * and the build would stamp the whole thing `'use client'`, so a Server\n * Component rendering one text input would ship the date picker too.\n * Injection keeps this file hook-free and therefore server-renderable.\n * Absent = static mode falls back to the native control.\n */\n controls?: {\n Date?: React.ComponentType<any>\n File?: React.ComponentType<any>\n }\n}\n\n/**\n * Normalize options from various DB formats into [{value, label}]\n * Handles:\n * - [{value, label}] → pass through\n * - {choices: [\"A\", \"B\"]} → [{value: \"A\", label: \"A\"}, ...]\n * - [\"A\", \"B\"] → [{value: \"A\", label: \"A\"}, ...]\n */\nfunction normalizeOptions(options: unknown): { value: string; label: string }[] {\n if (!options) return []\n if (Array.isArray(options)) {\n return options.map((opt) => {\n if (typeof opt === 'string') return { value: opt, label: opt }\n if (typeof opt === 'object' && opt !== null && 'value' in opt && 'label' in opt) return opt as { value: string; label: string }\n if (typeof opt === 'object' && opt !== null && 'label' in opt) return { value: (opt as any).label, label: (opt as any).label }\n return { value: String(opt), label: String(opt) }\n })\n }\n if (typeof options === 'object' && options !== null) {\n const obj = options as Record<string, unknown>\n if (Array.isArray(obj.choices)) return normalizeOptions(obj.choices)\n if (Array.isArray(obj.items)) return normalizeOptions(obj.items)\n if (Array.isArray(obj.options)) return normalizeOptions(obj.options)\n }\n return []\n}\n\nexport function FormField({ field, value, error, onChange, onFocus, onBlur, classPrefix = 'sk-form' , showValid, controls }: FormFieldProps) {\n // Static mode: no handler, so render native uncontrolled controls. The\n // browser owns the value and a native form POST still carries it.\n const interactive = typeof onChange === 'function'\n const emit = (v: unknown) => onChange?.(v)\n /** value/onChange when interactive, defaultValue when static. */\n const bind = (v: string) =>\n interactive\n ? { value: v, onChange: (e: any) => emit(e.target.value) }\n : { defaultValue: v || undefined }\n // Stable id from field (no hooks - avoids \"Rendered fewer hooks than expected\" with early returns)\n const inputId = `sk-${(field as { id?: string }).id || field.slug}`\n // Normalize options once\n const options = normalizeOptions(field.options)\n // Use CSS variables with inline style fallbacks\n const baseInputStyle: React.CSSProperties = {\n width: '100%',\n padding: 'var(--sk-input-padding, 10px 12px)',\n fontSize: 'var(--sk-font-size, 16px)',\n border: error\n ? 'var(--sk-input-border-w, 1px) solid var(--sk-input-border-error, #dc2626)'\n : 'var(--sk-input-border-w, 1px) solid var(--sk-input-border, #d1d5db)',\n borderRadius: 'var(--sk-input-radius, 6px)',\n backgroundColor: 'var(--sk-input-bg, #ffffff)',\n // fg and bg MUST come from the same source. Inlining bg but letting color\n // cascade from the section produced cream-on-white on brand-colored panels\n // (found live). Default pairs with the white bg; theme both via vars.\n //\n // The fallback chain matters, and it is the reason this was broken on\n // upforgelabs.com: a dark site that set --sk-input-bg and --sk-text-primary\n // but never heard of --sk-input-text landed on #111827 over its own dark\n // field, 1.03:1, an input you cannot read your own typing in. Falling\n // through --sk-text-primary first means theming the page's text is enough.\n color: 'var(--sk-input-text, var(--sk-text-primary, #111827))',\n outline: 'none',\n fontFamily: 'inherit',\n }\n \n const labelStyle: React.CSSProperties = {\n display: 'block',\n marginBottom: 6,\n fontWeight: 'var(--sk-label-weight, 500)' as any,\n color: 'var(--sk-label-color, inherit)',\n }\n \n const errorStyle: React.CSSProperties = {\n color: 'var(--sk-error, #dc2626)',\n fontSize: 14,\n marginTop: 4,\n }\n \n const helpStyle: React.CSSProperties = {\n color: 'var(--sk-text-tertiary, #6b7280)',\n fontSize: 14,\n marginTop: 4,\n }\n \n // Heading / Section Header (display only)\n if (field.field_type === 'heading' || field.field_type === 'section_header') {\n return <h3 className={`${classPrefix}__heading`} style={{ margin: '16px 0 8px', fontWeight: 600, fontSize: 18 }}>{field.label}</h3>\n }\n \n // Paragraph (display only)\n if (field.field_type === 'paragraph') {\n return <p className={`${classPrefix}__paragraph`} style={{ color: 'var(--sk-text-tertiary, #6b7280)', margin: '8px 0' }}>{field.help_text || field.label}</p>\n }\n \n // Hidden field\n if (field.field_type === 'hidden') {\n return interactive\n ? <input type=\"hidden\" name={field.slug} value={String(value || '')} readOnly />\n : <input type=\"hidden\" name={field.slug} defaultValue={String(value || '')} />\n }\n\n const hideLabel = !!(field as { hide_label?: boolean }).hide_label\n const effectivePlaceholder = hideLabel ? field.label : field.placeholder\n\n // Focus reporting sits on the wrapper, so every control inside (radios, the\n // date picker, the file button) reports as this one field. Moves between\n // controls inside the same field are not a new visit to it.\n const focusProps = interactive && (onFocus || onBlur)\n ? {\n onFocus: (e: React.FocusEvent<HTMLDivElement>) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) onFocus?.()\n },\n onBlur: (e: React.FocusEvent<HTMLDivElement>) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) onBlur?.()\n },\n }\n : {}\n\n return (\n <div className={`${classPrefix}__field ${classPrefix}__field--${field.field_type}`} {...focusProps}>\n <label htmlFor={inputId} className={`${classPrefix}__label`} style={{ ...labelStyle, ...(hideLabel ? { position: 'absolute', width: 1, height: 1, padding: 0, margin: -1, overflow: 'hidden', clip: 'rect(0,0,0,0)', whiteSpace: 'nowrap', border: 0 } : {}) }}>\n {field.label}\n {field.is_required && <span style={{ color: 'var(--sk-error, #dc2626)' }}> *</span>}\n </label>\n \n {/* Text, Email, Phone/Tel, Number — relative wrapper hosts the valid tick */}\n {['text', 'email', 'phone', 'tel', 'number'].includes(field.field_type) && (\n <div style={{ position: 'relative' }} data-sk-part=\"field-input-wrap\" data-sk-valid={showValid ? 'true' : undefined}>\n <input\n id={inputId}\n className={`${classPrefix}__input`}\n type={field.field_type === 'phone' || field.field_type === 'tel' ? 'tel' : field.field_type}\n name={field.slug}\n {...bind(String(value || ''))}\n placeholder={effectivePlaceholder}\n required={field.is_required}\n style={baseInputStyle}\n />\n {showValid && <FieldValidTick />}\n </div>\n )}\n \n {/* Textarea */}\n {field.field_type === 'textarea' && (\n <textarea\n id={inputId}\n className={`${classPrefix}__textarea`}\n name={field.slug}\n {...bind(String(value || ''))}\n placeholder={effectivePlaceholder}\n required={field.is_required}\n rows={4}\n style={{ ...baseInputStyle, resize: 'vertical' }}\n />\n )}\n \n {/* Select */}\n {field.field_type === 'select' && (\n <select\n id={inputId}\n className={`${classPrefix}__select`}\n name={field.slug}\n {...bind(String(value || ''))}\n required={field.is_required}\n style={baseInputStyle}\n >\n <option value=\"\">{effectivePlaceholder || 'Select an option'}</option>\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )}\n \n {/* Multi-select */}\n {field.field_type === 'multi-select' && (\n <select\n id={inputId}\n className={`${classPrefix}__select ${classPrefix}__select--multi`}\n name={field.slug}\n {...(interactive\n ? {\n value: Array.isArray(value) ? (value as string[]) : [],\n onChange: (e: any) =>\n emit(Array.from(e.target.selectedOptions, (opt: any) => opt.value)),\n }\n : { defaultValue: Array.isArray(value) ? (value as string[]) : [] })}\n required={field.is_required}\n multiple\n style={{ ...baseInputStyle, height: 120 }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )}\n \n {/* Radio */}\n {field.field_type === 'radio' && (\n <div className={`${classPrefix}__radio-group`} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>\n {options.map((option) => (\n <label key={option.value} className={`${classPrefix}__radio-option`} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <input\n type=\"radio\"\n name={field.slug}\n value={option.value}\n {...(interactive\n ? { checked: value === option.value, onChange: () => emit(option.value) }\n : { defaultChecked: value === option.value })}\n required={field.is_required}\n />\n {option.label}\n </label>\n ))}\n </div>\n )}\n \n {/* Checkbox (single) */}\n {field.field_type === 'checkbox' && options.length === 0 && (\n <label className={`${classPrefix}__checkbox`} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <input\n type=\"checkbox\"\n name={field.slug}\n {...(interactive\n ? { checked: !!value, onChange: (e: any) => emit(e.target.checked) }\n : { defaultChecked: !!value })}\n required={field.is_required}\n />\n {field.help_text || field.label}\n </label>\n )}\n \n {/* Checkbox (multiple options) */}\n {field.field_type === 'checkbox' && options.length > 0 && (\n <div className={`${classPrefix}__checkbox-group`} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>\n {options.map((option) => {\n const selectedValues = Array.isArray(value) ? value : []\n const isChecked = selectedValues.includes(option.value)\n \n return (\n <label key={option.value} className={`${classPrefix}__checkbox-option`} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <input\n type=\"checkbox\"\n name={field.slug}\n value={option.value}\n {...(interactive\n ? {\n checked: isChecked,\n onChange: () =>\n emit(\n isChecked\n ? selectedValues.filter((v) => v !== option.value)\n : [...selectedValues, option.value],\n ),\n }\n : { defaultChecked: isChecked })}\n />\n {option.label}\n </label>\n )\n })}\n </div>\n )}\n \n {/* Date - Custom calendar picker */}\n {field.field_type === 'date' && (\n interactive && controls?.Date ? (\n <controls.Date\n id={inputId}\n name={field.slug}\n value={String(value || '')}\n onChange={emit}\n required={field.is_required}\n placeholder={field.placeholder || 'Select a date'}\n className={`${classPrefix}__input ${classPrefix}__input--date`}\n />\n ) : (\n // Static: the browser's own date control. Same name and class, so\n // the swap to DatePicker on enhancement is in place.\n <input\n id={inputId}\n className={`${classPrefix}__input ${classPrefix}__input--date`}\n type=\"date\"\n name={field.slug}\n defaultValue={String(value || '') || undefined}\n required={field.is_required}\n style={baseInputStyle}\n />\n )\n )}\n \n {/* Time */}\n {field.field_type === 'time' && (\n <input\n id={inputId}\n className={`${classPrefix}__input ${classPrefix}__input--time`}\n type=\"time\"\n name={field.slug}\n {...bind(String(value || ''))}\n required={field.is_required}\n style={baseInputStyle}\n />\n )}\n \n {/* DateTime */}\n {field.field_type === 'datetime' && (\n <input\n id={inputId}\n className={`${classPrefix}__input ${classPrefix}__input--datetime`}\n type=\"datetime-local\"\n name={field.slug}\n {...bind(String(value || ''))}\n required={field.is_required}\n style={baseInputStyle}\n />\n )}\n \n {/* File */}\n {field.field_type === 'file' && (\n interactive && controls?.File ? (\n <controls.File\n field={field}\n inputId={inputId}\n classPrefix={classPrefix}\n baseInputStyle={baseInputStyle}\n onChange={emit}\n />\n ) : (\n // Static: a real file input so the field is visible and labelled,\n // but the Sonor upload only happens once enhanced. Forms with a file\n // field are excluded from native POST for exactly this reason\n // (see nativeEligible in native-fallback.tsx).\n <input\n id={inputId}\n className={`${classPrefix}__input ${classPrefix}__input--file`}\n type=\"file\"\n name={field.slug}\n required={field.is_required}\n style={baseInputStyle}\n />\n )\n )}\n \n {/* Rating */}\n {field.field_type === 'rating' && (\n <div className={`${classPrefix}__rating`} style={{ display: 'flex', gap: 4 }} role={interactive ? undefined : 'radiogroup'} aria-label={interactive ? undefined : field.label}>\n {!interactive && [1, 2, 3, 4, 5].map((star) => (\n // Static: a real radio group. Submits natively, and is reachable\n // by keyboard and screen readers without any script.\n <label key={`s${star}`} className={`${classPrefix}__rating-star`} style={{ fontSize: 24, cursor: 'pointer', color: (value as number) >= star ? 'var(--sk-rating-active, #fbbf24)' : 'var(--sk-rating-inactive, #d1d5db)' }}>\n <input\n type=\"radio\"\n name={field.slug}\n value={star}\n defaultChecked={(value as number) === star}\n required={field.is_required && star === 1}\n style={{ position: 'absolute', width: 1, height: 1, opacity: 0 }}\n />\n <span aria-label={`${star} star${star > 1 ? 's' : ''}`}>★</span>\n </label>\n ))}\n {interactive && [1, 2, 3, 4, 5].map((star) => (\n <button\n key={star}\n type=\"button\"\n onClick={() => emit(star)}\n className={`${classPrefix}__rating-star`}\n style={{\n background: 'none',\n border: 'none',\n fontSize: 24,\n cursor: 'pointer',\n color: (value as number) >= star ? 'var(--sk-rating-active, #fbbf24)' : 'var(--sk-rating-inactive, #d1d5db)',\n }}\n >\n ★\n </button>\n ))}\n </div>\n )}\n \n {/* Slider */}\n {field.field_type === 'slider' && (\n <div className={`${classPrefix}__slider`}>\n <input\n id={inputId}\n type=\"range\"\n name={field.slug}\n {...(interactive\n ? { value: Number(value || 50), onChange: (e: any) => emit(Number(e.target.value)) }\n : { defaultValue: Number(value || 50) })}\n min={field.validation?.min || 0}\n max={field.validation?.max || 100}\n style={{ width: '100%' }}\n />\n <div className={`${classPrefix}__slider-value`} style={{ textAlign: 'center', marginTop: 4 }}>{String(value || 50)}</div>\n </div>\n )}\n \n {/* Error message */}\n {error && <p className={`${classPrefix}__error`} style={errorStyle}>{error}</p>}\n \n {/* Help text */}\n {field.help_text && !error && field.field_type !== 'checkbox' && (\n <p className={`${classPrefix}__help`} style={helpStyle}>{field.help_text}</p>\n )}\n </div>\n )\n}\n"]}
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var chunkH5NBFNND_js = require('./chunk-H5NBFNND.js');
4
+ var chunkSWIKKSKL_js = require('./chunk-SWIKKSKL.js');
5
+
6
+ // src/seo/register-sitemap-request.ts
7
+ function resolveSyncSite(explicit) {
8
+ const host = chunkSWIKKSKL_js.normalizeSiteHost(explicit) || chunkH5NBFNND_js.resolveSiteHost();
9
+ return host === "example.com" ? "" : host;
10
+ }
11
+ function registerSitemapBody(req) {
12
+ const body = { entries: req.entries, mode: req.mode };
13
+ const site = chunkSWIKKSKL_js.normalizeSiteHost(req.site);
14
+ if (site) body.site = site;
15
+ if (req.optimizeMeta !== void 0) body.optimize_meta = req.optimizeMeta;
16
+ if (req.awaitMeta !== void 0) body.await_meta = req.awaitMeta;
17
+ return body;
18
+ }
19
+ function postRegisterSitemap(req) {
20
+ return fetch(`${req.apiUrl}/api/public/seo/register-sitemap`, {
21
+ method: "POST",
22
+ headers: {
23
+ "Content-Type": "application/json",
24
+ "x-api-key": req.apiKey
25
+ },
26
+ body: JSON.stringify(registerSitemapBody(req))
27
+ });
28
+ }
29
+
30
+ exports.postRegisterSitemap = postRegisterSitemap;
31
+ exports.resolveSyncSite = resolveSyncSite;
32
+ //# sourceMappingURL=chunk-XBX2K3GA.js.map
33
+ //# sourceMappingURL=chunk-XBX2K3GA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/seo/register-sitemap-request.ts"],"names":["normalizeSiteHost","resolveSiteHost"],"mappings":";;;;;;AAmCO,SAAS,gBAAgB,QAAA,EAA2B;AACzD,EAAA,MAAM,IAAA,GAAOA,kCAAA,CAAkB,QAAQ,CAAA,IAAKC,gCAAA,EAAgB;AAC5D,EAAA,OAAO,IAAA,KAAS,gBAAgB,EAAA,GAAK,IAAA;AACvC;AAGO,SAAS,oBAAoB,GAAA,EAAiF;AACnH,EAAA,MAAM,OAAgC,EAAE,OAAA,EAAS,IAAI,OAAA,EAAS,IAAA,EAAM,IAAI,IAAA,EAAK;AAC7E,EAAA,MAAM,IAAA,GAAOD,kCAAA,CAAkB,GAAA,CAAI,IAAI,CAAA;AACvC,EAAA,IAAI,IAAA,OAAW,IAAA,GAAO,IAAA;AACtB,EAAA,IAAI,GAAA,CAAI,YAAA,KAAiB,MAAA,EAAW,IAAA,CAAK,gBAAgB,GAAA,CAAI,YAAA;AAC7D,EAAA,IAAI,GAAA,CAAI,SAAA,KAAc,MAAA,EAAW,IAAA,CAAK,aAAa,GAAA,CAAI,SAAA;AACvD,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,oBAAoB,GAAA,EAAgD;AAClF,EAAA,OAAO,KAAA,CAAM,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA,gCAAA,CAAA,EAAoC;AAAA,IAC5D,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS;AAAA,MACP,cAAA,EAAgB,kBAAA;AAAA,MAChB,aAAa,GAAA,CAAI;AAAA,KACnB;AAAA,IACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,mBAAA,CAAoB,GAAG,CAAC;AAAA,GAC9C,CAAA;AACH","file":"chunk-XBX2K3GA.js","sourcesContent":["/**\n * @sonordev/site-kit/seo — the one POST to /api/public/seo/register-sitemap.\n *\n * SINGLE SOURCE OF TRUTH for the request body, used by createSitemap's\n * build-time sync (`syncSitemapToPortal`), the `sonor-register-sitemap` CLI\n * and `registerSitemap` / `registerLocalSitemap` on `seo/server`. There were\n * three hand-built bodies, and only createSitemap's carried `site`: on a\n * multi-site project the CLI and the seo/server helpers synced every page as\n * unattributed instead of this host's (found 2026-09-15). `site` is part of\n * seo_pages identity, so a missing one is a different page, not a no-op.\n *\n * A leaf: no `server-only`, no Node built-ins, so the plain-Node CLI can use\n * it as well as Next server code.\n */\n\nimport { resolveSiteHost } from '../sites/resolve'\nimport { normalizeSiteHost } from '../sites/normalize'\n\nexport interface RegisterSitemapRequest {\n apiUrl: string\n apiKey: string\n entries: unknown[]\n mode: 'additive' | 'full-replace'\n /** Sub-site host, already resolved. Empty or undefined leaves `site` off. */\n site?: string\n optimizeMeta?: boolean\n awaitMeta?: boolean\n}\n\n/**\n * The host a sync is tagged with: an explicit `site`, else\n * NEXT_PUBLIC_SITE_URL's. Empty when neither resolves (a single-site project\n * doesn't need one). `example.com` is the kit's placeholder origin and never a\n * real host, so it's never sent, same as createSitemap.\n */\nexport function resolveSyncSite(explicit?: string): string {\n const host = normalizeSiteHost(explicit) || resolveSiteHost()\n return host === 'example.com' ? '' : host\n}\n\n/** The request body. Exported for tests. */\nexport function registerSitemapBody(req: Omit<RegisterSitemapRequest, 'apiUrl' | 'apiKey'>): Record<string, unknown> {\n const body: Record<string, unknown> = { entries: req.entries, mode: req.mode }\n const site = normalizeSiteHost(req.site)\n if (site) body.site = site\n if (req.optimizeMeta !== undefined) body.optimize_meta = req.optimizeMeta\n if (req.awaitMeta !== undefined) body.await_meta = req.awaitMeta\n return body\n}\n\n/** POST the entries. Callers keep their own response and error handling. */\nexport function postRegisterSitemap(req: RegisterSitemapRequest): Promise<Response> {\n return fetch(`${req.apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': req.apiKey,\n },\n body: JSON.stringify(registerSitemapBody(req)),\n })\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
+ var chunk5XFFUP6D_js = require('./chunk-5XFFUP6D.js');
4
5
  var react = require('react');
5
6
 
6
- // src/forms/field-controls.ts
7
7
  var NO_CONTROLS = {};
8
8
  function useFieldControls(fields) {
9
9
  const needsDate = react.useMemo(
@@ -28,7 +28,7 @@ function useFieldControls(fields) {
28
28
  }
29
29
  if (needsFile && !requested.current.file) {
30
30
  requested.current.file = true;
31
- import('./FileField-UOQHL25J.js').then((m) => {
31
+ import('./FileField-SBPL4JHP.js').then((m) => {
32
32
  if (!cancelled) setControls((prev) => ({ ...prev, File: m.FileField }));
33
33
  }).catch(() => {
34
34
  requested.current.file = false;
@@ -42,10 +42,9 @@ function useFieldControls(fields) {
42
42
  }
43
43
 
44
44
  // src/forms/experience-plan.ts
45
- var NON_QUESTION_TYPES = ["heading", "section_header", "paragraph", "hidden"];
46
45
  function stageQuestions(config) {
47
46
  const input = (config.fields || []).filter(
48
- (f) => !NON_QUESTION_TYPES.includes(f.field_type)
47
+ (f) => !chunk5XFFUP6D_js.isDisplayOnly(f)
49
48
  );
50
49
  if (!config.is_multi_step || !config.steps?.length) {
51
50
  return input.map((field) => ({ field }));
@@ -122,13 +121,8 @@ function stageFirstName(value) {
122
121
  if (!token || token.length > 24) return null;
123
122
  return token;
124
123
  }
125
- function isEmptyValue(value) {
126
- if (value === void 0 || value === null || value === "") return true;
127
- if (Array.isArray(value)) return value.length === 0;
128
- return false;
129
- }
130
124
  function formatAnswer(value) {
131
- if (isEmptyValue(value)) return null;
125
+ if (chunk5XFFUP6D_js.isEmptyValue(value)) return null;
132
126
  if (Array.isArray(value)) return value.map(String).join(", ");
133
127
  if (typeof value === "boolean") return value ? "Yes" : "No";
134
128
  return String(value);
@@ -139,10 +133,9 @@ exports.AUTO_ADVANCE_TYPES = AUTO_ADVANCE_TYPES;
139
133
  exports.countStageQuestions = countStageQuestions;
140
134
  exports.countStageViews = countStageViews;
141
135
  exports.formatAnswer = formatAnswer;
142
- exports.isEmptyValue = isEmptyValue;
143
136
  exports.stageEstimate = stageEstimate;
144
137
  exports.stageFirstName = stageFirstName;
145
138
  exports.stageViews = stageViews;
146
139
  exports.useFieldControls = useFieldControls;
147
- //# sourceMappingURL=chunk-X5TCH7VZ.js.map
148
- //# sourceMappingURL=chunk-X5TCH7VZ.js.map
140
+ //# sourceMappingURL=chunk-XCYKM2SA.js.map
141
+ //# sourceMappingURL=chunk-XCYKM2SA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/forms/field-controls.ts","../src/forms/experience-plan.ts"],"names":["useMemo","useState","useRef","useEffect","isDisplayOnly","isEmptyValue"],"mappings":"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","file":"chunk-XCYKM2SA.js","sourcesContent":["'use client'\n\n/**\n * The field controls that need React hooks, loaded only when a form actually\n * has a field that uses them.\n *\n * FormField deliberately does NOT import these. DatePicker carries 17 hooks\n * and FileField holds upload state; importing them there put both in\n * FormField's chunk, which the build stamps `'use client'` — so a Server\n * Component rendering a single text input shipped 38 KB of date picker to the\n * browser. Injecting them from the client side keeps FormField hook-free and\n * therefore server-renderable, which is the whole basis of StaticForm.\n *\n * Injection alone still put both controls in the forms entry's eager graph,\n * because a module-level constant referencing them is a static import: every\n * form paid for the date picker, and most forms have no date field. They are\n * now fetched on demand, per control, from the field list.\n *\n * The wait costs nothing visually. FormField already renders the native\n * control when a control is absent (static mode does exactly this), so a date\n * field paints as `<input type=\"date\">` and upgrades in place when the chunk\n * lands — the same enhancement path a no-JS visitor never leaves.\n *\n * Every client renderer of <FormField> (FormClient, FormSpotlight, FormStage)\n * calls this hook, so the experiences and the classic form always offer\n * identical controls.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport type { FormField as FormFieldType } from './types'\n\nexport interface FieldControls {\n Date?: React.ComponentType<any>\n File?: React.ComponentType<any>\n}\n\n/** Stable identity for the common case (no date, no file) — no render churn. */\nconst NO_CONTROLS: FieldControls = {}\n\nexport function useFieldControls(fields: FormFieldType[] | undefined): FieldControls {\n const needsDate = useMemo(\n () => (fields ?? []).some((f) => f.field_type === 'date' || f.field_type === 'datetime'),\n [fields],\n )\n const needsFile = useMemo(\n () => (fields ?? []).some((f) => f.field_type === 'file'),\n [fields],\n )\n\n const [controls, setControls] = useState<FieldControls>(NO_CONTROLS)\n // Guards re-import when a conditional field toggles visibility mid-fill.\n const requested = useRef({ date: false, file: false })\n\n useEffect(() => {\n let cancelled = false\n\n if (needsDate && !requested.current.date) {\n requested.current.date = true\n import('./DatePicker')\n .then((m) => {\n if (!cancelled) setControls((prev) => ({ ...prev, Date: m.DatePicker }))\n })\n .catch(() => {\n // Chunk never arrived — the native date input stays, which submits\n // the same value. A failed fetch must not cost the lead.\n requested.current.date = false\n })\n }\n\n if (needsFile && !requested.current.file) {\n requested.current.file = true\n import('./FileField')\n .then((m) => {\n if (!cancelled) setControls((prev) => ({ ...prev, File: m.FileField }))\n })\n .catch(() => {\n requested.current.file = false\n })\n }\n\n return () => {\n cancelled = true\n }\n }, [needsDate, needsFile])\n\n return controls\n}\n","/**\n * Shared planning helpers for the alternate form experiences (stage,\n * spotlight). Pure data — no React, no CSS — so FormClient can import the\n * counts it needs for tracking WITHOUT pulling an experience component (and\n * its stylesheet) into every site's forms bundle. The components themselves\n * are lazy-loaded; this module is the only part that ships eagerly.\n */\n\nimport type {\n FormField as FormFieldType,\n FormStep,\n ManagedFormConfig,\n} from './types'\n// Display-only types are never staged; what counts as empty is shared with\n// validation. Both live in field-rules.ts.\nimport { isDisplayOnly, isEmptyValue } from './field-rules'\n\nexport interface StageQuestion {\n field: FormFieldType\n /** The step (chapter) this question belongs to, when the form is multi-step. */\n step?: FormStep\n}\n\nexport interface StageView {\n fields: FormFieldType[]\n step?: FormStep\n}\n\n/**\n * Flatten a form into its ordered question list. Steps become chapters:\n * multi-step forms iterate steps in step_number order (fields are already\n * sorted by sort_order via normalizeFormConfig); stepless fields trail.\n */\nexport function stageQuestions(config: ManagedFormConfig): StageQuestion[] {\n const input = (config.fields || []).filter(\n (f) => !isDisplayOnly(f),\n )\n if (!config.is_multi_step || !config.steps?.length) {\n return input.map((field) => ({ field }))\n }\n const ordered = [...config.steps].sort((a, b) => a.step_number - b.step_number)\n const out: StageQuestion[] = []\n const claimed = new Set<string>()\n for (const step of ordered) {\n for (const field of input) {\n if (field.step_id === step.id) {\n out.push({ field, step })\n claimed.add(field.id)\n }\n }\n }\n for (const field of input) {\n if (!claimed.has(field.id)) out.push({ field })\n }\n return out\n}\n\nconst WIDTH_FRACTION: Record<string, number> = {\n full: 1,\n half: 1 / 2,\n third: 1 / 3,\n quarter: 1 / 4,\n}\n\n/**\n * Group questions into beats using the classic grid's own row math:\n * consecutive sub-full-width fields fill a row (2 halves, 3 thirds...) and\n * that row is one beat; a full-width field closes any open row and stands\n * alone; a chapter change always starts a fresh beat.\n */\nexport function stageViews(config: ManagedFormConfig): StageView[] {\n const questions = stageQuestions(config)\n const views: StageView[] = []\n let open: StageView | null = null\n let openWidth = 0\n\n const close = () => {\n if (open) views.push(open)\n open = null\n openWidth = 0\n }\n\n for (const q of questions) {\n const fraction = WIDTH_FRACTION[q.field.width] ?? 1\n const chapterChanged = open && open.step?.id !== q.step?.id\n if (fraction >= 1 || chapterChanged) close()\n if (!open) {\n open = { fields: [q.field], step: q.step }\n openWidth = fraction\n if (fraction >= 1) close()\n continue\n }\n if (openWidth + fraction > 1.0001) close()\n if (!open) {\n open = { fields: [q.field], step: q.step }\n openWidth = fraction\n continue\n }\n open.fields.push(q.field)\n openWidth += fraction\n }\n close()\n return views\n}\n\nexport function countStageViews(config: ManagedFormConfig): number {\n return stageViews(config).length\n}\n\nexport function countStageQuestions(config: ManagedFormConfig): number {\n return stageQuestions(config).length\n}\n\n/**\n * Honest, friendly time estimate: \"about 40 seconds\".\n * ~8s per question, rounded to something a human would actually say.\n */\nexport function stageEstimate(questionCount: number): string {\n const seconds = questionCount * 8\n if (seconds < 50) return `about ${Math.max(15, Math.ceil(seconds / 5) * 5)} seconds`\n if (seconds <= 90) return 'about a minute'\n return `about ${Math.round(seconds / 60)} minutes`\n}\n\n/** First name for the greeting — conservative: short, single token, else null. */\nexport function stageFirstName(value: unknown): string | null {\n if (typeof value !== 'string') return null\n const token = value.trim().split(/\\s+/)[0]\n if (!token || token.length > 24) return null\n return token\n}\n\nexport function formatAnswer(value: unknown): string | null {\n if (isEmptyValue(value)) return null\n if (Array.isArray(value)) return value.map(String).join(', ')\n if (typeof value === 'boolean') return value ? 'Yes' : 'No'\n return String(value)\n}\n\n/** Single-select types where picking an answer advances after a lock-in beat. */\nexport const AUTO_ADVANCE_TYPES = ['radio', 'select', 'rating']\n"]}
@@ -1,14 +1,5 @@
1
- 'use strict';
2
-
3
- // src/og/config.ts
4
- function defineOgCard(config) {
5
- return config;
6
- }
7
- var OG_WIDTH = 1200;
8
- var OG_HEIGHT = 630;
9
- var TITLE_MAX_PX = 104;
10
- var TITLE_MIN_PX = 56;
11
- var OG_REPORT_ATTR = "data-og-report";
1
+ import { OG_HEIGHT, OG_WIDTH, TITLE_MAX_PX, barTextColor, TITLE_MIN_PX, OG_REPORT_ATTR } from './chunk-YU7QZ3PP.mjs';
2
+ import { applyTrailingSlash, resolveTrailingSlash } from './chunk-4LYW6PMU.mjs';
12
3
 
13
4
  // src/og/template.ts
14
5
  function fitScript() {
@@ -174,7 +165,7 @@ ${fontLink(config)}
174
165
  /* Never below 40px: script faces are illegible at thumbnail width under that. */
175
166
  .hand { font-size:42px; margin-top:14px; transform:rotate(-1.5deg); display:inline-block; }
176
167
  .bar { position:absolute; left:0; right:0; bottom:0; height:74px; display:flex; align-items:center; justify-content:center; gap:26px;
177
- font-weight:800; text-transform:uppercase; letter-spacing:.1em; font-size:31px; color:${theme.surface}; }
168
+ font-weight:800; text-transform:uppercase; letter-spacing:.1em; font-size:31px; color:${barTextColor(theme)}; }
178
169
  /* nowrap so an over-long segment overflows the bar sideways, where the
179
170
  fitter's width check sees it, instead of silently wrapping to a second
180
171
  line and spilling over the copy above. */
@@ -189,11 +180,147 @@ ${fitScript()}
189
180
  </body></html>`;
190
181
  }
191
182
 
192
- exports.OG_HEIGHT = OG_HEIGHT;
193
- exports.OG_REPORT_ATTR = OG_REPORT_ATTR;
194
- exports.OG_WIDTH = OG_WIDTH;
195
- exports.TITLE_MAX_PX = TITLE_MAX_PX;
196
- exports.buildOgHtml = buildOgHtml;
197
- exports.defineOgCard = defineOgCard;
198
- //# sourceMappingURL=chunk-6CJP7BFM.js.map
199
- //# sourceMappingURL=chunk-6CJP7BFM.js.map
183
+ // src/og/pages.ts
184
+ var DYNAMIC = "*";
185
+ function pathSegments(path) {
186
+ return path.split("/").filter(Boolean);
187
+ }
188
+ var TITLE_SEPARATOR = /\s*\|\s*|\s+[–—-]\s+/g;
189
+ var TRAILING_HOSTNAME = /,\s*(?:https?:\/\/)?(?:[a-z0-9-]+\.)+[a-z]{2,}\/?$/i;
190
+ var DANGLING_SEPARATOR = /(?:\s*\||\s+[–—-])\s*$/;
191
+ function stripBrandSuffix(title, brand) {
192
+ const original = title.trim();
193
+ const base = original.replace(DANGLING_SEPARATOR, "").replace(TRAILING_HOSTNAME, "").trim() || original;
194
+ let last = -1;
195
+ for (const m of base.matchAll(TITLE_SEPARATOR)) last = m.index ?? last;
196
+ const cleaned = last > 0 ? base.slice(0, last).trim() : base;
197
+ if (!cleaned) return base;
198
+ if (brand && cleaned.toLowerCase() === brand.toLowerCase()) return base;
199
+ return cleaned;
200
+ }
201
+ function titleFromPath(path) {
202
+ const last = pathSegments(path).filter((s) => s !== DYNAMIC).pop();
203
+ if (!last) return "Home";
204
+ return last.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
205
+ }
206
+ function kickerFromPath(path, fallback) {
207
+ const parts = pathSegments(path);
208
+ const section = (parts[parts.length - 1] === DYNAMIC ? parts : parts.slice(0, -1)).filter(
209
+ (s) => s !== DYNAMIC
210
+ );
211
+ if (!section.length) return fallback;
212
+ return section.join(" / ").replace(/[-_]+/g, " ");
213
+ }
214
+ function clampSubtitle(text, max = 100) {
215
+ if (!text) return void 0;
216
+ const flat = text.replace(/\s+/g, " ").trim();
217
+ if (!flat) return void 0;
218
+ if (flat.length <= max) return flat;
219
+ const sentence = flat.slice(0, max + 1).match(/^.*[.!?](?=\s|$)/)?.[0];
220
+ if (sentence && sentence.length >= 30) return sentence.trim();
221
+ return void 0;
222
+ }
223
+ function kickerIsRedundant(kicker, title) {
224
+ if (!kicker) return false;
225
+ const norm = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
226
+ const k = norm(kicker);
227
+ const t = norm(title);
228
+ if (!k) return true;
229
+ if (t.includes(k) || k.includes(t)) return true;
230
+ const titleWords = new Set(t.split(" "));
231
+ return k.split(" ").every((w) => titleWords.has(w));
232
+ }
233
+ function slugForPath(path) {
234
+ const segments = pathSegments(path);
235
+ if (!segments.length) return "home";
236
+ return segments.map((s) => s === DYNAMIC ? "any" : s).join("-").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
237
+ }
238
+ function unmatchedCardKeys(cards, paths) {
239
+ if (!cards) return [];
240
+ const known = new Set(paths.flatMap((p) => [p, slugForPath(p)]));
241
+ const patterns = paths.filter((p) => p.includes(DYNAMIC));
242
+ return Object.keys(cards).filter(
243
+ (key) => !known.has(key) && !patterns.some((pattern) => matchesRoutePattern(key, pattern))
244
+ );
245
+ }
246
+ function bareRoute(path) {
247
+ const segments = pathSegments(path);
248
+ return segments.length ? `/${segments.join("/")}` : "/";
249
+ }
250
+ function matchesRoutePattern(path, pattern) {
251
+ const concrete = pathSegments(path);
252
+ const shape = pathSegments(pattern);
253
+ if (concrete.includes(DYNAMIC) || concrete.length !== shape.length) return false;
254
+ return shape.every((seg, i) => seg === DYNAMIC || seg === concrete[i]);
255
+ }
256
+ function paramCardKeys(cards, paths) {
257
+ if (!cards) return [];
258
+ const known = new Set(paths.flatMap((p) => [p, slugForPath(p)]));
259
+ const patterns = paths.filter((p) => p.includes(DYNAMIC));
260
+ const found = [];
261
+ for (const key of Object.keys(cards)) {
262
+ if (known.has(key) || !key.startsWith("/")) continue;
263
+ const pattern = patterns.find((p) => matchesRoutePattern(key, p));
264
+ if (pattern) found.push({ path: bareRoute(key), pattern });
265
+ }
266
+ return found;
267
+ }
268
+ var PARAM_CARD_DIR = "_og";
269
+ function paramCardUrl(path) {
270
+ const segments = pathSegments(path);
271
+ return `/${PARAM_CARD_DIR}/${segments.length ? segments.join("/") : "home"}.jpg`;
272
+ }
273
+ function paramCardImage(path, options = {}) {
274
+ if (options.config) {
275
+ const bare = bareRoute(path);
276
+ const cards = options.config.cards ?? {};
277
+ if (!cards[bare] && !cards[`${bare}/`]) return void 0;
278
+ }
279
+ return {
280
+ url: paramCardUrl(path),
281
+ width: OG_WIDTH,
282
+ height: OG_HEIGHT,
283
+ type: "image/jpeg",
284
+ ...options.alt && { alt: options.alt }
285
+ };
286
+ }
287
+ function codeCardImage(path, options = {}) {
288
+ const base = bareRoute(path);
289
+ const url = applyTrailingSlash(`${base === "/" ? "" : base}/opengraph-image`, resolveTrailingSlash(options.trailingSlash));
290
+ return {
291
+ url,
292
+ width: OG_WIDTH,
293
+ height: OG_HEIGHT,
294
+ type: options.contentType ?? "image/png",
295
+ ...options.alt && { alt: options.alt }
296
+ };
297
+ }
298
+ function pageCardConfig(base, route, brand) {
299
+ const override = base.cards?.[route.path] ?? base.cards?.[`${route.path}/`] ?? base.cards?.[slugForPath(route.path)];
300
+ const isHome = route.path === "/";
301
+ const derived = isHome ? { ...base, cards: void 0 } : (() => {
302
+ const title = route.title ? stripBrandSuffix(route.title, brand) : titleFromPath(route.path);
303
+ const kicker = kickerFromPath(route.path, base.content.kicker);
304
+ return {
305
+ ...base,
306
+ // `cards` is a build-time instruction, not part of a rendered card.
307
+ cards: void 0,
308
+ content: {
309
+ ...base.content,
310
+ kicker: kickerIsRedundant(kicker, title) ? void 0 : kicker,
311
+ title,
312
+ subtitle: clampSubtitle(route.description) ?? base.content.subtitle
313
+ }
314
+ };
315
+ })();
316
+ if (!override) return derived;
317
+ return {
318
+ ...derived,
319
+ ...override,
320
+ content: { ...derived.content, ...override.content }
321
+ };
322
+ }
323
+
324
+ export { DYNAMIC, PARAM_CARD_DIR, buildOgHtml, codeCardImage, pageCardConfig, paramCardImage, paramCardKeys, paramCardUrl, unmatchedCardKeys };
325
+ //# sourceMappingURL=chunk-XZO5I4RS.mjs.map
326
+ //# sourceMappingURL=chunk-XZO5I4RS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/og/template.ts","../src/og/pages.ts"],"names":[],"mappings":"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","file":"chunk-XZO5I4RS.mjs","sourcesContent":["/**\n * OG card HTML template builder.\n *\n * Turns an OgCardConfig into a self-contained 1200x630 HTML document rendered\n * by headless Chrome. Layout rules baked in from the Ludlow card:\n * - content held inside the middle ~80% (platforms crop toward 2:1 and the\n * bottom bar is the first casualty)\n * - script/hand faces never below 40px — under that they turn to mush at\n * iMessage thumbnail width (~300px)\n * - the plate + title must survive alone if everything else is cropped\n */\n\nimport type { OgCardConfig, OgContent, OgTheme } from './config'\nimport { barTextColor } from './contrast'\nimport {\n OG_WIDTH,\n OG_HEIGHT,\n TITLE_MAX_PX,\n TITLE_MIN_PX,\n OG_REPORT_ATTR,\n} from './config'\n\n/**\n * The in-page fitter. Runs inside the render, after webfonts settle, and does\n * the two things a Node-side template cannot:\n *\n * 1. FITS THE TITLE. The h1 opens at TITLE_MAX_PX and steps down until the\n * copy column fits the frame. Before this the size was fixed, so title\n * length silently decided whether a card worked — a long one did not\n * shrink, it pushed the kicker off the top and the subtitle under the\n * bottom bar, and the CLI still reported success.\n * 2. MEASURES WHAT IS LEFT. Anything still clipped is written to the report\n * attribute, which `sonor-setup og` reads back through --dump-dom and\n * turns into a failure. Real measurement, not a character-count estimate.\n *\n * Fonts matter: measuring before `document.fonts.ready` measures the fallback\n * face and produces a size that is wrong for the face that actually renders.\n */\nfunction fitScript(): string {\n return `<script>\n(async function () {\n var report = { fits: true, titlePx: ${TITLE_MAX_PX}, issues: [] };\n function push(msg) { report.fits = false; report.issues.push(msg); }\n try {\n try { await document.fonts.ready; } catch (e) {}\n var h1 = document.querySelector('h1');\n var copy = document.querySelector('.copy');\n var wrap = document.querySelector('.wrap');\n var bar = document.querySelector('.bar');\n\n if (h1 && copy && wrap) {\n var cs = getComputedStyle(wrap);\n var avail = wrap.clientHeight - parseFloat(cs.paddingTop || '0') - parseFloat(cs.paddingBottom || '0');\n\n // Fit BOTH axes. Height alone is not enough: a single long word\n // (\"WORKBENCHES\") cannot wrap, so it keeps overflowing the column\n // sideways at a size that fits vertically. Shrinking for either\n // condition is what makes an arbitrary managed title safe to render.\n var tooTall = function () { return copy.scrollHeight > avail; };\n var tooWide = function () { return h1.scrollWidth > copy.clientWidth + 1; };\n var size = ${TITLE_MAX_PX};\n while (size > ${TITLE_MIN_PX} && (tooTall() || tooWide())) {\n size -= 2;\n h1.style.fontSize = size + 'px';\n }\n report.titlePx = size;\n\n if (tooTall()) {\n push('title/subtitle block overflows the card by ' + Math.ceil(copy.scrollHeight - avail) +\n 'px even at the ' + ${TITLE_MIN_PX} + 'px legibility floor - shorten content.title or content.subtitle');\n }\n if (tooWide()) {\n push('the longest title word still overflows the copy column by ' + Math.ceil(h1.scrollWidth - copy.clientWidth) +\n 'px at the ' + ${TITLE_MIN_PX} + 'px floor - shorten it or add a line break');\n }\n }\n\n // The bar is checked on BOTH axes. Width alone missed a real failure: a\n // long segment wrapped INSIDE its span, so scrollWidth never exceeded\n // clientWidth while the text grew past the bar's fixed height and spilled\n // over the subtitle. Segments are nowrap now, which turns that into\n // horizontal overflow the width check sees, and the height check is the\n // belt-and-braces for anything else that grows the bar.\n if (bar) {\n if (bar.scrollWidth > bar.clientWidth + 1) {\n push('bottom bar content overflows by ' + Math.ceil(bar.scrollWidth - bar.clientWidth) +\n 'px - drop a content.bar segment or shorten one');\n }\n if (bar.scrollHeight > bar.clientHeight + 1) {\n push('bottom bar content is ' + Math.ceil(bar.scrollHeight - bar.clientHeight) +\n 'px taller than the bar - a segment is wrapping; shorten it');\n }\n }\n\n // Nothing may sit outside the frame platforms actually crop to.\n var named = [['kicker', '.kicker'], ['title', 'h1'], ['subtitle', '.sub'], ['hand', '.hand'], ['bar', '.bar']];\n for (var i = 0; i < named.length; i++) {\n var el = document.querySelector(named[i][1]);\n if (!el) continue;\n var r = el.getBoundingClientRect();\n if (r.top < -1 || r.bottom > ${OG_HEIGHT} + 1) {\n push(named[i][0] + ' sits outside the ' + ${OG_HEIGHT} + 'px frame (top ' +\n Math.round(r.top) + ', bottom ' + Math.round(r.bottom) + ')');\n }\n }\n } catch (e) {\n push('fitter failed: ' + (e && e.message ? e.message : String(e)));\n }\n document.documentElement.setAttribute('${OG_REPORT_ATTR}', JSON.stringify(report));\n})();\n</script>`\n}\n\nfunction esc(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\nfunction fontLink(config: OgCardConfig): string {\n const fonts = config.fonts?.length\n ? config.fonts\n : [{ family: 'Barlow Condensed', weights: [800] }]\n const families = fonts\n .map(f => `family=${f.family.replace(/ /g, '+')}:wght@${(f.weights || [700]).join(';')}`)\n .join('&')\n return `<link href=\"https://fonts.googleapis.com/css2?${families}&display=block\" rel=\"stylesheet\">`\n}\n\nfunction displayFamily(config: OgCardConfig): string {\n return config.fonts?.[0]?.family || 'Barlow Condensed'\n}\n\nfunction handFamily(config: OgCardConfig): string {\n const fonts = config.fonts || []\n return fonts.length > 1 ? fonts[fonts.length - 1].family : displayFamily(config)\n}\n\nfunction muted(theme: OgTheme): string {\n return theme.muted || theme.text\n}\n\nfunction backgroundLayers(config: OgCardConfig): string {\n if (!config.background) return ''\n const { image, blur = 0, scrim } = config.background\n return `\n <div class=\"bg\"><img src=\"${esc(image)}\" style=\"filter:blur(${blur}px)\"></div>\n ${scrim ? `<div class=\"scrim\" style=\"background:${esc(scrim)}\"></div>` : ''}`\n}\n\nfunction barHtml(content: OgContent, theme: OgTheme): string {\n if (!content.bar?.length) return ''\n const segs = content.bar\n .map(s => `<span>${esc(s)}</span>`)\n .join('<span class=\"dot\"></span>')\n return `<div class=\"bar\" style=\"background:${esc(theme.accent)}\">${segs}</div>`\n}\n\nfunction copyHtml(config: OgCardConfig): string {\n const { content, theme } = config\n const titleHtml = esc(content.title).replace(/\\n/g, '<br>')\n // In `split` the photo owns the right pane, so a configured logo has nowhere\n // to go as a plate. It used to be dropped silently. Render it small above the\n // kicker instead: the brand mark still appears, and the plate invariant that\n // split has no `.plate` is preserved.\n const mark =\n config.logo && (config.layout ?? (config.logo ? 'plate-left' : 'banner')) === 'split'\n ? `<img class=\"mark\" src=\"${esc(config.logo)}\">`\n : ''\n return `\n <div class=\"copy\">\n ${mark}\n ${content.kicker ? `<div class=\"kicker\">${esc(content.kicker)}</div>` : ''}\n <h1>${titleHtml}</h1>\n ${content.subtitle ? `<div class=\"sub\" style=\"color:${esc(muted(theme))}\">${esc(content.subtitle)}</div>` : ''}\n ${content.hand ? `<div class=\"hand\" style=\"font-family:'${esc(handFamily(config))}',cursive\">${esc(content.hand)}</div>` : ''}\n </div>`\n}\n\nexport function buildOgHtml(config: OgCardConfig): string {\n if (config.html) return config.html\n if (config.template) {\n return config.template(config, {\n esc,\n fontLink: fontLink(config),\n width: OG_WIDTH,\n height: OG_HEIGHT,\n })\n }\n\n const { theme, logo, layout = logo ? 'plate-left' : 'banner' } = config\n const display = displayFamily(config)\n\n const plate = logo\n ? `<div class=\"plate\" style=\"background:${esc(theme.surface)}\"><img src=\"${esc(logo)}\"></div>`\n : ''\n\n const photo = config.photo\n ? `<div class=\"photo\" style=\"flex-basis:${config.photo.width ?? 430}px;border-radius:${config.photo.radius ?? 24}px\"><img src=\"${esc(config.photo.src)}\"></div>`\n : ''\n\n const body =\n layout === 'centered'\n ? `<div class=\"wrap centered\">${plate}${copyHtml(config)}</div>`\n : layout === 'banner'\n ? `<div class=\"wrap banner\">${copyHtml(config)}</div>`\n : layout === 'split'\n ? `<div class=\"wrap\">${copyHtml(config)}${photo}</div>`\n : `<div class=\"wrap\">${photo || plate}${copyHtml(config)}</div>`\n\n return `<!doctype html>\n<html><head><meta charset=\"utf-8\">\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n${fontLink(config)}\n<style>\n * { margin:0; padding:0; box-sizing:border-box; }\n html,body { width:${OG_WIDTH}px; height:${OG_HEIGHT}px; overflow:hidden; }\n body { position:relative; background:${theme.bg}; font-family:'${display}',sans-serif; color:${theme.text}; }\n .bg { position:absolute; inset:0; }\n .bg img { width:100%; height:100%; object-fit:cover; transform:scale(1.05); }\n .scrim { position:absolute; inset:0; }\n .wrap { position:relative; height:100%; display:flex; align-items:center; gap:52px; padding:0 68px ${config.content.bar?.length ? '74px' : '0'}; }\n .wrap.centered { flex-direction:column; justify-content:center; text-align:center; gap:28px; }\n .wrap.banner { padding-left:90px; }\n .plate { border-radius:28px; padding:26px; flex:0 0 auto; }\n .plate img { display:block; width:250px; height:auto; }\n .centered .plate img { width:180px; }\n .photo { flex:0 0 auto; height:76%; overflow:hidden; box-shadow:0 8px 40px rgba(0,0,0,.25); }\n .photo img { width:100%; height:100%; object-fit:cover; display:block; }\n .copy { flex:1 1 auto; min-width:0; }\n /* split-layout brand mark: the photo owns the right pane, so the logo rides\n above the kicker rather than being dropped. */\n .mark { display:block; height:44px; width:auto; margin-bottom:20px; }\n .kicker { font-weight:800; text-transform:uppercase; letter-spacing:.22em; font-size:24px; color:${theme.accent}; margin-bottom:14px; }\n /* Opening size only — the in-page fitter steps this down to fit the frame. */\n h1 { font-weight:800; text-transform:uppercase; font-size:${TITLE_MAX_PX}px; line-height:.9; letter-spacing:-.01em; }\n .sub { margin-top:22px; font-size:29px; font-weight:500; line-height:1.32; }\n /* Never below 40px: script faces are illegible at thumbnail width under that. */\n .hand { font-size:42px; margin-top:14px; transform:rotate(-1.5deg); display:inline-block; }\n .bar { position:absolute; left:0; right:0; bottom:0; height:74px; display:flex; align-items:center; justify-content:center; gap:26px;\n font-weight:800; text-transform:uppercase; letter-spacing:.1em; font-size:31px; color:${barTextColor(theme)}; }\n /* nowrap so an over-long segment overflows the bar sideways, where the\n fitter's width check sees it, instead of silently wrapping to a second\n line and spilling over the copy above. */\n .bar > span { white-space:nowrap; }\n .bar .dot { width:10px; height:10px; border-radius:50%; background:currentColor; opacity:.55; flex:0 0 auto; }\n</style></head>\n<body>\n${backgroundLayers(config)}\n${body}\n${barHtml(config.content, theme)}\n${fitScript()}\n</body></html>`\n}\n","/**\n * @sonordev/site-kit/og — per-page card derivation.\n *\n * The site-wide card answers \"what is this site\". A per-page card answers\n * \"what is THIS page\", which is what someone pasting a deep link is actually\n * sharing. Every static route gets one by default.\n *\n * Copy comes from Sonor's managed metadata when a key is configured, because\n * that is the same copy the page's <title> and description already use — the\n * card and the SERP entry then say the same thing. Without a key (or when a\n * lookup fails) the path itself is titled, which is worse copy but still a\n * real, page-specific card rather than the site default.\n *\n * Everything else — theme, fonts, logo, photo, bar — is inherited from the\n * site's own og.config.ts, so the whole set reads as one family.\n */\n\nimport type { OgCardConfig } from './config'\nimport { OG_HEIGHT, OG_WIDTH } from './config'\n// Single source of truth for Next's trailingSlash URL shape (pure string logic).\nimport { applyTrailingSlash, resolveTrailingSlash } from '../sitemap/shared'\n\n/** A route to build a card for. */\nexport interface OgPageRoute {\n /** URL path, e.g. `/services/garage`. */\n path: string\n /** Managed title, if Sonor had one. */\n title?: string\n /** Managed meta description, if Sonor had one. */\n description?: string\n}\n\n/**\n * The stand-in for a dynamic segment in a route path.\n *\n * A dynamic route has no single URL, so its card is keyed by a pattern with one\n * `*` per dynamic level: `/services/[slug]` is `/services/*`, and each further\n * dynamic level adds another star. The depth is what keeps those patterns\n * apart — they are different pages and deserve different cards.\n *\n * (Nested patterns are spelled out in prose rather than written literally in\n * these block comments: a star followed by a slash closes the comment. See\n * src/og/README.md.)\n */\nexport const DYNAMIC = '*'\n\n/** `/services/garage/` -> `['services', 'garage']`. */\nfunction pathSegments(path: string): string[] {\n return path.split('/').filter(Boolean)\n}\n\n/**\n * A separator between a title and its brand: a pipe with or without spaces\n * around it, or a dash (`-`, `–`, `—`) with spaces on both sides. A dash with\n * no spaces is part of a word (\"Walk-In Closets\"), never a separator; the old\n * pattern treated it as one and cut that title to \"Walk\".\n */\nconst TITLE_SEPARATOR = /\\s*\\|\\s*|\\s+[–—-]\\s+/g\n\n/** `, abbeyglenapts.com` at the very end: a domain appended as if it were the brand. */\nconst TRAILING_HOSTNAME = /,\\s*(?:https?:\\/\\/)?(?:[a-z0-9-]+\\.)+[a-z]{2,}\\/?$/i\n\n/** A separator the title ends on, with nothing after it (\"Contact Us |\"). */\nconst DANGLING_SEPARATOR = /(?:\\s*\\||\\s+[–—-])\\s*$/\n\n/**\n * Trailing brand suffix on a managed title (` | Acme`, ` - Acme`, ` — Acme`).\n * Managed titles carry the brand because a SERP entry needs it; a card does\n * not — the logo, the photo and the bar are already saying whose it is, and\n * every character spent on the brand is one not spent on the page.\n *\n * Also drops the two broken suffixes managed titles turn up with, both found\n * on 2026-09-15 and each worked around by hand in a site's `cards`: a\n * dangling separator with no brand after it (reinhart's \"About Us |\", Green\n * Bay's), and the domain after a comma (\"Privacy Policy, abbeyglenapts.com\").\n */\nexport function stripBrandSuffix(title: string, brand?: string): string {\n const original = title.trim()\n // The junk first, so \"About | Acme |\" still loses its brand after it.\n const base = original.replace(DANGLING_SEPARATOR, '').replace(TRAILING_HOSTNAME, '').trim() || original\n let last = -1\n for (const m of base.matchAll(TITLE_SEPARATOR)) last = m.index ?? last\n const cleaned = last > 0 ? base.slice(0, last).trim() : base\n // Only accept the strip if something survives it, so a title that IS the\n // brand (\"Acme\") is left alone rather than reduced to nothing.\n if (!cleaned) return base\n if (brand && cleaned.toLowerCase() === brand.toLowerCase()) return base\n return cleaned\n}\n\n/**\n * `/services/walk-in-closets` -> `Walk In Closets`. The no-managed-data path.\n *\n * `*` segments (a dynamic route's card, `/services/*`) are skipped rather than\n * titled: one file covers every param, so the honest title is the section the\n * params belong to. Without this, an unmanaged dynamic segment rendered a card\n * whose headline was literally `*`.\n */\nexport function titleFromPath(path: string): string {\n const last = pathSegments(path).filter(s => s !== DYNAMIC).pop()\n if (!last) return 'Home'\n return last\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, c => c.toUpperCase())\n .trim()\n}\n\n/**\n * The kicker for a page card: its parent section, so a deep link reads\n * \"SERVICES / Walk In Closets\" rather than repeating the site name on every\n * card. Falls back to the base card's kicker at the top level.\n */\nexport function kickerFromPath(path: string, fallback?: string): string | undefined {\n const parts = pathSegments(path)\n // When the leaf is a `*`, the stars ARE the leaf, so the section is every\n // static segment — `/services/*` and `/services/*/*` both read \"services\",\n // never \"services / *\". A static leaf under a dynamic segment\n // (`/properties/*/about`) is the page itself, so the section is what's\n // above it, minus the stars: \"properties\".\n const section = (parts[parts.length - 1] === DYNAMIC ? parts : parts.slice(0, -1)).filter(\n s => s !== DYNAMIC,\n )\n if (!section.length) return fallback\n return section.join(' / ').replace(/[-_]+/g, ' ')\n}\n\n/**\n * Keep a card subtitle to two readable lines, never a full meta description.\n *\n * A meta description is written for a SERP row and runs to ~155 characters; at\n * card size that is four lines crowding the bottom bar. This trims to the first\n * sentence when there is one, and otherwise cuts on a word boundary.\n */\nexport function clampSubtitle(text: string | undefined, max = 100): string | undefined {\n if (!text) return undefined\n const flat = text.replace(/\\s+/g, ' ').trim()\n if (!flat) return undefined\n if (flat.length <= max) return flat\n\n // A whole sentence reads as written rather than as truncated. The floor is\n // absolute rather than a ratio of `max` (a ratio rejected a clean\n // 48-character sentence) — but not so low it accepts a stray \"Inc.\".\n const sentence = flat.slice(0, max + 1).match(/^.*[.!?](?=\\s|$)/)?.[0]\n if (sentence && sentence.length >= 30) return sentence.trim()\n\n /*\n * Otherwise: refuse.\n *\n * A managed description is 150+ characters of prose written for a SERP row,\n * and at card size NO truncation of it looks deliberate. Both attempts\n * proved it on real cards: a word cut gave \"across Cincinnati and…\", and\n * cutting at the last comma gave \"home offices designed, built\" — worse,\n * because with no ellipsis it looks complete and merely ungrammatical.\n *\n * Returning undefined lets the caller fall back to the site's own subtitle,\n * which is short, hand-written and always fits. A clean generic line beats a\n * mangled specific one, and the TITLE is already page-specific — which is\n * the signal that actually matters on a card.\n */\n return undefined\n}\n\n/**\n * Is the kicker already saying what the title says?\n *\n * Managed titles are written for search and usually carry the section and the\n * city, so the home page came out as kicker \"Custom Closets · Cincinnati\" above\n * title \"CUSTOM CLOSETS CINCINNATI TRI-STATE\" — a stutter that also cost a line\n * of the frame. When either contains the other, the title wins.\n */\nfunction kickerIsRedundant(kicker: string | undefined, title: string): boolean {\n if (!kicker) return false\n const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim()\n const k = norm(kicker)\n const t = norm(title)\n if (!k) return true\n if (t.includes(k) || k.includes(t)) return true\n // Or every word of the kicker already appears in the title.\n const titleWords = new Set(t.split(' '))\n return k.split(' ').every(w => titleWords.has(w))\n}\n\n/**\n * File-safe name for a route's card: `/services/garage` -> `services-garage`,\n * `/` -> `home`. Deterministic, so the generator and anything reading the\n * output agree without a manifest.\n *\n * A `*` (dynamic) segment becomes `any`, one per level: `/services/*` is\n * `services-any`, and a second dynamic level is `services-any-any`. The naive\n * punctuation strip collapsed every one of those to `services` — the SAME slug\n * as the real `/services` route — so a `cards` override keyed by slug could\n * silently land on the wrong card. (A literal `/services/any` route would still collide;\n * key those by path, which is always unambiguous.)\n */\nexport function slugForPath(path: string): string {\n const segments = pathSegments(path)\n if (!segments.length) return 'home'\n return segments\n .map(s => (s === DYNAMIC ? 'any' : s))\n .join('-')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .toLowerCase()\n}\n\n/**\n * The `cards` keys in og.config.ts that match none of the routes being\n * rendered.\n *\n * `pageCardConfig` looks an override up by exact path or exact slug and\n * silently derives the card when neither hits, so a mistyped or stale key — or\n * one written for a route shape the generator does not produce (a two-star\n * services pattern, before nested dynamic segments got their own key) — cost a\n * hand-written card with nothing said about it. The caller reports these.\n */\nexport function unmatchedCardKeys(\n cards: Record<string, unknown> | undefined,\n paths: string[],\n): string[] {\n if (!cards) return []\n const known = new Set(paths.flatMap(p => [p, slugForPath(p)]))\n const patterns = paths.filter(p => p.includes(DYNAMIC))\n return Object.keys(cards).filter(\n key => !known.has(key) && !patterns.some(pattern => matchesRoutePattern(key, pattern)),\n )\n}\n\n/** `/floor-plans/1-bedroom/` -> `/floor-plans/1-bedroom`. */\nfunction bareRoute(path: string): string {\n const segments = pathSegments(path)\n return segments.length ? `/${segments.join('/')}` : '/'\n}\n\n/**\n * Does a concrete URL fall under a dynamic route pattern? One `*` matches\n * exactly one segment: `/properties/tall-pines/about` is under\n * `/properties/*` + `/about`, and `/floor-plans/1-bedroom` under\n * `/floor-plans/*`. A key that is itself a pattern matches nothing.\n */\nexport function matchesRoutePattern(path: string, pattern: string): boolean {\n const concrete = pathSegments(path)\n const shape = pathSegments(pattern)\n if (concrete.includes(DYNAMIC) || concrete.length !== shape.length) return false\n return shape.every((seg, i) => seg === DYNAMIC || seg === concrete[i])\n}\n\n/**\n * The `cards` keys that name one page under a dynamic route: a card per\n * floor plan, per community, per sub-page of a community. Keyed by the URL\n * itself (`/floor-plans/1-bedroom`), which any site can build from the same\n * data its `generateStaticParams` reads.\n *\n * A static file in a dynamic segment covers every param of the route, so\n * these can't be `opengraph-image` files. `sonor-setup og` renders each one to\n * `public/_og/` (see paramCardUrl), and the page declares it with\n * `paramCardImage`. The MDG property sites needed a card per floor plan and\n * per community and rendered them with their own script until this existed.\n *\n * Returns each key with the pattern it falls under. Keys that are a real\n * static route or a pattern are left to the route cards.\n */\nexport function paramCardKeys(\n cards: Record<string, unknown> | undefined,\n paths: string[],\n): Array<{ path: string; pattern: string }> {\n if (!cards) return []\n const known = new Set(paths.flatMap(p => [p, slugForPath(p)]))\n const patterns = paths.filter(p => p.includes(DYNAMIC))\n const found: Array<{ path: string; pattern: string }> = []\n for (const key of Object.keys(cards)) {\n if (known.has(key) || !key.startsWith('/')) continue\n const pattern = patterns.find(p => matchesRoutePattern(key, p))\n if (pattern) found.push({ path: bareRoute(key), pattern })\n }\n return found\n}\n\n/**\n * Public directory (under `public/`) that `sonor-setup og` owns for per-URL\n * cards. Generated; the command clears it on every run, so keep nothing else\n * in it.\n */\nexport const PARAM_CARD_DIR = '_og'\n\n/**\n * Where the per-URL card for a page is served: `/floor-plans/1-bedroom` ->\n * `/_og/floor-plans/1-bedroom.jpg`. Single source of truth for the file the\n * CLI writes and the URL `paramCardImage` declares.\n *\n * It ends in `.jpg` on purpose. Next serves a code-based `opengraph-image`\n * route without an extension, and `trailingSlash: true` answers that URL with\n * a 308 before the card, which some preview bots don't follow. A static file\n * with an extension is never redirected.\n */\nexport function paramCardUrl(path: string): string {\n const segments = pathSegments(path)\n return `/${PARAM_CARD_DIR}/${segments.length ? segments.join('/') : 'home'}.jpg`\n}\n\n/** An `openGraph.images` entry. */\nexport interface OgImageDescriptor {\n url: string\n width: number\n height: number\n type: string\n alt?: string\n}\n\n/**\n * The page's per-URL card, for its metadata:\n *\n * ```ts\n * const card = paramCardImage(`/floor-plans/${slug}`, { config: ogConfig })\n * return {\n * openGraph: { ...(card && { images: [card] }) },\n * twitter: { card: 'summary_large_image', ...(card && { images: [card.url] }) },\n * }\n * ```\n *\n * Pass `config` (the site's og.config) and it answers undefined for a page\n * with no `cards` entry, so the page keeps its segment's static card. Without\n * `config` it always answers, so only call it for URLs you gave a card.\n */\nexport function paramCardImage(\n path: string,\n options: { config?: Pick<OgCardConfig, 'cards'>; alt?: string } = {},\n): OgImageDescriptor | undefined {\n if (options.config) {\n const bare = bareRoute(path)\n const cards = options.config.cards ?? {}\n if (!cards[bare] && !cards[`${bare}/`]) return undefined\n }\n return {\n url: paramCardUrl(path),\n width: OG_WIDTH,\n height: OG_HEIGHT,\n type: 'image/jpeg',\n ...(options.alt && { alt: options.alt }),\n }\n}\n\n/**\n * A code-based card (`opengraph-image.tsx`) declared at the URL the site\n * actually serves it from.\n *\n * Next wires such a card in as `<path>/opengraph-image`, with no extension.\n * With `trailingSlash: true` that URL 308-redirects to the slashed one, so\n * every share preview starts with a redirect, and bots that don't follow one\n * show no card (the MDG property sites, 2026-09-15). Declaring the slashed URL\n * gets a 200 first time. Declared images beat the file convention, so this\n * replaces Next's own entry rather than adding a second.\n *\n * `trailingSlash` defaults to the site's next.config. Without it, this is the\n * URL Next would have used anyway.\n */\nexport function codeCardImage(\n path: string,\n options: { trailingSlash?: boolean; alt?: string; contentType?: string } = {},\n): OgImageDescriptor {\n const base = bareRoute(path)\n const url = applyTrailingSlash(`${base === '/' ? '' : base}/opengraph-image`, resolveTrailingSlash(options.trailingSlash))\n return {\n url,\n width: OG_WIDTH,\n height: OG_HEIGHT,\n type: options.contentType ?? 'image/png',\n ...(options.alt && { alt: options.alt }),\n }\n}\n\n/**\n * Build a page's card config by layering its copy over the site's card.\n *\n * `cards` in og.config.ts wins over everything derived here, so a site can\n * hand-write the two or three cards that matter and let the rest be generated.\n */\nexport function pageCardConfig(\n base: OgCardConfig,\n route: OgPageRoute,\n brand?: string,\n): OgCardConfig {\n const override =\n base.cards?.[route.path] ?? base.cards?.[`${route.path}/`] ?? base.cards?.[slugForPath(route.path)]\n const isHome = route.path === '/'\n\n /*\n * The home page keeps the card the site actually wrote.\n *\n * og.config.ts `content` IS the home page's card — it is the one route whose\n * subject is the whole site, and it is hand-written. Deriving it from the\n * managed <title> instead replaced a crafted headline (\"Built by brothers\")\n * with the SEO string (\"Custom Closets Cincinnati Tri-State\"), which repeated\n * the kicker and ran to four lines. Every other route has no hand-written\n * card, so deriving is a clear gain there.\n */\n const derived: OgCardConfig = isHome\n ? { ...base, cards: undefined }\n : (() => {\n const title = route.title ? stripBrandSuffix(route.title, brand) : titleFromPath(route.path)\n const kicker = kickerFromPath(route.path, base.content.kicker)\n return {\n ...base,\n // `cards` is a build-time instruction, not part of a rendered card.\n cards: undefined,\n content: {\n ...base.content,\n kicker: kickerIsRedundant(kicker, title) ? undefined : kicker,\n title,\n subtitle: clampSubtitle(route.description) ?? base.content.subtitle,\n },\n }\n })()\n\n if (!override) return derived\n return {\n ...derived,\n ...override,\n content: { ...derived.content, ...override.content },\n }\n}\n"]}