@sonordev/site-kit 5.7.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 (604) hide show
  1. package/README.md +3 -3
  2. package/agent-manifest.json +14 -2
  3. package/dist/AnalyticsProvider-OCXRNIVE.js +33 -0
  4. package/dist/{AnalyticsProvider-GJFG7YXA.js.map → AnalyticsProvider-OCXRNIVE.js.map} +1 -1
  5. package/dist/AnalyticsProvider-ZAUONQCX.mjs +12 -0
  6. package/dist/{AnalyticsProvider-EWF7JN2X.mjs.map → AnalyticsProvider-ZAUONQCX.mjs.map} +1 -1
  7. package/dist/{BlogViewTracker-2D3IJPJK.js → BlogViewTracker-HK5C7PU6.js} +14 -11
  8. package/dist/BlogViewTracker-HK5C7PU6.js.map +1 -0
  9. package/dist/{BlogViewTracker-CKYG6MYU.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-AWP6GBVW.js.map → ChatWidget-3OW5LY37.js.map} +1 -1
  13. package/dist/ChatWidget-54GVS27I.mjs +15 -0
  14. package/dist/{ChatWidget-Z5QXDZP3.mjs.map → ChatWidget-54GVS27I.mjs.map} +1 -1
  15. package/dist/EngageWidget-7EUP76WE.mjs +12 -0
  16. package/dist/{EngageWidget-BKEY5TPO.mjs.map → EngageWidget-7EUP76WE.mjs.map} +1 -1
  17. package/dist/EngageWidget-DDP5UFA4.js +21 -0
  18. package/dist/{EngageWidget-VT4DYXVO.js.map → EngageWidget-DDP5UFA4.js.map} +1 -1
  19. package/dist/{FileField-JJN5QKDL.mjs → FileField-IQLN6E3C.mjs} +5 -5
  20. package/dist/{FileField-JJN5QKDL.mjs.map → FileField-IQLN6E3C.mjs.map} +1 -1
  21. package/dist/{FileField-62ZWZMQK.js → FileField-SBPL4JHP.js} +6 -6
  22. package/dist/{FileField-62ZWZMQK.js.map → FileField-SBPL4JHP.js.map} +1 -1
  23. package/dist/{FormSpotlight-OTFB6QM5.mjs → FormSpotlight-E2LKKHGV.mjs} +11 -7
  24. package/dist/FormSpotlight-E2LKKHGV.mjs.map +1 -0
  25. package/dist/{FormSpotlight-URS4XRS7.js → FormSpotlight-YTACNE57.js} +25 -21
  26. package/dist/FormSpotlight-YTACNE57.js.map +1 -0
  27. package/dist/{FormStage-FVKMIV73.js → FormStage-S277U2CP.js} +20 -15
  28. package/dist/FormStage-S277U2CP.js.map +1 -0
  29. package/dist/{FormStage-VPGOCMAV.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-CXVDJMHN.mjs.map → ManagedForm-I3QVRQ53.mjs.map} +1 -1
  33. package/dist/ManagedForm-TSYKQFLJ.js +25 -0
  34. package/dist/{ManagedForm-FGNTDGED.js.map → ManagedForm-TSYKQFLJ.js.map} +1 -1
  35. package/dist/{ManagedNewsletterForm-SQYB4BZU.mjs → ManagedNewsletterForm-T3YRAWKZ.mjs} +9 -7
  36. package/dist/ManagedNewsletterForm-T3YRAWKZ.mjs.map +1 -0
  37. package/dist/{ManagedNewsletterForm-3O5L44AZ.js → ManagedNewsletterForm-YSOPPKS6.js} +10 -8
  38. package/dist/ManagedNewsletterForm-YSOPPKS6.js.map +1 -0
  39. package/dist/{SignalCore-M2PKKIGH.mjs → SignalCore-PPSIQ4BW.mjs} +8 -14
  40. package/dist/SignalCore-PPSIQ4BW.mjs.map +1 -0
  41. package/dist/{SignalCore-RFBOBNLQ.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-4OVMIIGC.mjs.map → SitemapSync-HSHCOKCL.mjs.map} +1 -1
  45. package/dist/SitemapSync-LH6UVP4P.js +18 -0
  46. package/dist/{SitemapSync-RK3SQ4M2.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/not-found.test.d.ts +2 -0
  73. package/dist/blog/not-found.test.d.ts.map +1 -0
  74. package/dist/blog/processBlogHtml.d.ts +19 -2
  75. package/dist/blog/processBlogHtml.d.ts.map +1 -1
  76. package/dist/blog/public-reads.d.ts +27 -0
  77. package/dist/blog/public-reads.d.ts.map +1 -0
  78. package/dist/blog/server-core.d.ts +76 -10
  79. package/dist/blog/server-core.d.ts.map +1 -1
  80. package/dist/blog/server-ui.js +29 -23
  81. package/dist/blog/server-ui.js.map +1 -1
  82. package/dist/blog/server-ui.mjs +12 -6
  83. package/dist/blog/server-ui.mjs.map +1 -1
  84. package/dist/blog/server.d.ts +76 -10
  85. package/dist/blog/server.d.ts.map +1 -1
  86. package/dist/blog/server.js +54 -47
  87. package/dist/blog/server.mjs +5 -2
  88. package/dist/blog/site-scope.test.d.ts +2 -0
  89. package/dist/blog/site-scope.test.d.ts.map +1 -0
  90. package/dist/brand/extract-brand-profile.d.ts +36 -2
  91. package/dist/brand/extract-brand-profile.d.ts.map +1 -1
  92. package/dist/brand/extract-brand-profile.test.d.ts +2 -0
  93. package/dist/brand/extract-brand-profile.test.d.ts.map +1 -0
  94. package/dist/{chunk-3YQILJKJ.js → chunk-2FQG2AHJ.js} +60 -35
  95. package/dist/chunk-2FQG2AHJ.js.map +1 -0
  96. package/dist/{chunk-D553G64G.js → chunk-2OQWLXDO.js} +13 -13
  97. package/dist/{chunk-D553G64G.js.map → chunk-2OQWLXDO.js.map} +1 -1
  98. package/dist/{chunk-OYOO2OO5.js → chunk-2SCDUVFJ.js} +10 -10
  99. package/dist/{chunk-OYOO2OO5.js.map → chunk-2SCDUVFJ.js.map} +1 -1
  100. package/dist/{chunk-3S5JN6KL.js → chunk-35ERUUH3.js} +6 -6
  101. package/dist/{chunk-3S5JN6KL.js.map → chunk-35ERUUH3.js.map} +1 -1
  102. package/dist/{chunk-57AFHENV.mjs → chunk-3AUFD7KR.mjs} +3 -3
  103. package/dist/{chunk-57AFHENV.mjs.map → chunk-3AUFD7KR.mjs.map} +1 -1
  104. package/dist/{chunk-L7ACQ6PC.js → chunk-3BVCF4ZF.js} +4 -4
  105. package/dist/{chunk-L7ACQ6PC.js.map → chunk-3BVCF4ZF.js.map} +1 -1
  106. package/dist/{chunk-BFJOZ3MU.mjs → chunk-3EY5E35M.mjs} +36 -71
  107. package/dist/chunk-3EY5E35M.mjs.map +1 -0
  108. package/dist/{chunk-BQGEVMIR.mjs → chunk-3SLFT453.mjs} +5 -5
  109. package/dist/{chunk-BQGEVMIR.mjs.map → chunk-3SLFT453.mjs.map} +1 -1
  110. package/dist/{chunk-ILNCUSXW.mjs → chunk-4L7OHRWB.mjs} +12 -9
  111. package/dist/chunk-4L7OHRWB.mjs.map +1 -0
  112. package/dist/chunk-4LYW6PMU.mjs +72 -0
  113. package/dist/chunk-4LYW6PMU.mjs.map +1 -0
  114. package/dist/{chunk-TSZIACRC.js → chunk-4OS6M3V4.js} +6 -12
  115. package/dist/chunk-4OS6M3V4.js.map +1 -0
  116. package/dist/{chunk-YKUEFRZI.js → chunk-4RY7JETY.js} +14 -14
  117. package/dist/{chunk-YKUEFRZI.js.map → chunk-4RY7JETY.js.map} +1 -1
  118. package/dist/chunk-4TLFZ6NR.mjs +16 -0
  119. package/dist/chunk-4TLFZ6NR.mjs.map +1 -0
  120. package/dist/{chunk-4B4S56WJ.mjs → chunk-5B4J3IBX.mjs} +75 -21
  121. package/dist/chunk-5B4J3IBX.mjs.map +1 -0
  122. package/dist/chunk-5O7JSWT6.js +8 -0
  123. package/dist/{chunk-5TXXTYXL.js.map → chunk-5O7JSWT6.js.map} +1 -1
  124. package/dist/chunk-5SANRSX3.mjs +17 -0
  125. package/dist/chunk-5SANRSX3.mjs.map +1 -0
  126. package/dist/{chunk-FBDHKYNF.mjs → chunk-5WGMXSCB.mjs} +3 -3
  127. package/dist/{chunk-FBDHKYNF.mjs.map → chunk-5WGMXSCB.mjs.map} +1 -1
  128. package/dist/chunk-5XFFUP6D.js +100 -0
  129. package/dist/chunk-5XFFUP6D.js.map +1 -0
  130. package/dist/{chunk-7ZX6TO6C.mjs → chunk-6HFFTGFP.mjs} +50 -26
  131. package/dist/chunk-6HFFTGFP.mjs.map +1 -0
  132. package/dist/{chunk-R2SXXFXZ.mjs → chunk-6SBTHS6C.mjs} +3 -3
  133. package/dist/{chunk-R2SXXFXZ.mjs.map → chunk-6SBTHS6C.mjs.map} +1 -1
  134. package/dist/{chunk-FO4KGPGF.js → chunk-7TC3GRXQ.js} +73 -38
  135. package/dist/chunk-7TC3GRXQ.js.map +1 -0
  136. package/dist/{chunk-XLPU3TEE.mjs → chunk-7THZOAUR.mjs} +4 -4
  137. package/dist/{chunk-XLPU3TEE.mjs.map → chunk-7THZOAUR.mjs.map} +1 -1
  138. package/dist/{chunk-MW2M6O7A.mjs → chunk-AOWJP25J.mjs} +4 -4
  139. package/dist/{chunk-MW2M6O7A.mjs.map → chunk-AOWJP25J.mjs.map} +1 -1
  140. package/dist/{chunk-UQ5YULFU.mjs → chunk-B2VFMPVJ.mjs} +4 -4
  141. package/dist/{chunk-UQ5YULFU.mjs.map → chunk-B2VFMPVJ.mjs.map} +1 -1
  142. package/dist/{chunk-JTF4DFUF.mjs → chunk-B35OJ7FR.mjs} +4 -4
  143. package/dist/{chunk-JTF4DFUF.mjs.map → chunk-B35OJ7FR.mjs.map} +1 -1
  144. package/dist/{chunk-2N27LCZH.js → chunk-BER36QXU.js} +9 -9
  145. package/dist/{chunk-2N27LCZH.js.map → chunk-BER36QXU.js.map} +1 -1
  146. package/dist/{chunk-47XQWV4S.mjs → chunk-BFZNLTWK.mjs} +3 -3
  147. package/dist/{chunk-47XQWV4S.mjs.map → chunk-BFZNLTWK.mjs.map} +1 -1
  148. package/dist/chunk-BQP6JIE2.mjs +28 -0
  149. package/dist/chunk-BQP6JIE2.mjs.map +1 -0
  150. package/dist/{chunk-KXGD4E7G.js → chunk-C3WU45JT.js} +7 -7
  151. package/dist/{chunk-KXGD4E7G.js.map → chunk-C3WU45JT.js.map} +1 -1
  152. package/dist/chunk-CUNZAD46.js +53 -0
  153. package/dist/chunk-CUNZAD46.js.map +1 -0
  154. package/dist/chunk-CXAXZFFW.js +157 -0
  155. package/dist/chunk-CXAXZFFW.js.map +1 -0
  156. package/dist/{chunk-H4OBGC43.mjs → chunk-DA7IANFG.mjs} +14 -3
  157. package/dist/chunk-DA7IANFG.mjs.map +1 -0
  158. package/dist/{chunk-NOU3JQJK.js → chunk-EIW6YEPY.js} +8 -8
  159. package/dist/{chunk-NOU3JQJK.js.map → chunk-EIW6YEPY.js.map} +1 -1
  160. package/dist/{chunk-RCSTDJUH.js → chunk-F6SKG34N.js} +8 -13
  161. package/dist/chunk-F6SKG34N.js.map +1 -0
  162. package/dist/{chunk-LC7AM4J5.js → chunk-FHPW7XVH.js} +77 -20
  163. package/dist/chunk-FHPW7XVH.js.map +1 -0
  164. package/dist/{chunk-JNRHTZL4.js → chunk-FVW6FT6L.js} +73 -29
  165. package/dist/chunk-FVW6FT6L.js.map +1 -0
  166. package/dist/{chunk-BFM5PEFV.js → chunk-GNDWTXLU.js} +56 -177
  167. package/dist/chunk-GNDWTXLU.js.map +1 -0
  168. package/dist/{chunk-OZ3FU4BT.js → chunk-H5NBFNND.js} +2 -2
  169. package/dist/chunk-H5NBFNND.js.map +1 -0
  170. package/dist/{chunk-RNAGCAIB.js → chunk-HAKD27AZ.js} +7 -7
  171. package/dist/{chunk-RNAGCAIB.js.map → chunk-HAKD27AZ.js.map} +1 -1
  172. package/dist/chunk-HCN3IKMW.mjs +106 -0
  173. package/dist/chunk-HCN3IKMW.mjs.map +1 -0
  174. package/dist/{chunk-V5THCFPG.mjs → chunk-HCX343AS.mjs} +4 -4
  175. package/dist/{chunk-V5THCFPG.mjs.map → chunk-HCX343AS.mjs.map} +1 -1
  176. package/dist/{chunk-TDJKGN5Q.mjs → chunk-HEOQT5SM.mjs} +216 -103
  177. package/dist/chunk-HEOQT5SM.mjs.map +1 -0
  178. package/dist/{chunk-6FC5Q4KU.mjs → chunk-HOJ4J4X2.mjs} +30 -12
  179. package/dist/chunk-HOJ4J4X2.mjs.map +1 -0
  180. package/dist/{chunk-ELQ4SRRR.js → chunk-HQOHB6QF.js} +15 -15
  181. package/dist/{chunk-ELQ4SRRR.js.map → chunk-HQOHB6QF.js.map} +1 -1
  182. package/dist/chunk-HRMGITUZ.mjs +6 -0
  183. package/dist/{chunk-QRBPT6Z6.mjs.map → chunk-HRMGITUZ.mjs.map} +1 -1
  184. package/dist/{chunk-JQ7M6CVL.mjs → chunk-HYVEIP2N.mjs} +3 -3
  185. package/dist/{chunk-JQ7M6CVL.mjs.map → chunk-HYVEIP2N.mjs.map} +1 -1
  186. package/dist/{chunk-H6YVT3BL.js → chunk-I3ND4XYW.js} +12 -9
  187. package/dist/chunk-I3ND4XYW.js.map +1 -0
  188. package/dist/{chunk-4UVM7E2W.js → chunk-JDTU2RWC.js} +3 -3
  189. package/dist/{chunk-4UVM7E2W.js.map → chunk-JDTU2RWC.js.map} +1 -1
  190. package/dist/{chunk-GZJE23Y5.mjs → chunk-JLVCWC6A.mjs} +2 -2
  191. package/dist/chunk-JLVCWC6A.mjs.map +1 -0
  192. package/dist/chunk-K4TCEAUX.js +52 -0
  193. package/dist/chunk-K4TCEAUX.js.map +1 -0
  194. package/dist/chunk-KV7XXLJV.mjs +30 -0
  195. package/dist/chunk-KV7XXLJV.mjs.map +1 -0
  196. package/dist/{chunk-C563AHZZ.mjs → chunk-L24RDT6Q.mjs} +3 -3
  197. package/dist/{chunk-C563AHZZ.mjs.map → chunk-L24RDT6Q.mjs.map} +1 -1
  198. package/dist/{chunk-FEWWGEQF.js → chunk-LBZGYF3B.js} +4 -4
  199. package/dist/{chunk-FEWWGEQF.js.map → chunk-LBZGYF3B.js.map} +1 -1
  200. package/dist/{chunk-CPY74A4F.js → chunk-LMEUYRRR.js} +72 -106
  201. package/dist/chunk-LMEUYRRR.js.map +1 -0
  202. package/dist/chunk-LVGSOW2F.js +32 -0
  203. package/dist/chunk-LVGSOW2F.js.map +1 -0
  204. package/dist/{chunk-DOB37PV4.js → chunk-M45AL7EA.js} +37 -19
  205. package/dist/chunk-M45AL7EA.js.map +1 -0
  206. package/dist/{chunk-YYDZ2TYR.js → chunk-MHX6TOAS.js} +3 -3
  207. package/dist/{chunk-YYDZ2TYR.js.map → chunk-MHX6TOAS.js.map} +1 -1
  208. package/dist/chunk-MLVHVKFT.mjs +148 -0
  209. package/dist/chunk-MLVHVKFT.mjs.map +1 -0
  210. package/dist/{chunk-M5GY2AI3.mjs → chunk-N2NZBPQ5.mjs} +4 -10
  211. package/dist/chunk-N2NZBPQ5.mjs.map +1 -0
  212. package/dist/chunk-NRBITVDK.js +114 -0
  213. package/dist/chunk-NRBITVDK.js.map +1 -0
  214. package/dist/{chunk-O2VJZOR2.mjs → chunk-O4YBWJHP.mjs} +6 -11
  215. package/dist/chunk-O4YBWJHP.mjs.map +1 -0
  216. package/dist/{chunk-BUJWXSYZ.mjs → chunk-O5ZSGBQD.mjs} +4 -4
  217. package/dist/{chunk-BUJWXSYZ.mjs.map → chunk-O5ZSGBQD.mjs.map} +1 -1
  218. package/dist/{chunk-TP7H6BSK.mjs → chunk-OE7CTIOU.mjs} +73 -30
  219. package/dist/chunk-OE7CTIOU.mjs.map +1 -0
  220. package/dist/{chunk-UJ6CHZAI.mjs → chunk-OEW2LFOV.js} +169 -25
  221. package/dist/chunk-OEW2LFOV.js.map +1 -0
  222. package/dist/chunk-P4Y75QSU.js +19 -0
  223. package/dist/chunk-P4Y75QSU.js.map +1 -0
  224. package/dist/{chunk-Q7347KP6.mjs → chunk-PK2OTGW5.mjs} +6 -12
  225. package/dist/chunk-PK2OTGW5.mjs.map +1 -0
  226. package/dist/{chunk-H65OX263.js → chunk-PRTXAIIC.js} +15 -15
  227. package/dist/{chunk-H65OX263.js.map → chunk-PRTXAIIC.js.map} +1 -1
  228. package/dist/{chunk-ABZGEHTC.mjs → chunk-PUAXHYBL.mjs} +3 -3
  229. package/dist/{chunk-ABZGEHTC.mjs.map → chunk-PUAXHYBL.mjs.map} +1 -1
  230. package/dist/chunk-QRHVMTHF.mjs +94 -0
  231. package/dist/chunk-QRHVMTHF.mjs.map +1 -0
  232. package/dist/{chunk-JTCQJKJE.js → chunk-QTJTDQYR.js} +76 -111
  233. package/dist/chunk-QTJTDQYR.js.map +1 -0
  234. package/dist/{chunk-HBN4A2N4.mjs → chunk-QVHVL7EX.mjs} +3 -3
  235. package/dist/{chunk-HBN4A2N4.mjs.map → chunk-QVHVL7EX.mjs.map} +1 -1
  236. package/dist/chunk-R7GHP3FY.js +81 -0
  237. package/dist/chunk-R7GHP3FY.js.map +1 -0
  238. package/dist/{chunk-P4TB4ROG.js → chunk-SEP5D4MI.js} +8 -2
  239. package/dist/chunk-SEP5D4MI.js.map +1 -0
  240. package/dist/{chunk-3CLP35TT.mjs → chunk-TXMVU4EY.mjs} +62 -97
  241. package/dist/chunk-TXMVU4EY.mjs.map +1 -0
  242. package/dist/{chunk-L4V6TKMJ.mjs → chunk-U2V542EO.mjs} +7 -3
  243. package/dist/chunk-U2V542EO.mjs.map +1 -0
  244. package/dist/{chunk-4WBTM6YE.js → chunk-UWHCHYCX.js} +4 -4
  245. package/dist/{chunk-4WBTM6YE.js.map → chunk-UWHCHYCX.js.map} +1 -1
  246. package/dist/{chunk-JNAXDFC4.mjs → chunk-VJ74275U.mjs} +38 -156
  247. package/dist/chunk-VJ74275U.mjs.map +1 -0
  248. package/dist/{chunk-H7274TKR.mjs → chunk-VJV7WUR2.mjs} +12 -4
  249. package/dist/chunk-VJV7WUR2.mjs.map +1 -0
  250. package/dist/{chunk-4A5V73SR.mjs → chunk-VYL6IHJA.mjs} +9 -9
  251. package/dist/{chunk-4A5V73SR.mjs.map → chunk-VYL6IHJA.mjs.map} +1 -1
  252. package/dist/{chunk-5B4FABFK.js → chunk-WS7MH3GD.js} +14 -2
  253. package/dist/chunk-WS7MH3GD.js.map +1 -0
  254. package/dist/{chunk-IPV2TUAT.js → chunk-XA2GJFVM.js} +12 -4
  255. package/dist/chunk-XA2GJFVM.js.map +1 -0
  256. package/dist/chunk-XBX2K3GA.js +33 -0
  257. package/dist/chunk-XBX2K3GA.js.map +1 -0
  258. package/dist/{chunk-F3AKYZOH.js → chunk-XCYKM2SA.js} +6 -13
  259. package/dist/chunk-XCYKM2SA.js.map +1 -0
  260. package/dist/{chunk-6CJP7BFM.js → chunk-XZO5I4RS.mjs} +147 -20
  261. package/dist/chunk-XZO5I4RS.mjs.map +1 -0
  262. package/dist/chunk-Y5QZPUL3.mjs +47 -0
  263. package/dist/chunk-Y5QZPUL3.mjs.map +1 -0
  264. package/dist/{chunk-C4PZ2R3B.js → chunk-YECDJDDD.js} +10 -10
  265. package/dist/{chunk-C4PZ2R3B.js.map → chunk-YECDJDDD.js.map} +1 -1
  266. package/dist/chunk-YN7QHLWF.js +19 -0
  267. package/dist/chunk-YN7QHLWF.js.map +1 -0
  268. package/dist/chunk-YU7QZ3PP.mjs +45 -0
  269. package/dist/chunk-YU7QZ3PP.mjs.map +1 -0
  270. package/dist/{chunk-VFGEY6FJ.js → chunk-ZEOC26LZ.js} +223 -110
  271. package/dist/chunk-ZEOC26LZ.js.map +1 -0
  272. package/dist/{chunk-RVRN5U7W.mjs → chunk-ZVI7MBVF.mjs} +73 -38
  273. package/dist/chunk-ZVI7MBVF.mjs.map +1 -0
  274. package/dist/cli/agent/checks.d.ts +15 -1
  275. package/dist/cli/agent/checks.d.ts.map +1 -1
  276. package/dist/cli/agent/sitemap-trailing-slash.test.d.ts +2 -0
  277. package/dist/cli/agent/sitemap-trailing-slash.test.d.ts.map +1 -0
  278. package/dist/cli/commands/doctor.d.ts.map +1 -1
  279. package/dist/cli/commands/og.d.ts +26 -8
  280. package/dist/cli/commands/og.d.ts.map +1 -1
  281. package/dist/cli/index.js +683 -322
  282. package/dist/cli/index.js.map +1 -1
  283. package/dist/cli/index.mjs +604 -243
  284. package/dist/cli/index.mjs.map +1 -1
  285. package/dist/client/index.js +6 -6
  286. package/dist/client/index.mjs +5 -5
  287. package/dist/commerce/CheckoutForm.d.ts.map +1 -1
  288. package/dist/commerce/ProductDetail.d.ts.map +1 -1
  289. package/dist/commerce/api.d.ts +14 -0
  290. package/dist/commerce/api.d.ts.map +1 -1
  291. package/dist/commerce/discount-checkout.test.d.ts +2 -0
  292. package/dist/commerce/discount-checkout.test.d.ts.map +1 -0
  293. package/dist/commerce/index.d.ts +1 -1
  294. package/dist/commerce/index.d.ts.map +1 -1
  295. package/dist/commerce/index.js +61 -56
  296. package/dist/commerce/index.mjs +6 -5
  297. package/dist/config/index.js +3 -3
  298. package/dist/config/index.mjs +1 -1
  299. package/dist/discover-CYXYKHZ2.mjs +4 -0
  300. package/dist/{discover-FGTKWOL3.mjs.map → discover-CYXYKHZ2.mjs.map} +1 -1
  301. package/dist/discover-NGEPXZOD.js +21 -0
  302. package/dist/{discover-NJZPWTDL.js.map → discover-NGEPXZOD.js.map} +1 -1
  303. package/dist/engage/index.js +12 -10
  304. package/dist/engage/index.js.map +1 -1
  305. package/dist/engage/index.mjs +9 -7
  306. package/dist/engage/index.mjs.map +1 -1
  307. package/dist/fleet/index.js +8 -8
  308. package/dist/fleet/index.mjs +4 -4
  309. package/dist/forms/FormClient.d.ts.map +1 -1
  310. package/dist/forms/FormField.d.ts +7 -1
  311. package/dist/forms/FormField.d.ts.map +1 -1
  312. package/dist/forms/FormSpotlight.d.ts +1 -1
  313. package/dist/forms/FormSpotlight.d.ts.map +1 -1
  314. package/dist/forms/FormStage.d.ts +1 -1
  315. package/dist/forms/FormStage.d.ts.map +1 -1
  316. package/dist/forms/experience-plan.d.ts +0 -1
  317. package/dist/forms/experience-plan.d.ts.map +1 -1
  318. package/dist/forms/field-interactions.d.ts +63 -0
  319. package/dist/forms/field-interactions.d.ts.map +1 -0
  320. package/dist/forms/field-interactions.test.d.ts +8 -0
  321. package/dist/forms/field-interactions.test.d.ts.map +1 -0
  322. package/dist/forms/field-rules.d.ts +41 -0
  323. package/dist/forms/field-rules.d.ts.map +1 -0
  324. package/dist/forms/field-rules.test.d.ts +8 -0
  325. package/dist/forms/field-rules.test.d.ts.map +1 -0
  326. package/dist/forms/form-field-focus.test.d.ts +8 -0
  327. package/dist/forms/form-field-focus.test.d.ts.map +1 -0
  328. package/dist/forms/index.js +25 -23
  329. package/dist/forms/index.js.map +1 -1
  330. package/dist/forms/index.mjs +13 -11
  331. package/dist/forms/index.mjs.map +1 -1
  332. package/dist/forms/server.js +11 -11
  333. package/dist/forms/server.mjs +9 -9
  334. package/dist/forms/static.js +8 -8
  335. package/dist/forms/static.mjs +7 -7
  336. package/dist/forms/tracking-session.d.ts +48 -3
  337. package/dist/forms/tracking-session.d.ts.map +1 -1
  338. package/dist/forms/types.d.ts +11 -0
  339. package/dist/forms/types.d.ts.map +1 -1
  340. package/dist/forms/useForm.d.ts +8 -0
  341. package/dist/forms/useForm.d.ts.map +1 -1
  342. package/dist/forms/useFormTracking.d.ts +29 -4
  343. package/dist/forms/useFormTracking.d.ts.map +1 -1
  344. package/dist/images/index.js +11 -11
  345. package/dist/images/index.mjs +4 -4
  346. package/dist/index.js +72 -68
  347. package/dist/index.js.map +1 -1
  348. package/dist/index.mjs +14 -10
  349. package/dist/index.mjs.map +1 -1
  350. package/dist/layout/client.js +10 -10
  351. package/dist/layout/client.mjs +9 -9
  352. package/dist/layout/index.js +13 -12
  353. package/dist/layout/index.js.map +1 -1
  354. package/dist/layout/index.mjs +11 -10
  355. package/dist/layout/index.mjs.map +1 -1
  356. package/dist/llms/aiRobots.d.ts +20 -4
  357. package/dist/llms/aiRobots.d.ts.map +1 -1
  358. package/dist/llms/api.d.ts +8 -3
  359. package/dist/llms/api.d.ts.map +1 -1
  360. package/dist/llms/discovery-headers.d.ts +24 -0
  361. package/dist/llms/discovery-headers.d.ts.map +1 -1
  362. package/dist/llms/generateLLMsTxt.d.ts.map +1 -1
  363. package/dist/llms/index.d.ts +2 -2
  364. package/dist/llms/index.d.ts.map +1 -1
  365. package/dist/llms/index.js +45 -96
  366. package/dist/llms/index.js.map +1 -1
  367. package/dist/llms/index.mjs +11 -81
  368. package/dist/llms/index.mjs.map +1 -1
  369. package/dist/llms/links.d.ts +26 -0
  370. package/dist/llms/links.d.ts.map +1 -0
  371. package/dist/llms/links.test.d.ts +2 -0
  372. package/dist/llms/links.test.d.ts.map +1 -0
  373. package/dist/llms/types.d.ts +15 -0
  374. package/dist/llms/types.d.ts.map +1 -1
  375. package/dist/llms/wiring.d.ts +22 -0
  376. package/dist/llms/wiring.d.ts.map +1 -1
  377. package/dist/llms/writeLLMsTxt.d.ts +9 -0
  378. package/dist/llms/writeLLMsTxt.d.ts.map +1 -1
  379. package/dist/maps/index.js +5 -5
  380. package/dist/maps/index.mjs +3 -3
  381. package/dist/motion/gsap.d.ts +54 -0
  382. package/dist/motion/gsap.d.ts.map +1 -1
  383. package/dist/motion/gsap.js +34 -4
  384. package/dist/motion/gsap.js.map +1 -1
  385. package/dist/motion/gsap.mjs +33 -5
  386. package/dist/motion/gsap.mjs.map +1 -1
  387. package/dist/motion/gsap.test.d.ts +2 -0
  388. package/dist/motion/gsap.test.d.ts.map +1 -0
  389. package/dist/og/config.d.ts +6 -0
  390. package/dist/og/config.d.ts.map +1 -1
  391. package/dist/og/contrast.d.ts +33 -0
  392. package/dist/og/contrast.d.ts.map +1 -0
  393. package/dist/og/index.d.ts +2 -0
  394. package/dist/og/index.d.ts.map +1 -1
  395. package/dist/og/index.js +26 -8
  396. package/dist/og/index.mjs +3 -1
  397. package/dist/og/pages.d.ts +101 -0
  398. package/dist/og/pages.d.ts.map +1 -1
  399. package/dist/og/route-copy.d.ts +34 -0
  400. package/dist/og/route-copy.d.ts.map +1 -0
  401. package/dist/og/route-fit.d.ts +77 -0
  402. package/dist/og/route-fit.d.ts.map +1 -0
  403. package/dist/og/route.d.ts +80 -20
  404. package/dist/og/route.d.ts.map +1 -1
  405. package/dist/og/route.js +195 -25
  406. package/dist/og/route.js.map +1 -1
  407. package/dist/og/route.mjs +193 -26
  408. package/dist/og/route.mjs.map +1 -1
  409. package/dist/og/route.test.d.ts +2 -0
  410. package/dist/og/route.test.d.ts.map +1 -0
  411. package/dist/og/template.d.ts.map +1 -1
  412. package/dist/og/wiring.d.ts +43 -3
  413. package/dist/og/wiring.d.ts.map +1 -1
  414. package/dist/proxy/index.d.ts.map +1 -1
  415. package/dist/proxy/index.js +15 -10
  416. package/dist/proxy/index.js.map +1 -1
  417. package/dist/proxy/index.mjs +12 -7
  418. package/dist/proxy/index.mjs.map +1 -1
  419. package/dist/proxy/llms-discovery.test.d.ts +2 -0
  420. package/dist/proxy/llms-discovery.test.d.ts.map +1 -0
  421. package/dist/redirects/index.d.ts +24 -0
  422. package/dist/redirects/index.d.ts.map +1 -1
  423. package/dist/redirects/index.js +11 -8
  424. package/dist/redirects/index.mjs +4 -1
  425. package/dist/redirects/index.test.d.ts +2 -0
  426. package/dist/redirects/index.test.d.ts.map +1 -0
  427. package/dist/redirects/not-found.js +8 -5
  428. package/dist/redirects/not-found.js.map +1 -1
  429. package/dist/redirects/not-found.mjs +4 -1
  430. package/dist/redirects/not-found.mjs.map +1 -1
  431. package/dist/robots/index.d.ts +2 -0
  432. package/dist/robots/index.d.ts.map +1 -1
  433. package/dist/robots/index.js +23 -3
  434. package/dist/robots/index.js.map +1 -1
  435. package/dist/robots/index.mjs +2 -2
  436. package/dist/robots/index.mjs.map +1 -1
  437. package/dist/search/index.js +4 -4
  438. package/dist/search/index.mjs +3 -3
  439. package/dist/seo/ManagedContent.d.ts +4 -2
  440. package/dist/seo/ManagedContent.d.ts.map +1 -1
  441. package/dist/seo/ManagedFAQ.d.ts.map +1 -1
  442. package/dist/seo/ManagedInternalLinks.d.ts.map +1 -1
  443. package/dist/seo/ManagedSchema.d.ts.map +1 -1
  444. package/dist/seo/client.js +6 -6
  445. package/dist/seo/client.mjs +5 -5
  446. package/dist/seo/getManagedMetadata.d.ts.map +1 -1
  447. package/dist/seo/getManagedMetadata.test.d.ts +2 -0
  448. package/dist/seo/getManagedMetadata.test.d.ts.map +1 -0
  449. package/dist/seo/index.js +59 -49
  450. package/dist/seo/index.js.map +1 -1
  451. package/dist/seo/index.mjs +29 -19
  452. package/dist/seo/index.mjs.map +1 -1
  453. package/dist/seo/managed-schema-filter.test.d.ts +2 -0
  454. package/dist/seo/managed-schema-filter.test.d.ts.map +1 -0
  455. package/dist/seo/register-sitemap-cli-impl.d.ts +32 -0
  456. package/dist/seo/register-sitemap-cli-impl.d.ts.map +1 -1
  457. package/dist/seo/register-sitemap-cli.d.ts +7 -0
  458. package/dist/seo/register-sitemap-cli.d.ts.map +1 -1
  459. package/dist/seo/register-sitemap-cli.js +273 -56
  460. package/dist/seo/register-sitemap-cli.js.map +1 -1
  461. package/dist/seo/register-sitemap-cli.mjs +269 -52
  462. package/dist/seo/register-sitemap-cli.mjs.map +1 -1
  463. package/dist/seo/register-sitemap-request.d.ts +36 -0
  464. package/dist/seo/register-sitemap-request.d.ts.map +1 -0
  465. package/dist/seo/register-sitemap-request.test.d.ts +2 -0
  466. package/dist/seo/register-sitemap-request.test.d.ts.map +1 -0
  467. package/dist/seo/routing.d.ts +2 -0
  468. package/dist/seo/routing.d.ts.map +1 -1
  469. package/dist/seo/schema-filter.d.ts +43 -0
  470. package/dist/seo/schema-filter.d.ts.map +1 -0
  471. package/dist/seo/schema-filter.test.d.ts +2 -0
  472. package/dist/seo/schema-filter.test.d.ts.map +1 -0
  473. package/dist/seo/server-api.d.ts +15 -2
  474. package/dist/seo/server-api.d.ts.map +1 -1
  475. package/dist/seo/server.js +23 -18
  476. package/dist/seo/server.mjs +7 -2
  477. package/dist/seo/site-scope.test.d.ts +2 -0
  478. package/dist/seo/site-scope.test.d.ts.map +1 -0
  479. package/dist/seo/types.d.ts +30 -0
  480. package/dist/seo/types.d.ts.map +1 -1
  481. package/dist/seo-meta/contract.d.ts +60 -0
  482. package/dist/seo-meta/contract.d.ts.map +1 -0
  483. package/dist/seo-meta/contract.js +41 -0
  484. package/dist/seo-meta/contract.js.map +1 -0
  485. package/dist/seo-meta/contract.mjs +4 -0
  486. package/dist/seo-meta/contract.mjs.map +1 -0
  487. package/dist/seo-meta/contract.test.d.ts +2 -0
  488. package/dist/seo-meta/contract.test.d.ts.map +1 -0
  489. package/dist/server/index.js +4 -3
  490. package/dist/server/index.mjs +3 -2
  491. package/dist/server/mint-site-token.d.ts +2 -32
  492. package/dist/server/mint-site-token.d.ts.map +1 -1
  493. package/dist/{server-api-RG3ZL3DV.mjs → server-api-A2EFCTZX.mjs} +7 -3
  494. package/dist/{server-api-RG3ZL3DV.mjs.map → server-api-A2EFCTZX.mjs.map} +1 -1
  495. package/dist/{server-api-RYJQAUGO.js → server-api-IWTZ7C3O.js} +25 -21
  496. package/dist/{server-api-RYJQAUGO.js.map → server-api-IWTZ7C3O.js.map} +1 -1
  497. package/dist/shared/build-entries.d.ts +2 -0
  498. package/dist/shared/build-entries.d.ts.map +1 -1
  499. package/dist/shared/fresh-fetch.d.ts +64 -0
  500. package/dist/shared/fresh-fetch.d.ts.map +1 -0
  501. package/dist/shared/fresh-fetch.test.d.ts +2 -0
  502. package/dist/shared/fresh-fetch.test.d.ts.map +1 -0
  503. package/dist/shared/next-files.d.ts +7 -0
  504. package/dist/shared/next-files.d.ts.map +1 -1
  505. package/dist/shared/page-leave.d.ts +27 -0
  506. package/dist/shared/page-leave.d.ts.map +1 -0
  507. package/dist/shared/page-leave.test.d.ts +2 -0
  508. package/dist/shared/page-leave.test.d.ts.map +1 -0
  509. package/dist/shared/source-graph.d.ts +63 -0
  510. package/dist/shared/source-graph.d.ts.map +1 -0
  511. package/dist/shared/source-graph.test.d.ts +2 -0
  512. package/dist/shared/source-graph.test.d.ts.map +1 -0
  513. package/dist/shared/version.d.ts +1 -1
  514. package/dist/signal/SignalCore.d.ts.map +1 -1
  515. package/dist/signal/index.js +11 -11
  516. package/dist/signal/index.mjs +2 -2
  517. package/dist/sitemap/index.d.ts +19 -4
  518. package/dist/sitemap/index.d.ts.map +1 -1
  519. package/dist/sitemap/index.js +53 -43
  520. package/dist/sitemap/index.js.map +1 -1
  521. package/dist/sitemap/index.mjs +37 -27
  522. package/dist/sitemap/index.mjs.map +1 -1
  523. package/dist/sitemap/shared.d.ts +65 -0
  524. package/dist/sitemap/shared.d.ts.map +1 -1
  525. package/dist/sitemap/trailing-slash.test.d.ts +2 -0
  526. package/dist/sitemap/trailing-slash.test.d.ts.map +1 -0
  527. package/dist/sites/resolve.d.ts.map +1 -1
  528. package/dist/sites/site-param.d.ts +16 -0
  529. package/dist/sites/site-param.d.ts.map +1 -0
  530. package/dist/sync/index.js +17 -17
  531. package/dist/sync/index.mjs +4 -4
  532. package/dist/writeLLMsTxt-CQ7A4AAL.js +20 -0
  533. package/dist/writeLLMsTxt-CQ7A4AAL.js.map +1 -0
  534. package/dist/writeLLMsTxt-NX5MSPYX.mjs +11 -0
  535. package/dist/writeLLMsTxt-NX5MSPYX.mjs.map +1 -0
  536. package/package.json +8 -3
  537. package/dist/AnalyticsProvider-EWF7JN2X.mjs +0 -11
  538. package/dist/AnalyticsProvider-GJFG7YXA.js +0 -32
  539. package/dist/BlogViewTracker-2D3IJPJK.js.map +0 -1
  540. package/dist/BlogViewTracker-CKYG6MYU.mjs.map +0 -1
  541. package/dist/ChatWidget-AWP6GBVW.js +0 -22
  542. package/dist/ChatWidget-Z5QXDZP3.mjs +0 -13
  543. package/dist/EngageWidget-BKEY5TPO.mjs +0 -12
  544. package/dist/EngageWidget-VT4DYXVO.js +0 -21
  545. package/dist/FormSpotlight-OTFB6QM5.mjs.map +0 -1
  546. package/dist/FormSpotlight-URS4XRS7.js.map +0 -1
  547. package/dist/FormStage-FVKMIV73.js.map +0 -1
  548. package/dist/FormStage-VPGOCMAV.mjs.map +0 -1
  549. package/dist/ManagedForm-CXVDJMHN.mjs +0 -14
  550. package/dist/ManagedForm-FGNTDGED.js +0 -23
  551. package/dist/ManagedNewsletterForm-3O5L44AZ.js.map +0 -1
  552. package/dist/ManagedNewsletterForm-SQYB4BZU.mjs.map +0 -1
  553. package/dist/SignalCore-M2PKKIGH.mjs.map +0 -1
  554. package/dist/SignalCore-RFBOBNLQ.js.map +0 -1
  555. package/dist/SitemapSync-4OVMIIGC.mjs +0 -9
  556. package/dist/SitemapSync-RK3SQ4M2.js +0 -18
  557. package/dist/chunk-3CLP35TT.mjs.map +0 -1
  558. package/dist/chunk-3UC6JETG.js +0 -32
  559. package/dist/chunk-3UC6JETG.js.map +0 -1
  560. package/dist/chunk-3YQILJKJ.js.map +0 -1
  561. package/dist/chunk-4B4S56WJ.mjs.map +0 -1
  562. package/dist/chunk-5B4FABFK.js.map +0 -1
  563. package/dist/chunk-5TXXTYXL.js +0 -8
  564. package/dist/chunk-6CJP7BFM.js.map +0 -1
  565. package/dist/chunk-6FC5Q4KU.mjs.map +0 -1
  566. package/dist/chunk-7ZX6TO6C.mjs.map +0 -1
  567. package/dist/chunk-AWK57R5S.mjs +0 -29
  568. package/dist/chunk-AWK57R5S.mjs.map +0 -1
  569. package/dist/chunk-BFJOZ3MU.mjs.map +0 -1
  570. package/dist/chunk-BFM5PEFV.js.map +0 -1
  571. package/dist/chunk-CPY74A4F.js.map +0 -1
  572. package/dist/chunk-DOB37PV4.js.map +0 -1
  573. package/dist/chunk-F3AKYZOH.js.map +0 -1
  574. package/dist/chunk-FO4KGPGF.js.map +0 -1
  575. package/dist/chunk-GZJE23Y5.mjs.map +0 -1
  576. package/dist/chunk-H4OBGC43.mjs.map +0 -1
  577. package/dist/chunk-H6YVT3BL.js.map +0 -1
  578. package/dist/chunk-H7274TKR.mjs.map +0 -1
  579. package/dist/chunk-ILNCUSXW.mjs.map +0 -1
  580. package/dist/chunk-IPV2TUAT.js.map +0 -1
  581. package/dist/chunk-JEOKDUPQ.js +0 -45
  582. package/dist/chunk-JEOKDUPQ.js.map +0 -1
  583. package/dist/chunk-JNAXDFC4.mjs.map +0 -1
  584. package/dist/chunk-JNRHTZL4.js.map +0 -1
  585. package/dist/chunk-JTCQJKJE.js.map +0 -1
  586. package/dist/chunk-L4V6TKMJ.mjs.map +0 -1
  587. package/dist/chunk-LC7AM4J5.js.map +0 -1
  588. package/dist/chunk-M5GY2AI3.mjs.map +0 -1
  589. package/dist/chunk-O2VJZOR2.mjs.map +0 -1
  590. package/dist/chunk-OZ3FU4BT.js.map +0 -1
  591. package/dist/chunk-P4TB4ROG.js.map +0 -1
  592. package/dist/chunk-Q7347KP6.mjs.map +0 -1
  593. package/dist/chunk-QJU6HBSK.mjs +0 -39
  594. package/dist/chunk-QJU6HBSK.mjs.map +0 -1
  595. package/dist/chunk-QRBPT6Z6.mjs +0 -6
  596. package/dist/chunk-RCSTDJUH.js.map +0 -1
  597. package/dist/chunk-RVRN5U7W.mjs.map +0 -1
  598. package/dist/chunk-TDJKGN5Q.mjs.map +0 -1
  599. package/dist/chunk-TP7H6BSK.mjs.map +0 -1
  600. package/dist/chunk-TSZIACRC.js.map +0 -1
  601. package/dist/chunk-UJ6CHZAI.mjs.map +0 -1
  602. package/dist/chunk-VFGEY6FJ.js.map +0 -1
  603. package/dist/discover-FGTKWOL3.mjs +0 -4
  604. package/dist/discover-NJZPWTDL.js +0 -21
@@ -1,4 +1,6 @@
1
1
  import { getSiteConfig } from './chunk-B22WSN4L.mjs';
2
+ import { withSiteParam, withSiteBody } from './chunk-4TLFZ6NR.mjs';
3
+ import { resolveSiteHost } from './chunk-JLVCWC6A.mjs';
2
4
  import { NextResponse } from 'next/server';
3
5
 
4
6
  var DEFAULT_PORTAL_URL = "https://api.sonor.io";
@@ -10,9 +12,9 @@ var DEFAULT_FETCH_TIMEOUT_MS = 300;
10
12
  var FAILURE_COOLDOWN_MS = 3e4;
11
13
  var SK_PATH_HEADER = "x-sk-path";
12
14
  var rulesCache = /* @__PURE__ */ new Map();
13
- function getRedirectCacheKey(apiKey, domain) {
14
- if (apiKey) return `key:${apiKey}`;
15
- return `domain:${domain || ""}`;
15
+ function getRedirectCacheKey(apiKey, domain, site) {
16
+ const scope = apiKey ? `key:${apiKey}` : `domain:${domain || ""}`;
17
+ return `${scope}|site:${site}`;
16
18
  }
17
19
  async function fetchRedirectRules(config) {
18
20
  const now = Date.now();
@@ -25,7 +27,8 @@ async function fetchRedirectRules(config) {
25
27
  const siteConfig = await getSiteConfig({ apiUrl: baseUrl });
26
28
  domain = siteConfig?.domain;
27
29
  }
28
- const cacheKey = getRedirectCacheKey(apiKey, domain);
30
+ const site = resolveSiteHost(config.site);
31
+ const cacheKey = getRedirectCacheKey(apiKey, domain, site);
29
32
  const cached = rulesCache.get(cacheKey);
30
33
  if (cached && now < cached.expiry) {
31
34
  return cached.rules;
@@ -34,10 +37,10 @@ async function fetchRedirectRules(config) {
34
37
  let url;
35
38
  const headers = { "Content-Type": "application/json" };
36
39
  if (apiKey) {
37
- url = `${baseUrl}/api/public/seo/redirects`;
40
+ url = withSiteParam(`${baseUrl}/api/public/seo/redirects`, site);
38
41
  headers["x-api-key"] = apiKey;
39
42
  } else if (domain) {
40
- url = `${baseUrl}/api/public/seo/redirects?domain=${encodeURIComponent(domain)}`;
43
+ url = withSiteParam(`${baseUrl}/api/public/seo/redirects?domain=${encodeURIComponent(domain)}`, site);
41
44
  } else {
42
45
  return [];
43
46
  }
@@ -100,7 +103,7 @@ async function trackRedirectHit(config, fromPath, domainForHit) {
100
103
  await fetch(`${baseUrl}/api/public/seo/redirects/hit`, {
101
104
  method: "POST",
102
105
  headers: { "Content-Type": "application/json" },
103
- body: JSON.stringify({ domain, from_path: fromPath })
106
+ body: JSON.stringify(withSiteBody({ domain, from_path: fromPath }, config.site))
104
107
  });
105
108
  } catch {
106
109
  }
@@ -118,5 +121,5 @@ function clearRedirectCache() {
118
121
  }
119
122
 
120
123
  export { SK_PATH_HEADER, clearRedirectCache, fetchRedirectRules, findRedirectMatch, generateNextRedirects, handleManagedRedirects, trackRedirectHit };
121
- //# sourceMappingURL=chunk-ILNCUSXW.mjs.map
122
- //# sourceMappingURL=chunk-ILNCUSXW.mjs.map
124
+ //# sourceMappingURL=chunk-4L7OHRWB.mjs.map
125
+ //# sourceMappingURL=chunk-4L7OHRWB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/redirects/index.ts"],"names":[],"mappings":"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","file":"chunk-4L7OHRWB.mjs","sourcesContent":["/**\n * Managed Redirects - Next.js Middleware Helper\n * \n * Fetches redirect rules from Portal and applies them.\n * Supports API key only (domain resolved from Portal) or domain-based lookup.\n *\n * On a multi-site project (one Sonor project, many domains) rules are per\n * host: a rule with no site applies everywhere, and one tagged\n * 'bd-charlotte.com' applies only there. The list read and the hit both name\n * the host through `sites/site-param` (explicit `site` > NEXT_PUBLIC_SITE_URL\n * host), and the in-memory cache key carries it too. Keyed by API key alone,\n * two hosts served by one process would share whichever list was fetched\n * first, for the whole cache window.\n *\n * Usage in proxy.ts (API key only):\n * \n * import { handleManagedRedirects } from '@sonordev/site-kit/redirects'\n * \n * export default async function proxy(request: NextRequest) {\n * const redirect = await handleManagedRedirects(request, {\n * apiKey: process.env.SONOR_API_KEY,\n * portalApiUrl: process.env.SONOR_API_URL,\n * })\n * if (redirect) return redirect\n * return NextResponse.next()\n * }\n * \n * Or with domain (legacy):\n * const redirect = await handleManagedRedirects(request, { domain: 'example.com' })\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport { getSiteConfig } from '../site-config'\nimport { resolveSiteHost } from '../sites/resolve'\nimport { withSiteBody, withSiteParam } from '../sites/site-param'\n\nexport interface RedirectRule {\n from_path: string\n to_path: string\n redirect_type: '301' | '302' | '307' | '308'\n is_enabled: boolean\n}\n\nexport interface RedirectConfig {\n /** Domain to fetch redirects for (optional when apiKey is set) */\n domain?: string\n /** Project API key; when set, redirects are fetched by key (no domain needed) */\n apiKey?: string\n /**\n * Sub-site host on a multi-site project (e.g. 'bd-charlotte.com'). Same\n * meaning as the `site` argument of withSiteParam: when unset it comes from\n * the NEXT_PUBLIC_SITE_URL host. The API returns this host's rules plus the\n * project-wide ones. When nothing resolves no site is sent, and the API\n * answers for the project's primary domain.\n */\n site?: string\n portalApiUrl?: string\n cacheSeconds?: number\n /**\n * Hard ceiling on the rules fetch, in ms. Default 300.\n *\n * This fetch can sit in front of HTML (proxy hot path / not-found render),\n * and without a bound a *slow* Portal becomes every page's TTFB — the\n * try/catch only fails open on error, not on slow. Build-time callers\n * (generateNextRedirects) pass a larger value.\n */\n fetchTimeoutMs?: number\n}\n\nconst DEFAULT_PORTAL_URL = 'https://api.sonor.io'\n\n/**\n * Env parity with the API key: SONOR_API_URL was honored for the key's\n * sibling everywhere else in the kit but ignored here, so sites overriding\n * the API URL by env silently fetched redirect rules from production.\n */\nfunction envApiUrl(): string | undefined {\n const raw = typeof process !== 'undefined' && process.env ? process.env.SONOR_API_URL : undefined\n return typeof raw === 'string' && raw ? raw : undefined\n}\nconst DEFAULT_FETCH_TIMEOUT_MS = 300\n/**\n * After a failed fetch, don't re-hit the API for this long. Without this a\n * cold instance with a down Portal pays the full timeout on EVERY request.\n */\nconst FAILURE_COOLDOWN_MS = 30_000\n\n/**\n * Request header the site-kit proxy stamps with `pathname + search` so the\n * not-found boundary (which receives no URL from Next) can know what was\n * requested. Single source of truth — used by createProxy and the deprecated\n * resolveManagedRedirect.\n */\nexport const SK_PATH_HEADER = 'x-sk-path'\n\n// Cache for redirect rules keyed by apiKey or 'domain:'+domain, plus the site host\nconst rulesCache = new Map<string, { rules: RedirectRule[]; expiry: number }>()\n\n/**\n * The host is part of the key because rules are per host. One process can\n * serve several hosts of a multi-site project (a `site` passed per call), and\n * a key without it would hand every host the first host's list.\n */\nfunction getRedirectCacheKey(apiKey: string | undefined, domain: string | undefined, site: string): string {\n const scope = apiKey ? `key:${apiKey}` : `domain:${domain || ''}`\n return `${scope}|site:${site}`\n}\n\n/**\n * Fetch redirect rules from Portal API.\n * When apiKey is set (or from env), uses key-based endpoint (no domain required).\n * Otherwise uses domain query (or domain from getSiteConfig when only env API key is set).\n * Either way the site host goes along as `?site=`, left off when it resolves empty.\n */\nexport async function fetchRedirectRules(config: RedirectConfig): Promise<RedirectRule[]> {\n const now = Date.now()\n const cacheSeconds = config.cacheSeconds ?? 300\n const baseUrl = config.portalApiUrl || envApiUrl() || DEFAULT_PORTAL_URL\n\n const rawKey = config.apiKey ?? (typeof process !== 'undefined' && process.env ? process.env.SONOR_API_KEY : undefined)\n const apiKey = typeof rawKey === 'string' ? rawKey : undefined\n let domain = config.domain\n\n if (!apiKey && !domain) {\n const siteConfig = await getSiteConfig({ apiUrl: baseUrl })\n domain = siteConfig?.domain\n }\n\n // Resolved once, so the cache key and the ?site= param always name the same\n // host: the entry a host reads is the list fetched for that host.\n const site = resolveSiteHost(config.site)\n const cacheKey = getRedirectCacheKey(apiKey, domain, site)\n const cached = rulesCache.get(cacheKey)\n if (cached && now < cached.expiry) {\n return cached.rules\n }\n\n try {\n let url: string\n const headers: Record<string, string> = { 'Content-Type': 'application/json' }\n\n if (apiKey) {\n url = withSiteParam(`${baseUrl}/api/public/seo/redirects`, site)\n headers['x-api-key'] = apiKey\n } else if (domain) {\n url = withSiteParam(`${baseUrl}/api/public/seo/redirects?domain=${encodeURIComponent(domain)}`, site)\n } else {\n return []\n }\n\n const timeoutMs = config.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS\n // Guarded like every other web API here (see shared/identity): AbortSignal\n // .timeout is Node 17.3+/modern edge; when absent we just fetch unbounded.\n const signal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(timeoutMs)\n : undefined\n\n const res = await fetch(url, {\n headers,\n signal,\n // No-op in proxy (outside the data cache) but real in RSC renders,\n // where the not-found resolver runs.\n next: { revalidate: cacheSeconds },\n })\n\n if (!res.ok) {\n console.error(`[site-kit] Failed to fetch redirects: ${res.status}`)\n rulesCache.set(cacheKey, { rules: cached?.rules ?? [], expiry: now + FAILURE_COOLDOWN_MS })\n return cached?.rules ?? []\n }\n\n const data = await res.json()\n const rules = (data.redirects || []).filter((r: RedirectRule) => r.is_enabled)\n rulesCache.set(cacheKey, { rules, expiry: now + cacheSeconds * 1000 })\n return rules\n } catch (error) {\n console.error('[site-kit] Error fetching redirects:', error)\n rulesCache.set(cacheKey, { rules: cached?.rules ?? [], expiry: now + FAILURE_COOLDOWN_MS })\n return cached?.rules ?? []\n }\n}\n\n/**\n * Find the rule matching a pathname (exact, tolerating trailing-slash\n * variance). Single source of truth for match semantics — used by the proxy\n * hot path and the not-found resolver. Do not re-fork.\n */\nexport function findRedirectMatch(\n pathname: string,\n rules: RedirectRule[],\n): RedirectRule | undefined {\n return rules.find(r => {\n if (r.from_path === pathname) return true\n const normalizedFrom = r.from_path.endsWith('/') ? r.from_path.slice(0, -1) : r.from_path\n const normalizedPath = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname\n return normalizedFrom === normalizedPath\n })\n}\n\n/**\n * Handle managed redirects in middleware\n * Returns a NextResponse.redirect if a match is found, otherwise undefined\n */\nexport async function handleManagedRedirects(\n request: NextRequest,\n config: RedirectConfig,\n): Promise<NextResponse | undefined> {\n const pathname = request.nextUrl.pathname\n \n // Skip for static assets and API routes\n if (\n pathname.startsWith('/_next') ||\n pathname.startsWith('/api') ||\n pathname.includes('.') // Has file extension\n ) {\n return undefined\n }\n\n const rules = await fetchRedirectRules(config)\n const match = findRedirectMatch(pathname, rules)\n\n if (!match) {\n return undefined\n }\n\n // Build redirect URL\n const redirectUrl = new URL(match.to_path, request.url)\n \n // Preserve query params\n request.nextUrl.searchParams.forEach((value, key) => {\n redirectUrl.searchParams.set(key, value)\n })\n\n // Track hit (fire and forget); domain may be from config or resolved by apiKey\n trackRedirectHit(config, match.from_path, config.domain).catch(() => {})\n\n // Return redirect response\n const statusCode = parseInt(match.redirect_type) as 301 | 302 | 307 | 308\n return NextResponse.redirect(redirectUrl, statusCode)\n}\n\n/**\n * Track redirect hit for analytics (needs domain; resolved from config or getSiteConfig when using apiKey)\n * Exported for the not-found resolver — fire-and-forget, never throws.\n * The site host goes in the body so a multi-site project counts the hit on\n * that host's rule, not the project-wide one.\n */\nexport async function trackRedirectHit(config: RedirectConfig, fromPath: string, domainForHit?: string): Promise<void> {\n try {\n const baseUrl = config.portalApiUrl || envApiUrl() || DEFAULT_PORTAL_URL\n const domain = domainForHit ?? config.domain ?? (await getSiteConfig({ apiKey: config.apiKey, apiUrl: baseUrl }))?.domain\n if (!domain) return\n await fetch(`${baseUrl}/api/public/seo/redirects/hit`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(withSiteBody({ domain, from_path: fromPath }, config.site)),\n })\n } catch {\n // Ignore tracking errors\n }\n}\n\n/**\n * Generate Next.js redirects config from Portal\n * Use this in next.config.js for build-time redirects\n *\n * The site host resolves as it does everywhere else. Next loads .env files\n * before it evaluates next.config, so a NEXT_PUBLIC_SITE_URL from .env.local\n * or the host's env is already visible here, and each build of a multi-site\n * project bakes in its own host's rules.\n *\n * Usage in next.config.js:\n * \n * const { generateNextRedirects } = require('@sonordev/site-kit/redirects')\n * \n * module.exports = {\n * async redirects() {\n * return generateNextRedirects({\n * domain: 'example.com',\n * portalApiUrl: process.env.PORTAL_API_URL,\n * })\n * }\n * }\n */\nexport async function generateNextRedirects(config: RedirectConfig): Promise<Array<{\n source: string\n destination: string\n permanent: boolean\n}>> {\n // Build-time: nothing is waiting on this response, so allow a generous\n // timeout instead of the request-path default.\n const rules = await fetchRedirectRules({ fetchTimeoutMs: 10_000, ...config, cacheSeconds: 0 })\n \n return rules.map(r => ({\n source: r.from_path,\n destination: r.to_path,\n permanent: r.redirect_type === '301' || r.redirect_type === '308',\n }))\n}\n\n/**\n * Clear redirect cache (useful for development)\n */\nexport function clearRedirectCache(): void {\n rulesCache.clear()\n}\n"]}
@@ -0,0 +1,72 @@
1
+ // src/sitemap/shared.ts
2
+ function inferPageType(urlPath) {
3
+ if (urlPath === "/" || urlPath === "") return "homepage";
4
+ if (/^\/services(\/|$)/i.test(urlPath)) return "service";
5
+ if (/^\/compare(\/|$)/i.test(urlPath)) return "comparison";
6
+ if (/^\/(insights|blog)(\/|$)/i.test(urlPath)) return "blog";
7
+ if (/^\/industries(\/|$)/i.test(urlPath)) return "industry";
8
+ if (/^\/work(\/|$)/i.test(urlPath)) return "portfolio";
9
+ if (/^\/faq(\/|$)/i.test(urlPath)) return "faq";
10
+ if (/^\/pricing(\/|$)/i.test(urlPath)) return "pricing";
11
+ return "page";
12
+ }
13
+ function stripTrailingSlash(path) {
14
+ if (path !== "/" && path.endsWith("/")) {
15
+ return path.slice(0, -1);
16
+ }
17
+ return path;
18
+ }
19
+ function applyTrailingSlash(path, trailingSlash) {
20
+ const cut = path.search(/[?#]/);
21
+ const pathname = cut === -1 ? path : path.slice(0, cut);
22
+ const suffix = cut === -1 ? "" : path.slice(cut);
23
+ return shapePathname(pathname, trailingSlash) + suffix;
24
+ }
25
+ function shapePathname(pathname, trailingSlash) {
26
+ if (pathname === "" || pathname === "/") return pathname;
27
+ if (/^\/\.well-known(\/|$)/.test(pathname)) return pathname;
28
+ const bare = stripTrailingSlash(pathname);
29
+ if (!trailingSlash) return bare;
30
+ const lastSegment = bare.slice(bare.lastIndexOf("/") + 1);
31
+ return lastSegment.includes(".") ? bare : `${bare}/`;
32
+ }
33
+ function nextTrailingSlash() {
34
+ let value;
35
+ try {
36
+ value = process.env.__NEXT_TRAILING_SLASH;
37
+ } catch {
38
+ return void 0;
39
+ }
40
+ if (value === true || value === "true") return true;
41
+ if (value === false || value === "false") return false;
42
+ return void 0;
43
+ }
44
+ function resolveTrailingSlash(explicit) {
45
+ return explicit ?? nextTrailingSlash() ?? false;
46
+ }
47
+ function locToPath(loc) {
48
+ let path;
49
+ try {
50
+ path = new URL(loc).pathname;
51
+ } catch {
52
+ path = loc.startsWith("/") ? loc : `/${loc}`;
53
+ }
54
+ return stripTrailingSlash(path);
55
+ }
56
+ var EMBEDDED_DOMAIN_PREFIX = /^\/{1,2}[a-z0-9.-]+\.[a-z]{2,}(\/|$)/i;
57
+ var EMBEDDED_DOMAIN_ANYWHERE = /\/\/[a-z0-9.-]+\.[a-z]{2,}/i;
58
+ function stripEmbeddedDomain(path) {
59
+ return path.replace(EMBEDDED_DOMAIN_PREFIX, "/");
60
+ }
61
+ function isMalformedSitemapPath(path) {
62
+ return path.includes("://") || EMBEDDED_DOMAIN_ANYWHERE.test(path);
63
+ }
64
+ var LLMS_WRITE_ROUTE_BUDGET_MS = 5e4;
65
+ function llmsWriteTimeoutMs(configured, routeStartedAt, now = Date.now()) {
66
+ if (configured != null) return configured;
67
+ return LLMS_WRITE_ROUTE_BUDGET_MS - (now - routeStartedAt);
68
+ }
69
+
70
+ export { applyTrailingSlash, inferPageType, isMalformedSitemapPath, llmsWriteTimeoutMs, locToPath, resolveTrailingSlash, stripEmbeddedDomain, stripTrailingSlash };
71
+ //# sourceMappingURL=chunk-4LYW6PMU.mjs.map
72
+ //# sourceMappingURL=chunk-4LYW6PMU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sitemap/shared.ts"],"names":[],"mappings":"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","file":"chunk-4LYW6PMU.mjs","sourcesContent":["/**\n * @sonordev/site-kit — shared sitemap page classification + path normalization\n *\n * Single source of truth for two bits of logic that used to be copy-pasted in\n * three places (createSitemap in `sitemap/index.ts`, the runtime `SitemapSync`\n * component, and the `sonor-register-sitemap` CLI):\n *\n * 1. inferPageType — path → Signal page-type hint\n * 2. path normalization — turning a sitemap `<loc>` / entry URL into a clean,\n * site-relative path, and rejecting/repairing malformed embedded-domain paths\n *\n * It also owns the outbound direction, `applyTrailingSlash`: the shape of a\n * path in a URL the kit emits, which follows the site's Next `trailingSlash`.\n * Normalized paths (the dedupe/sync key) never carry the slash. Emitted URLs\n * carry it when the site does.\n *\n * The copies had already drifted (one treated `''` as the homepage, the others\n * didn't; one stripped embedded domains, another only rejected them). Keeping\n * one implementation is the CLAUDE.md \"consolidate duplicated logic\" rule.\n *\n * Pure string logic only — NO Node built-ins, NO React — so this file is safe to\n * import from the browser `SitemapSync` client component AND from the Node CLI.\n */\n\n/** Signal page-type hint attached to each sitemap entry. */\nexport type PageType =\n | 'homepage'\n | 'service'\n | 'comparison'\n | 'blog'\n | 'industry'\n | 'portfolio'\n | 'faq'\n | 'pricing'\n | 'page'\n\n/**\n * Infer a page type from a URL path, to give Signal context about what each\n * page covers. Accepts both `'/'` and `''` as the homepage (callers pass either\n * depending on how they normalized the path).\n */\nexport function inferPageType(urlPath: string): PageType {\n if (urlPath === '/' || urlPath === '') return 'homepage'\n if (/^\\/services(\\/|$)/i.test(urlPath)) return 'service'\n if (/^\\/compare(\\/|$)/i.test(urlPath)) return 'comparison'\n if (/^\\/(insights|blog)(\\/|$)/i.test(urlPath)) return 'blog'\n if (/^\\/industries(\\/|$)/i.test(urlPath)) return 'industry'\n if (/^\\/work(\\/|$)/i.test(urlPath)) return 'portfolio'\n if (/^\\/faq(\\/|$)/i.test(urlPath)) return 'faq'\n if (/^\\/pricing(\\/|$)/i.test(urlPath)) return 'pricing'\n return 'page'\n}\n\n/**\n * Strip a trailing slash from a path, preserving the `'/'` root. Used so that\n * `/about` and `/about/` are treated as the same page everywhere.\n */\nexport function stripTrailingSlash(path: string): string {\n if (path !== '/' && path.endsWith('/')) {\n return path.slice(0, -1)\n }\n return path\n}\n\n/**\n * Shape a site path the way the site's own Next config serves it.\n *\n * Single source of truth for Next's `trailingSlash` URL shape, used by\n * createSitemap (`<loc>`), the llms.txt link rewrite and ClusterNavigation.\n * With `trailingSlash: true`, Next 308-redirects `/about` to `/about/`. Every\n * URL the kit emits for a page has to carry the slash already, or crawlers\n * get a redirect instead of the page and the sitemap disagrees with the\n * canonicals. That's what happened on the five MDG property sites\n * (2026-09-15).\n *\n * Mirrors the redirects Next adds in `lib/load-custom-routes`:\n * - `/` stays `/`.\n * - A last segment with a `.` is a file (`/llms.txt`, `/feed.xml`) and never\n * gets a slash.\n * - `/.well-known/*` is left exactly as written. Next exempts it from both\n * redirects.\n * - `trailingSlash: false` strips the slash, which is Next's default.\n *\n * A `?query` or `#hash` is kept and the rule applies to the path before it.\n */\nexport function applyTrailingSlash(path: string, trailingSlash: boolean): string {\n const cut = path.search(/[?#]/)\n const pathname = cut === -1 ? path : path.slice(0, cut)\n const suffix = cut === -1 ? '' : path.slice(cut)\n return shapePathname(pathname, trailingSlash) + suffix\n}\n\nfunction shapePathname(pathname: string, trailingSlash: boolean): string {\n if (pathname === '' || pathname === '/') return pathname\n if (/^\\/\\.well-known(\\/|$)/.test(pathname)) return pathname\n const bare = stripTrailingSlash(pathname)\n if (!trailingSlash) return bare\n const lastSegment = bare.slice(bare.lastIndexOf('/') + 1)\n return lastSegment.includes('.') ? bare : `${bare}/`\n}\n\n/**\n * The site's `next.config` `trailingSlash`, or undefined when not running inside\n * a Next bundle.\n *\n * Next inlines `process.env.__NEXT_TRAILING_SLASH` at compile time (its\n * `define-env`) into every module it bundles, node_modules included, for\n * server, edge and client alike. The kit reads the site's config this way\n * with no file I/O. Keep the expression spelled exactly like this: the\n * bundler matches the literal member expression, so destructuring\n * `process.env` or indexing it with a variable gets no substitution.\n *\n * Returns undefined in plain Node, like a postbuild script, or when a site\n * lists the kit in `serverExternalPackages`. Pass `trailingSlash` explicitly\n * there.\n */\nexport function nextTrailingSlash(): boolean | undefined {\n let value: unknown\n try {\n value = process.env.__NEXT_TRAILING_SLASH\n } catch {\n return undefined // no `process` in this runtime and no Next substitution\n }\n if (value === true || value === 'true') return true\n if (value === false || value === 'false') return false\n return undefined\n}\n\n/** An explicit `trailingSlash` option, else the site's Next config, else Next's default (false). */\nexport function resolveTrailingSlash(explicit?: boolean): boolean {\n return explicit ?? nextTrailingSlash() ?? false\n}\n\n/**\n * Turn a sitemap `<loc>` value (a full URL) or an already-relative path into a\n * clean, site-relative path. Falls back gracefully when the value isn't a\n * parseable absolute URL, and always strips the trailing slash.\n *\n * `https://example.com/about/` → `/about`\n * `about` → `/about`\n */\nexport function locToPath(loc: string): string {\n let path: string\n try {\n path = new URL(loc).pathname\n } catch {\n path = loc.startsWith('/') ? loc : `/${loc}`\n }\n return stripTrailingSlash(path)\n}\n\n/**\n * Matches a leading embedded domain in a malformed path, e.g. a crawler or bad\n * generator producing `//example.com/services` instead of `/services`.\n */\nconst EMBEDDED_DOMAIN_PREFIX = /^\\/{1,2}[a-z0-9.-]+\\.[a-z]{2,}(\\/|$)/i\n\n/** Matches an embedded protocol or domain anywhere in a path (unrepairable). */\nconst EMBEDDED_DOMAIN_ANYWHERE = /\\/\\/[a-z0-9.-]+\\.[a-z]{2,}/i\n\n/**\n * Repair a path whose leading segment is actually a domain\n * (`//example.com/x` → `/x`). Only touches the leading embedded domain; a path\n * that's malformed deeper in is left for `isMalformedSitemapPath` to reject.\n */\nexport function stripEmbeddedDomain(path: string): string {\n return path.replace(EMBEDDED_DOMAIN_PREFIX, '/')\n}\n\n/**\n * True when a path still contains an embedded protocol or domain after\n * normalization — such a \"path\" isn't a real page path and must not be synced.\n */\nexport function isMalformedSitemapPath(path: string): boolean {\n return path.includes('://') || EMBEDDED_DOMAIN_ANYWHERE.test(path)\n}\n\n/**\n * How much of the sitemap route's time the build-time llms.txt write may use.\n *\n * Next gives a prerendered route 60s (`staticPageGenerationTimeout`), then\n * retries it and fails the build. Sonor generates llms.txt through an LLM call\n * that takes roughly 27-60s, so the write can't reliably fit, and it runs\n * after the Portal sync has already spent part of the budget. Until 2026-09 a\n * one-year Data Cache entry hid this: the call ran live only on a site's first\n * build, and every later build replayed the stored response (a stale file).\n * With reads fresh (shared/fresh-fetch.ts), the write gets whatever is left of\n * this share of the budget. When Sonor answers in time, llms.txt refreshes;\n * when it doesn't, the existing file keeps serving and the build still passes.\n */\nexport const LLMS_WRITE_ROUTE_BUDGET_MS = 50_000\n\n/**\n * Timeout for the in-route llms.txt write: an explicit `llmsWriteTimeoutMs`\n * wins; otherwise what's left of LLMS_WRITE_ROUTE_BUDGET_MS since the route\n * started. Zero or less means skip the write.\n */\nexport function llmsWriteTimeoutMs(\n configured: number | undefined,\n routeStartedAt: number,\n now: number = Date.now(),\n): number {\n if (configured != null) return configured\n return LLMS_WRITE_ROUTE_BUDGET_MS - (now - routeStartedAt)\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunk5TXXTYXL_js = require('./chunk-5TXXTYXL.js');
3
+ var chunkLVGSOW2F_js = require('./chunk-LVGSOW2F.js');
4
+ var chunk5O7JSWT6_js = require('./chunk-5O7JSWT6.js');
4
5
  require('server-only');
5
6
 
6
7
  var MINT_PATH = "/api/public/site-token";
@@ -37,13 +38,6 @@ function failClosed(reason, rawKey, now) {
37
38
  `site-kit: could not mint a site token (${reason}). Refusing to publish the raw SONOR_API_KEY in page HTML, so this build fails instead. Check that the mint endpoint is reachable and the key is valid, then rebuild. To ship anyway \u2014 which publishes the project secret in public HTML \u2014 set SONOR_SITE_TOKEN_FALLBACK=raw.`
38
39
  );
39
40
  }
40
- function resolveFetch() {
41
- const current = globalThis.fetch;
42
- if (!current) throw new Error("site-kit: global fetch is unavailable");
43
- const original = current._nextOriginalFetch;
44
- if (typeof original === "function") return { fn: original, unpatched: true };
45
- return { fn: current, unpatched: false };
46
- }
47
41
  function isFrameworkSignal(err) {
48
42
  if (!err || typeof err !== "object") return false;
49
43
  const e = err;
@@ -74,13 +68,13 @@ async function mintWithRetry(rawKey, apiUrl) {
74
68
  for (let attempt = 0; attempt < MINT_MAX_ATTEMPTS; attempt++) {
75
69
  let res = null;
76
70
  try {
77
- const { fn: fetchFn, unpatched } = resolveFetch();
71
+ const { fn: fetchFn, unpatched } = chunkLVGSOW2F_js.resolveFetch();
78
72
  res = await fetchFn(`${base}${MINT_PATH}`, {
79
73
  method: "POST",
80
74
  headers: {
81
75
  "content-type": "application/json",
82
76
  "x-api-key": rawKey,
83
- "x-sitekit-version": chunk5TXXTYXL_js.SITE_KIT_VERSION
77
+ "x-sitekit-version": chunk5O7JSWT6_js.SITE_KIT_VERSION
84
78
  },
85
79
  // Only meaningful on the fallback path, where a future Next stopped
86
80
  // exposing `_nextOriginalFetch` and we're back on the patched fetch.
@@ -132,5 +126,5 @@ async function mintWithRetry(rawKey, apiUrl) {
132
126
  }
133
127
 
134
128
  exports.resolveClientCredential = resolveClientCredential;
135
- //# sourceMappingURL=chunk-TSZIACRC.js.map
136
- //# sourceMappingURL=chunk-TSZIACRC.js.map
129
+ //# sourceMappingURL=chunk-4OS6M3V4.js.map
130
+ //# sourceMappingURL=chunk-4OS6M3V4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/mint-site-token.ts"],"names":["resolveFetch","SITE_KIT_VERSION"],"mappings":"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","file":"chunk-4OS6M3V4.js","sourcesContent":["/**\n * @sonordev/site-kit/server — Client-token minting (server-only)\n *\n * SiteKitLayout holds the raw `SONOR_API_KEY` server-side but must NOT ship it to\n * the browser. This mints a short-lived, project-scoped token (server-to-server,\n * authenticated with the raw key, no browser Origin so it passes domain-binding)\n * and returns THAT for the layout to inject instead.\n *\n * `import 'server-only'` makes importing this into a client bundle a hard build\n * error — the raw key stays on the server.\n *\n * FAILS CLOSED. If minting genuinely fails, this throws and the build fails —\n * it does NOT publish the raw key. A failed deploy is loud and recoverable; a\n * leaked project secret in public HTML is neither. The only paths that still\n * return the raw key are a 404 (an older API that predates the endpoint, an\n * expected state during rollout) and the explicit `SONOR_SITE_TOKEN_FALLBACK=raw`\n * escape hatch, for when shipping beats being blocked.\n *\n * That posture is not academic. Through 3.5.0 a throttled mint (HTTP 429)\n * returned the raw key AND cached it for 60s, so every page rendered in that\n * window shipped the secret: one real build came out with 180 of 272 prerendered\n * pages carrying it. The build \"succeeded\" and nothing downstream noticed.\n * Rate limiting is transient by definition — the fix is to wait and retry, not\n * to downgrade to publishing the key.\n *\n * Two things keep the request count low enough that throttling is rare:\n * - a module-level memo, so a worker mints once and every page reuses the seed;\n * - an in-flight map, because that memo is only populated AFTER the await. Next\n * renders pages concurrently, so without coalescing the first N concurrent\n * renders in a process all miss the cache and all fire a request — a\n * stampede per worker, multiplied by one worker per core. That is how a\n * single site exhausted a 60/min budget.\n *\n * SEED FRESHNESS: a static page's seed carries `iat` = build time, and the API\n * refuses to refresh a seed older than SITE_TOKEN_MAX_REFRESH_AGE_SECONDS\n * (sonor-api common/site-auth/site-token.util.ts — currently 400 days, raised\n * from 30 alongside this fix). A site not rebuilt within that window serves a\n * seed the client cannot refresh, and its forms/analytics/engage start failing\n * for new visitors. Keep that limit comfortably longer than the fleet's\n * realistic redeploy gap; marketing sites routinely go many months untouched.\n */\nimport 'server-only'\nimport { SITE_KIT_VERSION } from '../shared/version'\nimport { resolveFetch } from '../shared/fresh-fetch'\n\n// Re-exported for this module's unit tests; the helper lives in shared/fresh-fetch.\nexport { resolveFetch }\n\nconst MINT_PATH = '/api/public/site-token'\nconst MINT_TIMEOUT_MS = 4_000\nconst SITE_TOKEN_PREFIX = 'st1.'\n\n/**\n * Retry budget for transient failures (429 / 5xx / network). Rate limiting is\n * measured per minute, so a few seconds of backoff clears it; the whole ladder\n * costs at most ~20s once per build worker, and only when something is wrong.\n */\nconst MINT_MAX_ATTEMPTS = 4\nconst MINT_BACKOFF_BASE_MS = 500\nconst MINT_BACKOFF_CAP_MS = 8_000\n\ninterface CacheEntry {\n credential: string\n expiresAt: number\n}\nconst cache = new Map<string, CacheEntry>()\n\n/**\n * Requests already in flight, keyed by raw key. The `cache` above is only\n * written after the response lands, so concurrent renders would otherwise each\n * start their own mint. See the module header.\n */\nconst inflight = new Map<string, Promise<string>>()\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))\n\n/**\n * Honour `Retry-After` when the server sends it (delta-seconds or HTTP date),\n * otherwise exponential backoff. Capped so a misconfigured server cannot stall\n * a build indefinitely.\n */\nfunction retryDelayMs(res: Response | null, attempt: number): number {\n const header = res?.headers?.get?.('retry-after')\n if (header) {\n const seconds = Number(header)\n const ms = Number.isFinite(seconds)\n ? seconds * 1000\n : Date.parse(header) - Date.now()\n if (Number.isFinite(ms) && ms > 0) return Math.min(ms, MINT_BACKOFF_CAP_MS)\n }\n return Math.min(MINT_BACKOFF_BASE_MS * 2 ** attempt, MINT_BACKOFF_CAP_MS)\n}\n\n/** 429 and 5xx are transient; waiting is the correct response to both. */\nconst isRetryableStatus = (status: number) => status === 429 || status >= 500\n\n/**\n * The escape hatch, for when a broken mint must not block a release. Opt-in and\n * loud: it re-enables publishing the project secret in page HTML.\n */\nfunction rawFallbackAllowed(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.env?.SONOR_SITE_TOKEN_FALLBACK === 'raw'\n )\n}\n\nfunction failClosed(reason: string, rawKey: string, now: number): string {\n if (rawFallbackAllowed()) {\n console.warn(\n `[SiteKitLayout] Token mint failed (${reason}) and SONOR_SITE_TOKEN_FALLBACK=raw is set; ` +\n 'injecting the RAW API KEY into page HTML. The key is publicly readable wherever ' +\n 'this page is served — unset the escape hatch once the mint is healthy.',\n )\n cache.set(rawKey, { credential: rawKey, expiresAt: now + 60_000 })\n return rawKey\n }\n throw new Error(\n `site-kit: could not mint a site token (${reason}). Refusing to publish the raw ` +\n 'SONOR_API_KEY in page HTML, so this build fails instead. Check that the mint ' +\n 'endpoint is reachable and the key is valid, then rebuild. To ship anyway — ' +\n 'which publishes the project secret in public HTML — set SONOR_SITE_TOKEN_FALLBACK=raw.',\n )\n}\n\n/*\n * The mint uses Next's saved original fetch (resolveFetch, shared/fresh-fetch.ts,\n * which documents why). A credential is not page data: `cache: 'no-store'` would\n * bail a static route before the request goes out (verified on Next 16.2.9: the\n * mint endpoint received zero requests for a static build, and every page\n * shipped the raw key), and a Data Cache entry would let a fresh deploy re-bake a\n * months-old seed. The module-level memo above is the only cache we want: one\n * mint per build process, and a build-fresh seed on every deploy.\n */\n\n/**\n * Next signals \"this render must go dynamic\" by THROWING (DynamicServerError,\n * static-gen bailout, redirect/notFound digests, React's postpone). Those are\n * the framework's control flow, not a mint failure. Swallowing one makes Next\n * believe the render succeeded statically — which is precisely how the raw key\n * ended up stranded in prerendered HTML with no error anywhere. Let them\n * propagate; only real network/HTTP failures fall back to the raw key.\n *\n * @internal Exported for unit tests; not part of the package's public API.\n */\nexport function isFrameworkSignal(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false\n const e = err as { digest?: unknown; code?: unknown; $$typeof?: unknown }\n if (e.digest === 'DYNAMIC_SERVER_USAGE') return true\n if (e.code === 'NEXT_STATIC_GEN_BAILOUT') return true\n if (typeof e.digest === 'string' && e.digest.startsWith('NEXT_')) return true\n if (e.$$typeof === Symbol.for('react.postpone')) return true\n return false\n}\n\nexport async function resolveClientCredential(\n rawKey: string,\n apiUrl: string,\n): Promise<string> {\n if (!rawKey) return ''\n // Env should hold a raw key; if it already looks like a token, pass it through.\n if (rawKey.startsWith(SITE_TOKEN_PREFIX)) return rawKey\n\n const cached = cache.get(rawKey)\n if (cached && cached.expiresAt > Date.now()) return cached.credential\n\n // Collapse concurrent renders onto one request rather than a stampede.\n const pending = inflight.get(rawKey)\n if (pending) return pending\n\n const request = mintWithRetry(rawKey, apiUrl)\n inflight.set(rawKey, request)\n try {\n return await request\n } finally {\n inflight.delete(rawKey)\n }\n}\n\nasync function mintWithRetry(rawKey: string, apiUrl: string): Promise<string> {\n const base = (apiUrl || 'https://api.sonor.io').replace(/\\/+$/, '')\n let lastReason = 'unknown error'\n\n for (let attempt = 0; attempt < MINT_MAX_ATTEMPTS; attempt++) {\n let res: Response | null = null\n try {\n const { fn: fetchFn, unpatched } = resolveFetch()\n res = await fetchFn(`${base}${MINT_PATH}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-api-key': rawKey,\n 'x-sitekit-version': SITE_KIT_VERSION,\n },\n // Only meaningful on the fallback path, where a future Next stopped\n // exposing `_nextOriginalFetch` and we're back on the patched fetch.\n // `revalidate: false` is the one setting that neither bails out of static\n // generation nor downgrades the route to ISR; a Data Cache entry is the\n // lesser evil versus shipping the raw key again.\n ...(unpatched ? {} : ({ next: { revalidate: false } } as RequestInit)),\n signal:\n typeof AbortSignal !== 'undefined' && AbortSignal.timeout\n ? AbortSignal.timeout(MINT_TIMEOUT_MS)\n : undefined,\n })\n } catch (err) {\n // Never swallow the framework's own control flow — see isFrameworkSignal.\n if (isFrameworkSignal(err)) throw err\n lastReason = err instanceof Error ? err.message : 'network error'\n if (attempt < MINT_MAX_ATTEMPTS - 1) {\n await sleep(retryDelayMs(null, attempt))\n continue\n }\n break\n }\n\n if (res.ok) {\n const data: any = await res.json().catch(() => null)\n const token = data?.token\n const expiresIn = typeof data?.expiresIn === 'number' ? data.expiresIn : 3600\n if (typeof token === 'string' && token.startsWith(SITE_TOKEN_PREFIX)) {\n cache.set(rawKey, {\n credential: token,\n expiresAt: Date.now() + Math.min((expiresIn * 1000) / 2, 30 * 60_000),\n })\n return token\n }\n lastReason = 'mint returned no usable token'\n break\n }\n\n // 404 = an API older than the endpoint. Expected during rollout, and the raw\n // key is exactly what such an API still expects, so this stays a fallback\n // rather than a build failure.\n if (res.status === 404) {\n cache.set(rawKey, { credential: rawKey, expiresAt: Date.now() + 60_000 })\n return rawKey\n }\n\n lastReason = `HTTP ${res.status}`\n if (isRetryableStatus(res.status) && attempt < MINT_MAX_ATTEMPTS - 1) {\n const delay = retryDelayMs(res, attempt)\n console.warn(\n `[SiteKitLayout] Token mint returned ${res.status}; retrying in ${Math.round(delay)}ms ` +\n `(attempt ${attempt + 2}/${MINT_MAX_ATTEMPTS}).`,\n )\n await sleep(delay)\n continue\n }\n break\n }\n\n return failClosed(lastReason, rawKey, Date.now())\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkH65OX263_js = require('./chunk-H65OX263.js');
4
+ var chunkPRTXAIIC_js = require('./chunk-PRTXAIIC.js');
5
5
  var react = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
 
@@ -40,7 +40,7 @@ function ManagedImage({
40
40
  }
41
41
  try {
42
42
  const params = new URLSearchParams({ page_path: currentPath });
43
- const res = await chunkH65OX263_js.sonorFetch(
43
+ const res = await chunkPRTXAIIC_js.sonorFetch(
44
44
  `${apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
45
45
  { headers: { "Content-Type": "application/json" } },
46
46
  { apiKey }
@@ -214,7 +214,7 @@ function ImagePickerModal({
214
214
  const params = new URLSearchParams();
215
215
  if (currentFolder) params.set("folder", currentFolder);
216
216
  if (search) params.set("search", search);
217
- const res = await chunkH65OX263_js.sonorFetch(
217
+ const res = await chunkPRTXAIIC_js.sonorFetch(
218
218
  `${config.apiUrl}/public/images/files?${params}`,
219
219
  { headers: { "Content-Type": "application/json" } },
220
220
  { apiKey: config.apiKey }
@@ -236,7 +236,7 @@ function ImagePickerModal({
236
236
  const handleSelectFile = async (file) => {
237
237
  if (!config?.apiKey || !config?.apiUrl) return;
238
238
  try {
239
- const res = await chunkH65OX263_js.sonorFetch(
239
+ const res = await chunkPRTXAIIC_js.sonorFetch(
240
240
  `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,
241
241
  {
242
242
  method: "POST",
@@ -267,7 +267,7 @@ function ImagePickerModal({
267
267
  formData.append("page_path", pagePath);
268
268
  formData.append("folder", currentFolder || "Website/Images");
269
269
  if (altText) formData.append("alt_text", altText);
270
- const res = await chunkH65OX263_js.sonorFetch(`${config.apiUrl}/public/images/upload`, {
270
+ const res = await chunkPRTXAIIC_js.sonorFetch(`${config.apiUrl}/public/images/upload`, {
271
271
  method: "POST",
272
272
  body: formData
273
273
  }, { apiKey: config.apiKey, retries: 0, timeoutMs: 6e4 });
@@ -284,7 +284,7 @@ function ImagePickerModal({
284
284
  if (!config?.apiKey || !config?.apiUrl) return;
285
285
  try {
286
286
  const params = new URLSearchParams({ page_path: pagePath });
287
- await chunkH65OX263_js.sonorFetch(
287
+ await chunkPRTXAIIC_js.sonorFetch(
288
288
  `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
289
289
  { method: "DELETE" },
290
290
  { apiKey: config.apiKey, retries: 0 }
@@ -428,7 +428,7 @@ function ImagePickerModal({
428
428
  async function fetchManagedImage(config, slotId, pagePath) {
429
429
  const params = new URLSearchParams();
430
430
  if (pagePath) params.set("page_path", pagePath);
431
- const res = await chunkH65OX263_js.sonorFetch(
431
+ const res = await chunkPRTXAIIC_js.sonorFetch(
432
432
  `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
433
433
  { headers: { "Content-Type": "application/json" } },
434
434
  { apiKey: config.apiKey }
@@ -443,7 +443,7 @@ async function fetchManagedImages(config, options) {
443
443
  if (options?.pagePath) params.set("page_path", options.pagePath);
444
444
  if (options?.category) params.set("category", options.category);
445
445
  if (options?.includePlaceholders) params.set("include_placeholders", "true");
446
- const res = await chunkH65OX263_js.sonorFetch(
446
+ const res = await chunkPRTXAIIC_js.sonorFetch(
447
447
  `${config.apiUrl}/public/images?${params}`,
448
448
  { headers: { "Content-Type": "application/json" } },
449
449
  { apiKey: config.apiKey }
@@ -457,7 +457,7 @@ async function listImageFiles(config, options) {
457
457
  const params = new URLSearchParams();
458
458
  if (options?.folder) params.set("folder", options.folder);
459
459
  if (options?.search) params.set("search", options.search);
460
- const res = await chunkH65OX263_js.sonorFetch(
460
+ const res = await chunkPRTXAIIC_js.sonorFetch(
461
461
  `${config.apiUrl}/public/images/files?${params}`,
462
462
  { headers: { "Content-Type": "application/json" } },
463
463
  { apiKey: config.apiKey }
@@ -474,7 +474,7 @@ async function uploadImage(config, file, options) {
474
474
  if (options?.pagePath) formData.append("page_path", options.pagePath);
475
475
  if (options?.folder) formData.append("folder", options.folder);
476
476
  if (options?.altText) formData.append("alt_text", options.altText);
477
- const res = await chunkH65OX263_js.sonorFetch(`${config.apiUrl}/public/images/upload`, {
477
+ const res = await chunkPRTXAIIC_js.sonorFetch(`${config.apiUrl}/public/images/upload`, {
478
478
  method: "POST",
479
479
  body: formData
480
480
  }, { apiKey: config.apiKey, retries: 0, timeoutMs: 6e4 });
@@ -484,7 +484,7 @@ async function uploadImage(config, file, options) {
484
484
  return res.json();
485
485
  }
486
486
  async function assignImageToSlot(config, slotId, options) {
487
- const res = await chunkH65OX263_js.sonorFetch(
487
+ const res = await chunkPRTXAIIC_js.sonorFetch(
488
488
  `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,
489
489
  {
490
490
  method: "POST",
@@ -511,7 +511,7 @@ async function assignImageToSlot(config, slotId, options) {
511
511
  async function clearImageSlot(config, slotId, pagePath) {
512
512
  const params = new URLSearchParams();
513
513
  if (pagePath) params.set("page_path", pagePath);
514
- const res = await chunkH65OX263_js.sonorFetch(
514
+ const res = await chunkPRTXAIIC_js.sonorFetch(
515
515
  `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,
516
516
  { method: "DELETE" },
517
517
  { apiKey: config.apiKey, retries: 0 }
@@ -529,5 +529,5 @@ exports.fetchManagedImage = fetchManagedImage;
529
529
  exports.fetchManagedImages = fetchManagedImages;
530
530
  exports.listImageFiles = listImageFiles;
531
531
  exports.uploadImage = uploadImage;
532
- //# sourceMappingURL=chunk-YKUEFRZI.js.map
533
- //# sourceMappingURL=chunk-YKUEFRZI.js.map
532
+ //# sourceMappingURL=chunk-4RY7JETY.js.map
533
+ //# sourceMappingURL=chunk-4RY7JETY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/images/ManagedImage.tsx","../src/images/api.ts"],"names":["useState","useCallback","sonorFetch","useEffect","jsx","jsxs"],"mappings":"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","file":"chunk-YKUEFRZI.js","sourcesContent":["/**\n * ManagedImage - Portal-managed image component\n * \n * Features:\n * - Fetches images from Portal API via API key (never direct Supabase)\n * - Dev mode: Click to open image picker modal\n * - Supports responsive variants\n * - Automatic focal point handling\n * - Placeholder state for empty slots\n * \n * @example\n * ```tsx\n * <ManagedImage \n * slotId=\"hero-background\"\n * alt=\"Hero background image\"\n * className=\"w-full h-96 object-cover\"\n * />\n * ```\n */\n\n'use client'\n\nimport React, { useState, useEffect, useCallback } from 'react'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ManagedImageData {\n id: string\n slot_id: string\n page_path: string | null\n file_id: string | null\n external_url: string | null\n alt_text: string | null\n title: string | null\n caption: string | null\n focal_point_x: number\n focal_point_y: number\n aspect_ratio: string | null\n public_url?: string\n is_placeholder: boolean\n}\n\nexport interface ImageFile {\n id: string\n filename: string\n storage_path: string\n mime_type: string\n file_size: number\n folder_path: string | null\n public_url?: string\n}\n\nexport interface ManagedImageProps {\n /** API key for Portal API */\n apiKey?: string\n /** API URL (defaults to https://api.sonor.io) */\n apiUrl?: string\n /** Unique slot identifier (e.g., 'hero-background', 'about-team-1') */\n slotId: string\n /** Page path for page-specific slots (defaults to current path) */\n pagePath?: string\n /** Fallback alt text if not set in Portal */\n alt?: string\n /** CSS class names */\n className?: string\n /** Image width */\n width?: number | string\n /** Image height */\n height?: number | string\n /** CSS object-fit property */\n objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\n /** Fallback image URL when no image assigned */\n fallback?: string\n /** Custom placeholder component */\n placeholder?: React.ReactNode\n /** Called when image loads */\n onLoad?: () => void\n /** Called on error */\n onError?: (error: Error) => void\n /** Priority loading (Next.js Image optimization) */\n priority?: boolean\n /** Additional styles */\n style?: React.CSSProperties\n /** Enable dev picker even outside dev mode */\n forceDevMode?: boolean\n}\n\n// Check if we're in dev mode. `?sonor_dev=true` opens the picker on any host.\n// (The Uptrade-era `uptrade_dev` param is gone: nothing in the workspace sent it.)\nconst isDevMode = (): boolean => {\n if (typeof window === 'undefined') return false\n return (\n process.env.NODE_ENV === 'development' ||\n window.location.hostname === 'localhost' ||\n window.location.hostname === '127.0.0.1' ||\n new URLSearchParams(window.location.search).get('sonor_dev') === 'true'\n )\n}\n\nexport function ManagedImage({\n apiKey = process.env.SONOR_API_KEY,\n apiUrl = process.env.SONOR_API_URL || 'https://api.sonor.io',\n slotId,\n pagePath,\n alt,\n className = '',\n width,\n height,\n objectFit = 'cover',\n fallback,\n placeholder,\n onLoad,\n onError,\n priority,\n style,\n forceDevMode,\n}: ManagedImageProps) {\n const [imageData, setImageData] = useState<ManagedImageData | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n const [showPicker, setShowPicker] = useState(false)\n const [devMode] = useState(() => forceDevMode || isDevMode())\n\n // Get current page path if not provided\n const currentPath = pagePath ?? (typeof window !== 'undefined' ? window.location.pathname : '/')\n\n // Fetch image data from Portal API\n const fetchImage = useCallback(async () => {\n if (!apiKey || !apiUrl) {\n setLoading(false)\n return\n }\n\n try {\n const params = new URLSearchParams({ page_path: currentPath })\n const res = await sonorFetch(\n `${apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n const data = await res.json()\n setImageData(data.image)\n setError(null)\n } catch (err) {\n // warn, not error: a failed slot fetch must not fail the Lighthouse\n // best-practices errors-in-console audit on every page using this slot.\n console.warn('[ManagedImage] Fetch error:', err)\n setError(err instanceof Error ? err : new Error(String(err)))\n onError?.(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setLoading(false)\n }\n }, [apiKey, apiUrl, slotId, currentPath, onError])\n\n useEffect(() => {\n fetchImage()\n }, [fetchImage])\n\n // Calculate object-position from focal point\n const objectPosition = imageData\n ? `${imageData.focal_point_x}% ${imageData.focal_point_y}%`\n : '50% 50%'\n\n // Get the image URL\n const imageUrl = imageData?.public_url || imageData?.external_url || fallback\n\n // Handle click in dev mode\n const handleClick = (e: React.MouseEvent) => {\n if (devMode) {\n e.preventDefault()\n e.stopPropagation()\n setShowPicker(true)\n }\n }\n\n // Render placeholder state\n if (loading) {\n return (\n <div\n className={`bg-gray-200 animate-pulse ${className}`}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n />\n )\n }\n\n // No image assigned - show placeholder or dev picker hint\n if (!imageUrl) {\n if (placeholder) {\n return <>{placeholder}</>\n }\n\n return (\n <div\n onClick={handleClick}\n className={`\n bg-gray-100 border-2 border-dashed border-gray-300 \n flex items-center justify-center text-gray-400\n ${devMode ? 'cursor-pointer hover:border-blue-400 hover:text-blue-500 hover:bg-blue-50' : ''}\n ${className}\n `}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n title={devMode ? `Click to add image for slot: ${slotId}` : undefined}\n >\n <div className=\"text-center p-4\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n {devMode && (\n <p className=\"text-sm font-medium\">Click to add image</p>\n )}\n <p className=\"text-xs mt-1\">{slotId}</p>\n </div>\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n }\n\n // Render the image\n return (\n <div className=\"relative\" style={{ width, height }}>\n <img\n src={imageUrl}\n alt={imageData?.alt_text || alt || ''}\n title={imageData?.title || undefined}\n data-managed-image=\"true\"\n data-slot-id={slotId}\n data-page-path={currentPath}\n className={className}\n style={{\n objectFit,\n objectPosition,\n width: width ?? '100%',\n height: height ?? 'auto',\n ...style,\n }}\n onLoad={onLoad}\n onError={() => onError?.(new Error('Image failed to load'))}\n loading={priority ? 'eager' : 'lazy'}\n onClick={handleClick}\n />\n\n {/* Dev mode overlay */}\n {devMode && (\n <div\n className=\"absolute inset-0 bg-black/0 hover:bg-black/30 transition-colors cursor-pointer flex items-center justify-center opacity-0 hover:opacity-100\"\n onClick={handleClick}\n >\n <div className=\"bg-white/90 px-3 py-1.5 rounded-lg shadow-lg text-sm font-medium text-gray-700\">\n Edit Image\n </div>\n </div>\n )}\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n currentImage={imageData}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n}\n\n// ============================================================================\n// IMAGE PICKER MODAL\n// ============================================================================\n\ninterface ImagePickerModalProps {\n slotId: string\n pagePath: string\n config: any\n currentImage?: ManagedImageData | null\n onClose: () => void\n onSelect: () => void\n}\n\nfunction ImagePickerModal({\n slotId,\n pagePath,\n config,\n currentImage,\n onClose,\n onSelect,\n}: ImagePickerModalProps) {\n const [files, setFiles] = useState<ImageFile[]>([])\n const [folders, setFolders] = useState<string[]>([])\n const [currentFolder, setCurrentFolder] = useState<string>('')\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(true)\n const [uploading, setUploading] = useState(false)\n const [altText, setAltText] = useState(currentImage?.alt_text || '')\n\n // Fetch available files\n const fetchFiles = useCallback(async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n setLoading(true)\n try {\n const params = new URLSearchParams()\n if (currentFolder) params.set('folder', currentFolder)\n if (search) params.set('search', search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (res.ok) {\n const data = await res.json()\n setFiles(data.files || [])\n setFolders(data.folders || [])\n }\n } catch (err) {\n console.warn('[ImagePicker] Fetch error:', err)\n } finally {\n setLoading(false)\n }\n }, [config?.apiKey, config?.apiUrl, currentFolder, search])\n\n useEffect(() => {\n fetchFiles()\n }, [fetchFiles])\n\n // Select an existing file\n const handleSelectFile = async (file: ImageFile) => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: pagePath,\n file_id: file.id,\n alt_text: altText || file.filename,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Select error:', err)\n }\n }\n\n // Upload new file\n const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file || !config?.apiKey || !config?.apiUrl) return\n\n setUploading(true)\n try {\n const formData = new FormData()\n formData.append('file', file)\n formData.append('slot_id', slotId)\n formData.append('page_path', pagePath)\n formData.append('folder', currentFolder || 'Website/Images')\n if (altText) formData.append('alt_text', altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long\n // timeout, no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Upload error:', err)\n } finally {\n setUploading(false)\n }\n }\n\n // Clear the slot\n const handleClear = async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const params = new URLSearchParams({ page_path: pagePath })\n await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n onSelect()\n } catch (err) {\n console.warn('[ImagePicker] Clear error:', err)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-[99999] bg-black/50 flex items-center justify-center p-4\"\n onClick={onClose}\n >\n <div\n className=\"bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-4 border-b\">\n <div>\n <h2 className=\"text-lg font-semibold\">Select Image</h2>\n <p className=\"text-sm text-gray-500\">Slot: {slotId}</p>\n </div>\n <button\n onClick={onClose}\n className=\"text-gray-400 hover:text-gray-600 p-2\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-4 overflow-y-auto\" style={{ maxHeight: 'calc(90vh - 180px)' }}>\n {/* Upload & Search */}\n <div className=\"flex gap-4 mb-4\">\n <div className=\"flex-1\">\n <input\n type=\"text\"\n placeholder=\"Search images...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n <label className=\"px-4 py-2 bg-blue-600 text-white rounded-lg cursor-pointer hover:bg-blue-700 text-sm font-medium flex items-center gap-2\">\n {uploading ? 'Uploading...' : 'Upload New'}\n <input\n type=\"file\"\n accept=\"image/*\"\n onChange={handleUpload}\n disabled={uploading}\n className=\"hidden\"\n />\n </label>\n {currentImage?.file_id && (\n <button\n onClick={handleClear}\n className=\"px-4 py-2 border border-red-200 text-red-600 rounded-lg hover:bg-red-50 text-sm\"\n >\n Remove\n </button>\n )}\n </div>\n\n {/* Alt text input */}\n <div className=\"mb-4\">\n <input\n type=\"text\"\n placeholder=\"Alt text for image...\"\n value={altText}\n onChange={(e) => setAltText(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n\n {/* Folder navigation */}\n {folders.length > 0 && (\n <div className=\"flex gap-2 mb-4 flex-wrap\">\n <button\n onClick={() => setCurrentFolder('')}\n className={`px-3 py-1 text-sm rounded-full ${\n !currentFolder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n All\n </button>\n {folders.map((folder) => (\n <button\n key={folder}\n onClick={() => setCurrentFolder(folder)}\n className={`px-3 py-1 text-sm rounded-full ${\n currentFolder === folder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n {folder}\n </button>\n ))}\n </div>\n )}\n\n {/* File grid */}\n {loading ? (\n <div className=\"grid grid-cols-4 gap-4\">\n {[...Array(8)].map((_, i) => (\n <div key={i} className=\"aspect-square bg-gray-200 rounded-lg animate-pulse\" />\n ))}\n </div>\n ) : files.length === 0 ? (\n <div className=\"text-center py-12 text-gray-500\">\n <p>No images found</p>\n <p className=\"text-sm mt-1\">Upload a new image to get started</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-4 gap-4\">\n {files.map((file) => (\n <button\n key={file.id}\n onClick={() => handleSelectFile(file)}\n className={`\n aspect-square rounded-lg overflow-hidden border-2 transition-all\n hover:border-blue-400 hover:shadow-lg\n ${currentImage?.file_id === file.id ? 'border-blue-500 ring-2 ring-blue-200' : 'border-gray-200'}\n `}\n >\n <img\n src={file.public_url}\n alt={file.filename}\n className=\"w-full h-full object-cover\"\n />\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"p-4 border-t bg-gray-50 flex justify-end\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-lg text-sm\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ManagedImage\n","/**\n * Images API functions\n * \n * All functions use Portal API with API key authentication.\n * Never makes direct Supabase calls.\n */\n\nimport type { ManagedImageData, ImageFile } from './ManagedImage'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ImageApiConfig {\n apiUrl: string\n apiKey: string\n}\n\n/**\n * Fetch a managed image for a specific slot\n */\nexport async function fetchManagedImage(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ image: ManagedImageData | null; is_placeholder: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Fetch all managed images for the project\n */\nexport async function fetchManagedImages(\n config: ImageApiConfig,\n options?: {\n pagePath?: string\n category?: string\n includePlaceholders?: boolean\n },\n): Promise<{ images: ManagedImageData[] }> {\n const params = new URLSearchParams()\n if (options?.pagePath) params.set('page_path', options.pagePath)\n if (options?.category) params.set('category', options.category)\n if (options?.includePlaceholders) params.set('include_placeholders', 'true')\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch images: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * List available image files in the project\n */\nexport async function listImageFiles(\n config: ImageApiConfig,\n options?: {\n folder?: string\n search?: string\n },\n): Promise<{ files: ImageFile[]; folders: string[] }> {\n const params = new URLSearchParams()\n if (options?.folder) params.set('folder', options.folder)\n if (options?.search) params.set('search', options.search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to list files: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Upload a new image\n */\nexport async function uploadImage(\n config: ImageApiConfig,\n file: File,\n options?: {\n slotId?: string\n pagePath?: string\n folder?: string\n altText?: string\n },\n): Promise<{ file: ImageFile; image?: ManagedImageData }> {\n const formData = new FormData()\n formData.append('file', file)\n if (options?.slotId) formData.append('slot_id', options.slotId)\n if (options?.pagePath) formData.append('page_path', options.pagePath)\n if (options?.folder) formData.append('folder', options.folder)\n if (options?.altText) formData.append('alt_text', options.altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long timeout,\n // no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (!res.ok) {\n throw new Error(`Failed to upload image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Assign an existing file to an image slot\n */\nexport async function assignImageToSlot(\n config: ImageApiConfig,\n slotId: string,\n options: {\n fileId?: string\n externalUrl?: string\n pagePath?: string\n altText?: string\n title?: string\n caption?: string\n focalPointX?: number\n focalPointY?: number\n aspectRatio?: string\n },\n): Promise<{ image: ManagedImageData }> {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: options.pagePath,\n file_id: options.fileId,\n external_url: options.externalUrl,\n alt_text: options.altText,\n title: options.title,\n caption: options.caption,\n focal_point_x: options.focalPointX,\n focal_point_y: options.focalPointY,\n aspect_ratio: options.aspectRatio,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to assign image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Clear an image from a slot (keeps the file)\n */\nexport async function clearImageSlot(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ success: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to clear slot: ${res.status}`)\n }\n\n return res.json()\n}\n"]}
1
+ {"version":3,"sources":["../src/images/ManagedImage.tsx","../src/images/api.ts"],"names":["useState","useCallback","sonorFetch","useEffect","jsx","jsxs"],"mappings":"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","file":"chunk-4RY7JETY.js","sourcesContent":["/**\n * ManagedImage - Portal-managed image component\n * \n * Features:\n * - Fetches images from Portal API via API key (never direct Supabase)\n * - Dev mode: Click to open image picker modal\n * - Supports responsive variants\n * - Automatic focal point handling\n * - Placeholder state for empty slots\n * \n * @example\n * ```tsx\n * <ManagedImage \n * slotId=\"hero-background\"\n * alt=\"Hero background image\"\n * className=\"w-full h-96 object-cover\"\n * />\n * ```\n */\n\n'use client'\n\nimport React, { useState, useEffect, useCallback } from 'react'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ManagedImageData {\n id: string\n slot_id: string\n page_path: string | null\n file_id: string | null\n external_url: string | null\n alt_text: string | null\n title: string | null\n caption: string | null\n focal_point_x: number\n focal_point_y: number\n aspect_ratio: string | null\n public_url?: string\n is_placeholder: boolean\n}\n\nexport interface ImageFile {\n id: string\n filename: string\n storage_path: string\n mime_type: string\n file_size: number\n folder_path: string | null\n public_url?: string\n}\n\nexport interface ManagedImageProps {\n /** API key for Portal API */\n apiKey?: string\n /** API URL (defaults to https://api.sonor.io) */\n apiUrl?: string\n /** Unique slot identifier (e.g., 'hero-background', 'about-team-1') */\n slotId: string\n /** Page path for page-specific slots (defaults to current path) */\n pagePath?: string\n /** Fallback alt text if not set in Portal */\n alt?: string\n /** CSS class names */\n className?: string\n /** Image width */\n width?: number | string\n /** Image height */\n height?: number | string\n /** CSS object-fit property */\n objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\n /** Fallback image URL when no image assigned */\n fallback?: string\n /** Custom placeholder component */\n placeholder?: React.ReactNode\n /** Called when image loads */\n onLoad?: () => void\n /** Called on error */\n onError?: (error: Error) => void\n /** Priority loading (Next.js Image optimization) */\n priority?: boolean\n /** Additional styles */\n style?: React.CSSProperties\n /** Enable dev picker even outside dev mode */\n forceDevMode?: boolean\n}\n\n// Check if we're in dev mode. `?sonor_dev=true` opens the picker on any host.\n// (The Uptrade-era `uptrade_dev` param is gone: nothing in the workspace sent it.)\nconst isDevMode = (): boolean => {\n if (typeof window === 'undefined') return false\n return (\n process.env.NODE_ENV === 'development' ||\n window.location.hostname === 'localhost' ||\n window.location.hostname === '127.0.0.1' ||\n new URLSearchParams(window.location.search).get('sonor_dev') === 'true'\n )\n}\n\nexport function ManagedImage({\n apiKey = process.env.SONOR_API_KEY,\n apiUrl = process.env.SONOR_API_URL || 'https://api.sonor.io',\n slotId,\n pagePath,\n alt,\n className = '',\n width,\n height,\n objectFit = 'cover',\n fallback,\n placeholder,\n onLoad,\n onError,\n priority,\n style,\n forceDevMode,\n}: ManagedImageProps) {\n const [imageData, setImageData] = useState<ManagedImageData | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n const [showPicker, setShowPicker] = useState(false)\n const [devMode] = useState(() => forceDevMode || isDevMode())\n\n // Get current page path if not provided\n const currentPath = pagePath ?? (typeof window !== 'undefined' ? window.location.pathname : '/')\n\n // Fetch image data from Portal API\n const fetchImage = useCallback(async () => {\n if (!apiKey || !apiUrl) {\n setLoading(false)\n return\n }\n\n try {\n const params = new URLSearchParams({ page_path: currentPath })\n const res = await sonorFetch(\n `${apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n const data = await res.json()\n setImageData(data.image)\n setError(null)\n } catch (err) {\n // warn, not error: a failed slot fetch must not fail the Lighthouse\n // best-practices errors-in-console audit on every page using this slot.\n console.warn('[ManagedImage] Fetch error:', err)\n setError(err instanceof Error ? err : new Error(String(err)))\n onError?.(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setLoading(false)\n }\n }, [apiKey, apiUrl, slotId, currentPath, onError])\n\n useEffect(() => {\n fetchImage()\n }, [fetchImage])\n\n // Calculate object-position from focal point\n const objectPosition = imageData\n ? `${imageData.focal_point_x}% ${imageData.focal_point_y}%`\n : '50% 50%'\n\n // Get the image URL\n const imageUrl = imageData?.public_url || imageData?.external_url || fallback\n\n // Handle click in dev mode\n const handleClick = (e: React.MouseEvent) => {\n if (devMode) {\n e.preventDefault()\n e.stopPropagation()\n setShowPicker(true)\n }\n }\n\n // Render placeholder state\n if (loading) {\n return (\n <div\n className={`bg-gray-200 animate-pulse ${className}`}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n />\n )\n }\n\n // No image assigned - show placeholder or dev picker hint\n if (!imageUrl) {\n if (placeholder) {\n return <>{placeholder}</>\n }\n\n return (\n <div\n onClick={handleClick}\n className={`\n bg-gray-100 border-2 border-dashed border-gray-300 \n flex items-center justify-center text-gray-400\n ${devMode ? 'cursor-pointer hover:border-blue-400 hover:text-blue-500 hover:bg-blue-50' : ''}\n ${className}\n `}\n style={{\n width: width ?? '100%',\n height: height ?? 200,\n ...style,\n }}\n title={devMode ? `Click to add image for slot: ${slotId}` : undefined}\n >\n <div className=\"text-center p-4\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n {devMode && (\n <p className=\"text-sm font-medium\">Click to add image</p>\n )}\n <p className=\"text-xs mt-1\">{slotId}</p>\n </div>\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n }\n\n // Render the image\n return (\n <div className=\"relative\" style={{ width, height }}>\n <img\n src={imageUrl}\n alt={imageData?.alt_text || alt || ''}\n title={imageData?.title || undefined}\n data-managed-image=\"true\"\n data-slot-id={slotId}\n data-page-path={currentPath}\n className={className}\n style={{\n objectFit,\n objectPosition,\n width: width ?? '100%',\n height: height ?? 'auto',\n ...style,\n }}\n onLoad={onLoad}\n onError={() => onError?.(new Error('Image failed to load'))}\n loading={priority ? 'eager' : 'lazy'}\n onClick={handleClick}\n />\n\n {/* Dev mode overlay */}\n {devMode && (\n <div\n className=\"absolute inset-0 bg-black/0 hover:bg-black/30 transition-colors cursor-pointer flex items-center justify-center opacity-0 hover:opacity-100\"\n onClick={handleClick}\n >\n <div className=\"bg-white/90 px-3 py-1.5 rounded-lg shadow-lg text-sm font-medium text-gray-700\">\n Edit Image\n </div>\n </div>\n )}\n\n {showPicker && (\n <ImagePickerModal\n slotId={slotId}\n pagePath={currentPath}\n config={{ apiKey, apiUrl }}\n currentImage={imageData}\n onClose={() => setShowPicker(false)}\n onSelect={() => {\n setShowPicker(false)\n fetchImage()\n }}\n />\n )}\n </div>\n )\n}\n\n// ============================================================================\n// IMAGE PICKER MODAL\n// ============================================================================\n\ninterface ImagePickerModalProps {\n slotId: string\n pagePath: string\n config: any\n currentImage?: ManagedImageData | null\n onClose: () => void\n onSelect: () => void\n}\n\nfunction ImagePickerModal({\n slotId,\n pagePath,\n config,\n currentImage,\n onClose,\n onSelect,\n}: ImagePickerModalProps) {\n const [files, setFiles] = useState<ImageFile[]>([])\n const [folders, setFolders] = useState<string[]>([])\n const [currentFolder, setCurrentFolder] = useState<string>('')\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(true)\n const [uploading, setUploading] = useState(false)\n const [altText, setAltText] = useState(currentImage?.alt_text || '')\n\n // Fetch available files\n const fetchFiles = useCallback(async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n setLoading(true)\n try {\n const params = new URLSearchParams()\n if (currentFolder) params.set('folder', currentFolder)\n if (search) params.set('search', search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (res.ok) {\n const data = await res.json()\n setFiles(data.files || [])\n setFolders(data.folders || [])\n }\n } catch (err) {\n console.warn('[ImagePicker] Fetch error:', err)\n } finally {\n setLoading(false)\n }\n }, [config?.apiKey, config?.apiUrl, currentFolder, search])\n\n useEffect(() => {\n fetchFiles()\n }, [fetchFiles])\n\n // Select an existing file\n const handleSelectFile = async (file: ImageFile) => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: pagePath,\n file_id: file.id,\n alt_text: altText || file.filename,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Select error:', err)\n }\n }\n\n // Upload new file\n const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (!file || !config?.apiKey || !config?.apiUrl) return\n\n setUploading(true)\n try {\n const formData = new FormData()\n formData.append('file', file)\n formData.append('slot_id', slotId)\n formData.append('page_path', pagePath)\n formData.append('folder', currentFolder || 'Website/Images')\n if (altText) formData.append('alt_text', altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long\n // timeout, no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (res.ok) {\n onSelect()\n }\n } catch (err) {\n console.warn('[ImagePicker] Upload error:', err)\n } finally {\n setUploading(false)\n }\n }\n\n // Clear the slot\n const handleClear = async () => {\n if (!config?.apiKey || !config?.apiUrl) return\n\n try {\n const params = new URLSearchParams({ page_path: pagePath })\n await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n onSelect()\n } catch (err) {\n console.warn('[ImagePicker] Clear error:', err)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-[99999] bg-black/50 flex items-center justify-center p-4\"\n onClick={onClose}\n >\n <div\n className=\"bg-white rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-4 border-b\">\n <div>\n <h2 className=\"text-lg font-semibold\">Select Image</h2>\n <p className=\"text-sm text-gray-500\">Slot: {slotId}</p>\n </div>\n <button\n onClick={onClose}\n className=\"text-gray-400 hover:text-gray-600 p-2\"\n >\n <svg className=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-4 overflow-y-auto\" style={{ maxHeight: 'calc(90vh - 180px)' }}>\n {/* Upload & Search */}\n <div className=\"flex gap-4 mb-4\">\n <div className=\"flex-1\">\n <input\n type=\"text\"\n placeholder=\"Search images...\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n <label className=\"px-4 py-2 bg-blue-600 text-white rounded-lg cursor-pointer hover:bg-blue-700 text-sm font-medium flex items-center gap-2\">\n {uploading ? 'Uploading...' : 'Upload New'}\n <input\n type=\"file\"\n accept=\"image/*\"\n onChange={handleUpload}\n disabled={uploading}\n className=\"hidden\"\n />\n </label>\n {currentImage?.file_id && (\n <button\n onClick={handleClear}\n className=\"px-4 py-2 border border-red-200 text-red-600 rounded-lg hover:bg-red-50 text-sm\"\n >\n Remove\n </button>\n )}\n </div>\n\n {/* Alt text input */}\n <div className=\"mb-4\">\n <input\n type=\"text\"\n placeholder=\"Alt text for image...\"\n value={altText}\n onChange={(e) => setAltText(e.target.value)}\n className=\"w-full px-3 py-2 border rounded-lg text-sm\"\n />\n </div>\n\n {/* Folder navigation */}\n {folders.length > 0 && (\n <div className=\"flex gap-2 mb-4 flex-wrap\">\n <button\n onClick={() => setCurrentFolder('')}\n className={`px-3 py-1 text-sm rounded-full ${\n !currentFolder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n All\n </button>\n {folders.map((folder) => (\n <button\n key={folder}\n onClick={() => setCurrentFolder(folder)}\n className={`px-3 py-1 text-sm rounded-full ${\n currentFolder === folder ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 hover:bg-gray-200'\n }`}\n >\n {folder}\n </button>\n ))}\n </div>\n )}\n\n {/* File grid */}\n {loading ? (\n <div className=\"grid grid-cols-4 gap-4\">\n {[...Array(8)].map((_, i) => (\n <div key={i} className=\"aspect-square bg-gray-200 rounded-lg animate-pulse\" />\n ))}\n </div>\n ) : files.length === 0 ? (\n <div className=\"text-center py-12 text-gray-500\">\n <p>No images found</p>\n <p className=\"text-sm mt-1\">Upload a new image to get started</p>\n </div>\n ) : (\n <div className=\"grid grid-cols-4 gap-4\">\n {files.map((file) => (\n <button\n key={file.id}\n onClick={() => handleSelectFile(file)}\n className={`\n aspect-square rounded-lg overflow-hidden border-2 transition-all\n hover:border-blue-400 hover:shadow-lg\n ${currentImage?.file_id === file.id ? 'border-blue-500 ring-2 ring-blue-200' : 'border-gray-200'}\n `}\n >\n <img\n src={file.public_url}\n alt={file.filename}\n className=\"w-full h-full object-cover\"\n />\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"p-4 border-t bg-gray-50 flex justify-end\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-lg text-sm\"\n >\n Cancel\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ManagedImage\n","/**\n * Images API functions\n * \n * All functions use Portal API with API key authentication.\n * Never makes direct Supabase calls.\n */\n\nimport type { ManagedImageData, ImageFile } from './ManagedImage'\nimport { sonorFetch } from '../shared/sonorFetch'\n\nexport interface ImageApiConfig {\n apiUrl: string\n apiKey: string\n}\n\n/**\n * Fetch a managed image for a specific slot\n */\nexport async function fetchManagedImage(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ image: ManagedImageData | null; is_placeholder: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Fetch all managed images for the project\n */\nexport async function fetchManagedImages(\n config: ImageApiConfig,\n options?: {\n pagePath?: string\n category?: string\n includePlaceholders?: boolean\n },\n): Promise<{ images: ManagedImageData[] }> {\n const params = new URLSearchParams()\n if (options?.pagePath) params.set('page_path', options.pagePath)\n if (options?.category) params.set('category', options.category)\n if (options?.includePlaceholders) params.set('include_placeholders', 'true')\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to fetch images: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * List available image files in the project\n */\nexport async function listImageFiles(\n config: ImageApiConfig,\n options?: {\n folder?: string\n search?: string\n },\n): Promise<{ files: ImageFile[]; folders: string[] }> {\n const params = new URLSearchParams()\n if (options?.folder) params.set('folder', options.folder)\n if (options?.search) params.set('search', options.search)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/files?${params}`,\n { headers: { 'Content-Type': 'application/json' } },\n { apiKey: config.apiKey },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to list files: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Upload a new image\n */\nexport async function uploadImage(\n config: ImageApiConfig,\n file: File,\n options?: {\n slotId?: string\n pagePath?: string\n folder?: string\n altText?: string\n },\n): Promise<{ file: ImageFile; image?: ManagedImageData }> {\n const formData = new FormData()\n formData.append('file', file)\n if (options?.slotId) formData.append('slot_id', options.slotId)\n if (options?.pagePath) formData.append('page_path', options.pagePath)\n if (options?.folder) formData.append('folder', options.folder)\n if (options?.altText) formData.append('alt_text', options.altText)\n\n // No Content-Type — the browser sets the multipart boundary. Long timeout,\n // no retry: a retried upload would duplicate the file.\n const res = await sonorFetch(`${config.apiUrl}/public/images/upload`, {\n method: 'POST',\n body: formData,\n }, { apiKey: config.apiKey, retries: 0, timeoutMs: 60000 })\n\n if (!res.ok) {\n throw new Error(`Failed to upload image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Assign an existing file to an image slot\n */\nexport async function assignImageToSlot(\n config: ImageApiConfig,\n slotId: string,\n options: {\n fileId?: string\n externalUrl?: string\n pagePath?: string\n altText?: string\n title?: string\n caption?: string\n focalPointX?: number\n focalPointY?: number\n aspectRatio?: string\n },\n): Promise<{ image: ManagedImageData }> {\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n page_path: options.pagePath,\n file_id: options.fileId,\n external_url: options.externalUrl,\n alt_text: options.altText,\n title: options.title,\n caption: options.caption,\n focal_point_x: options.focalPointX,\n focal_point_y: options.focalPointY,\n aspect_ratio: options.aspectRatio,\n }),\n },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to assign image: ${res.status}`)\n }\n\n return res.json()\n}\n\n/**\n * Clear an image from a slot (keeps the file)\n */\nexport async function clearImageSlot(\n config: ImageApiConfig,\n slotId: string,\n pagePath?: string,\n): Promise<{ success: boolean }> {\n const params = new URLSearchParams()\n if (pagePath) params.set('page_path', pagePath)\n\n const res = await sonorFetch(\n `${config.apiUrl}/public/images/slot/${encodeURIComponent(slotId)}?${params}`,\n { method: 'DELETE' },\n { apiKey: config.apiKey, retries: 0 },\n )\n\n if (!res.ok) {\n throw new Error(`Failed to clear slot: ${res.status}`)\n }\n\n return res.json()\n}\n"]}