@sonordev/site-kit 5.5.0 → 5.7.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 (392) hide show
  1. package/agent-manifest.json +11 -3
  2. package/dist/AnalyticsProvider-EWF7JN2X.mjs +11 -0
  3. package/dist/{AnalyticsProvider-KFXAH4GR.mjs.map → AnalyticsProvider-EWF7JN2X.mjs.map} +1 -1
  4. package/dist/AnalyticsProvider-GJFG7YXA.js +32 -0
  5. package/dist/{AnalyticsProvider-WDDW3IJW.js.map → AnalyticsProvider-GJFG7YXA.js.map} +1 -1
  6. package/dist/{BlogViewTracker-D4DIEP4Q.js → BlogViewTracker-2D3IJPJK.js} +6 -6
  7. package/dist/{BlogViewTracker-D4DIEP4Q.js.map → BlogViewTracker-2D3IJPJK.js.map} +1 -1
  8. package/dist/{BlogViewTracker-ZVEGGH3Y.mjs → BlogViewTracker-CKYG6MYU.mjs} +5 -5
  9. package/dist/{BlogViewTracker-ZVEGGH3Y.mjs.map → BlogViewTracker-CKYG6MYU.mjs.map} +1 -1
  10. package/dist/ChatWidget-AWP6GBVW.js +22 -0
  11. package/dist/{ChatWidget-2ZYPYIMQ.js.map → ChatWidget-AWP6GBVW.js.map} +1 -1
  12. package/dist/ChatWidget-Z5QXDZP3.mjs +13 -0
  13. package/dist/{ChatWidget-FYCCLMQE.mjs.map → ChatWidget-Z5QXDZP3.mjs.map} +1 -1
  14. package/dist/EngageWidget-BKEY5TPO.mjs +12 -0
  15. package/dist/{EngageWidget-6HUZYOY7.mjs.map → EngageWidget-BKEY5TPO.mjs.map} +1 -1
  16. package/dist/EngageWidget-VT4DYXVO.js +21 -0
  17. package/dist/{EngageWidget-MYQTBBW6.js.map → EngageWidget-VT4DYXVO.js.map} +1 -1
  18. package/dist/{FileField-JK2S24XU.js → FileField-62ZWZMQK.js} +6 -6
  19. package/dist/{FileField-JK2S24XU.js.map → FileField-62ZWZMQK.js.map} +1 -1
  20. package/dist/{FileField-OZZHWGPA.mjs → FileField-JJN5QKDL.mjs} +5 -5
  21. package/dist/{FileField-OZZHWGPA.mjs.map → FileField-JJN5QKDL.mjs.map} +1 -1
  22. package/dist/{FormSpotlight-XV42L72H.mjs → FormSpotlight-OTFB6QM5.mjs} +3 -3
  23. package/dist/{FormSpotlight-XV42L72H.mjs.map → FormSpotlight-OTFB6QM5.mjs.map} +1 -1
  24. package/dist/{FormSpotlight-5AXFQU5M.js → FormSpotlight-URS4XRS7.js} +15 -15
  25. package/dist/{FormSpotlight-5AXFQU5M.js.map → FormSpotlight-URS4XRS7.js.map} +1 -1
  26. package/dist/{FormStage-HATUHNRV.js → FormStage-FVKMIV73.js} +13 -13
  27. package/dist/{FormStage-HATUHNRV.js.map → FormStage-FVKMIV73.js.map} +1 -1
  28. package/dist/{FormStage-RUK675HV.mjs → FormStage-VPGOCMAV.mjs} +3 -3
  29. package/dist/{FormStage-RUK675HV.mjs.map → FormStage-VPGOCMAV.mjs.map} +1 -1
  30. package/dist/ManagedForm-CXVDJMHN.mjs +14 -0
  31. package/dist/{ManagedForm-OA3MNGXT.mjs.map → ManagedForm-CXVDJMHN.mjs.map} +1 -1
  32. package/dist/ManagedForm-FGNTDGED.js +23 -0
  33. package/dist/{ManagedForm-JWEXJEXK.js.map → ManagedForm-FGNTDGED.js.map} +1 -1
  34. package/dist/{ManagedNewsletterForm-AAHH63KT.js → ManagedNewsletterForm-3O5L44AZ.js} +8 -8
  35. package/dist/{ManagedNewsletterForm-AAHH63KT.js.map → ManagedNewsletterForm-3O5L44AZ.js.map} +1 -1
  36. package/dist/{ManagedNewsletterForm-HZKTNWLW.mjs → ManagedNewsletterForm-SQYB4BZU.mjs} +7 -7
  37. package/dist/{ManagedNewsletterForm-HZKTNWLW.mjs.map → ManagedNewsletterForm-SQYB4BZU.mjs.map} +1 -1
  38. package/dist/{SignalCore-X3GDGBZD.mjs → SignalCore-M2PKKIGH.mjs} +5 -5
  39. package/dist/{SignalCore-X3GDGBZD.mjs.map → SignalCore-M2PKKIGH.mjs.map} +1 -1
  40. package/dist/{SignalCore-YSNZYBKJ.js → SignalCore-RFBOBNLQ.js} +11 -11
  41. package/dist/{SignalCore-YSNZYBKJ.js.map → SignalCore-RFBOBNLQ.js.map} +1 -1
  42. package/dist/SitemapSync-4OVMIIGC.mjs +9 -0
  43. package/dist/{SitemapSync-2PTDBH5E.mjs.map → SitemapSync-4OVMIIGC.mjs.map} +1 -1
  44. package/dist/SitemapSync-RK3SQ4M2.js +18 -0
  45. package/dist/{SitemapSync-3SFAI546.js.map → SitemapSync-RK3SQ4M2.js.map} +1 -1
  46. package/dist/SitemapSync.d.ts +3 -2
  47. package/dist/SitemapSync.d.ts.map +1 -1
  48. package/dist/analytics/AnalyticsProvider.d.ts +3 -1
  49. package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
  50. package/dist/analytics/WebVitals.d.ts +3 -1
  51. package/dist/analytics/WebVitals.d.ts.map +1 -1
  52. package/dist/analytics/index.js +13 -13
  53. package/dist/analytics/index.mjs +5 -5
  54. package/dist/analytics/send-gate.d.ts +8 -37
  55. package/dist/analytics/send-gate.d.ts.map +1 -1
  56. package/dist/blog/index.js +20 -20
  57. package/dist/blog/index.mjs +3 -3
  58. package/dist/blog/metadata-images.test.d.ts +2 -0
  59. package/dist/blog/metadata-images.test.d.ts.map +1 -0
  60. package/dist/blog/server-core.d.ts +31 -6
  61. package/dist/blog/server-core.d.ts.map +1 -1
  62. package/dist/blog/server-ui.js +16 -16
  63. package/dist/blog/server-ui.mjs +3 -3
  64. package/dist/blog/server.d.ts +31 -6
  65. package/dist/blog/server.d.ts.map +1 -1
  66. package/dist/blog/server.js +40 -40
  67. package/dist/blog/server.mjs +1 -1
  68. package/dist/blog/static-params.test.d.ts +2 -0
  69. package/dist/blog/static-params.test.d.ts.map +1 -0
  70. package/dist/{chunk-KAUUGRYB.js → chunk-2N27LCZH.js} +26 -32
  71. package/dist/chunk-2N27LCZH.js.map +1 -0
  72. package/dist/{chunk-R4MX6EOM.mjs → chunk-3CLP35TT.mjs} +7 -7
  73. package/dist/{chunk-R4MX6EOM.mjs.map → chunk-3CLP35TT.mjs.map} +1 -1
  74. package/dist/{chunk-SQVYLIIN.js → chunk-3S5JN6KL.js} +16 -19
  75. package/dist/chunk-3S5JN6KL.js.map +1 -0
  76. package/dist/chunk-3UC6JETG.js +32 -0
  77. package/dist/chunk-3UC6JETG.js.map +1 -0
  78. package/dist/{chunk-CT5REGAK.js → chunk-3YQILJKJ.js} +14 -14
  79. package/dist/{chunk-CT5REGAK.js.map → chunk-3YQILJKJ.js.map} +1 -1
  80. package/dist/{chunk-3B6CXGAK.mjs → chunk-47XQWV4S.mjs} +3 -3
  81. package/dist/{chunk-3B6CXGAK.mjs.map → chunk-47XQWV4S.mjs.map} +1 -1
  82. package/dist/{chunk-RZUZMUTN.mjs → chunk-4A5V73SR.mjs} +21 -9
  83. package/dist/chunk-4A5V73SR.mjs.map +1 -0
  84. package/dist/{chunk-FYVLQ3OU.js → chunk-4UVM7E2W.js} +3 -3
  85. package/dist/{chunk-FYVLQ3OU.js.map → chunk-4UVM7E2W.js.map} +1 -1
  86. package/dist/{chunk-HFJQMIFM.js → chunk-4WBTM6YE.js} +4 -4
  87. package/dist/{chunk-HFJQMIFM.js.map → chunk-4WBTM6YE.js.map} +1 -1
  88. package/dist/{chunk-XQYC4KMH.mjs → chunk-57AFHENV.mjs} +48 -42
  89. package/dist/chunk-57AFHENV.mjs.map +1 -0
  90. package/dist/chunk-5RNAUYWE.js +50 -0
  91. package/dist/chunk-5RNAUYWE.js.map +1 -0
  92. package/dist/chunk-5TXXTYXL.js +8 -0
  93. package/dist/{chunk-SUZ3ZLB2.js.map → chunk-5TXXTYXL.js.map} +1 -1
  94. package/dist/{chunk-RU54J2PY.mjs → chunk-6FC5Q4KU.mjs} +3 -3
  95. package/dist/{chunk-RU54J2PY.mjs.map → chunk-6FC5Q4KU.mjs.map} +1 -1
  96. package/dist/{chunk-ZRQFG3L6.mjs → chunk-7ZX6TO6C.mjs} +4 -4
  97. package/dist/{chunk-ZRQFG3L6.mjs.map → chunk-7ZX6TO6C.mjs.map} +1 -1
  98. package/dist/chunk-A6UYV475.mjs +45 -0
  99. package/dist/chunk-A6UYV475.mjs.map +1 -0
  100. package/dist/{chunk-4XGACM7D.mjs → chunk-ABZGEHTC.mjs} +3 -3
  101. package/dist/{chunk-4XGACM7D.mjs.map → chunk-ABZGEHTC.mjs.map} +1 -1
  102. package/dist/chunk-AWK57R5S.mjs +29 -0
  103. package/dist/chunk-AWK57R5S.mjs.map +1 -0
  104. package/dist/{chunk-EEQYKMGH.mjs → chunk-BFJOZ3MU.mjs} +23 -17
  105. package/dist/chunk-BFJOZ3MU.mjs.map +1 -0
  106. package/dist/{chunk-HX3BRMOX.js → chunk-BFM5PEFV.js} +3 -3
  107. package/dist/{chunk-HX3BRMOX.js.map → chunk-BFM5PEFV.js.map} +1 -1
  108. package/dist/{chunk-VYHRAICF.mjs → chunk-BQGEVMIR.mjs} +4 -4
  109. package/dist/{chunk-VYHRAICF.mjs.map → chunk-BQGEVMIR.mjs.map} +1 -1
  110. package/dist/{chunk-S6FEC6UT.mjs → chunk-BUJWXSYZ.mjs} +14 -17
  111. package/dist/chunk-BUJWXSYZ.mjs.map +1 -0
  112. package/dist/{chunk-VAS3LH5W.js → chunk-C4PZ2R3B.js} +55 -49
  113. package/dist/chunk-C4PZ2R3B.js.map +1 -0
  114. package/dist/{chunk-MU7IEPDG.mjs → chunk-C563AHZZ.mjs} +3 -3
  115. package/dist/{chunk-MU7IEPDG.mjs.map → chunk-C563AHZZ.mjs.map} +1 -1
  116. package/dist/{chunk-746RKQHA.js → chunk-CPY74A4F.js} +23 -17
  117. package/dist/chunk-CPY74A4F.js.map +1 -0
  118. package/dist/{chunk-UNPEMSLK.js → chunk-D553G64G.js} +24 -12
  119. package/dist/chunk-D553G64G.js.map +1 -0
  120. package/dist/{chunk-KPKQKFT4.js → chunk-DOB37PV4.js} +3 -3
  121. package/dist/{chunk-KPKQKFT4.js.map → chunk-DOB37PV4.js.map} +1 -1
  122. package/dist/{chunk-2OU4KBUN.js → chunk-ELQ4SRRR.js} +15 -15
  123. package/dist/{chunk-2OU4KBUN.js.map → chunk-ELQ4SRRR.js.map} +1 -1
  124. package/dist/{chunk-Q26VZNM2.js → chunk-F3AKYZOH.js} +3 -3
  125. package/dist/{chunk-Q26VZNM2.js.map → chunk-F3AKYZOH.js.map} +1 -1
  126. package/dist/{chunk-X2XFLYZ3.mjs → chunk-FBDHKYNF.mjs} +3 -3
  127. package/dist/{chunk-X2XFLYZ3.mjs.map → chunk-FBDHKYNF.mjs.map} +1 -1
  128. package/dist/{chunk-BNOQXDPJ.js → chunk-FEWWGEQF.js} +4 -4
  129. package/dist/{chunk-BNOQXDPJ.js.map → chunk-FEWWGEQF.js.map} +1 -1
  130. package/dist/{chunk-NZSFOZJV.js → chunk-FO4KGPGF.js} +2 -2
  131. package/dist/{chunk-NZSFOZJV.js.map → chunk-FO4KGPGF.js.map} +1 -1
  132. package/dist/{chunk-QEGUI2Q2.js → chunk-H65OX263.js} +15 -15
  133. package/dist/{chunk-QEGUI2Q2.js.map → chunk-H65OX263.js.map} +1 -1
  134. package/dist/{chunk-46BMNWE6.js → chunk-H6YVT3BL.js} +2 -2
  135. package/dist/{chunk-46BMNWE6.js.map → chunk-H6YVT3BL.js.map} +1 -1
  136. package/dist/{chunk-TX2QQ7IX.mjs → chunk-HBN4A2N4.mjs} +3 -3
  137. package/dist/{chunk-TX2QQ7IX.mjs.map → chunk-HBN4A2N4.mjs.map} +1 -1
  138. package/dist/{chunk-AJQI3WTN.mjs → chunk-ILNCUSXW.mjs} +2 -2
  139. package/dist/{chunk-AJQI3WTN.mjs.map → chunk-ILNCUSXW.mjs.map} +1 -1
  140. package/dist/{chunk-RMMHWSPP.mjs → chunk-JNAXDFC4.mjs} +3 -3
  141. package/dist/{chunk-RMMHWSPP.mjs.map → chunk-JNAXDFC4.mjs.map} +1 -1
  142. package/dist/{chunk-TALEV3IH.mjs → chunk-JQ7M6CVL.mjs} +3 -3
  143. package/dist/{chunk-TALEV3IH.mjs.map → chunk-JQ7M6CVL.mjs.map} +1 -1
  144. package/dist/{chunk-2CMSWJWC.js → chunk-JTCQJKJE.js} +18 -18
  145. package/dist/{chunk-2CMSWJWC.js.map → chunk-JTCQJKJE.js.map} +1 -1
  146. package/dist/{chunk-7PPNXORV.mjs → chunk-JTF4DFUF.mjs} +25 -31
  147. package/dist/chunk-JTF4DFUF.mjs.map +1 -0
  148. package/dist/{chunk-MCJF2KJ6.js → chunk-KXGD4E7G.js} +5 -5
  149. package/dist/{chunk-MCJF2KJ6.js.map → chunk-KXGD4E7G.js.map} +1 -1
  150. package/dist/chunk-L4V6TKMJ.mjs +94 -0
  151. package/dist/chunk-L4V6TKMJ.mjs.map +1 -0
  152. package/dist/{chunk-W5NVW23S.js → chunk-L7ACQ6PC.js} +4 -4
  153. package/dist/{chunk-W5NVW23S.js.map → chunk-L7ACQ6PC.js.map} +1 -1
  154. package/dist/{chunk-WIZRCI6J.mjs → chunk-M5GY2AI3.mjs} +3 -3
  155. package/dist/{chunk-WIZRCI6J.mjs.map → chunk-M5GY2AI3.mjs.map} +1 -1
  156. package/dist/{chunk-HBI67P7Y.mjs → chunk-MW2M6O7A.mjs} +18 -14
  157. package/dist/chunk-MW2M6O7A.mjs.map +1 -0
  158. package/dist/{chunk-A3F5GRNJ.js → chunk-NOU3JQJK.js} +8 -8
  159. package/dist/{chunk-A3F5GRNJ.js.map → chunk-NOU3JQJK.js.map} +1 -1
  160. package/dist/{chunk-DYULWKDC.mjs → chunk-O2VJZOR2.mjs} +14 -33
  161. package/dist/chunk-O2VJZOR2.mjs.map +1 -0
  162. package/dist/{chunk-FF5N5D3D.js → chunk-OYOO2OO5.js} +8 -8
  163. package/dist/{chunk-FF5N5D3D.js.map → chunk-OYOO2OO5.js.map} +1 -1
  164. package/dist/chunk-P4TB4ROG.js +110 -0
  165. package/dist/chunk-P4TB4ROG.js.map +1 -0
  166. package/dist/{chunk-V6NOM7PJ.mjs → chunk-Q7347KP6.mjs} +3 -3
  167. package/dist/{chunk-V6NOM7PJ.mjs.map → chunk-Q7347KP6.mjs.map} +1 -1
  168. package/dist/chunk-QRBPT6Z6.mjs +6 -0
  169. package/dist/{chunk-WDBCXRTT.mjs.map → chunk-QRBPT6Z6.mjs.map} +1 -1
  170. package/dist/{chunk-G5HUI4BO.mjs → chunk-R2SXXFXZ.mjs} +3 -3
  171. package/dist/{chunk-G5HUI4BO.mjs.map → chunk-R2SXXFXZ.mjs.map} +1 -1
  172. package/dist/{chunk-PIPLBBDH.js → chunk-RCSTDJUH.js} +22 -41
  173. package/dist/chunk-RCSTDJUH.js.map +1 -0
  174. package/dist/{chunk-Z6S4MWSR.js → chunk-RNAGCAIB.js} +21 -17
  175. package/dist/chunk-RNAGCAIB.js.map +1 -0
  176. package/dist/{chunk-AEARU24Q.mjs → chunk-RVRN5U7W.mjs} +2 -2
  177. package/dist/{chunk-AEARU24Q.mjs.map → chunk-RVRN5U7W.mjs.map} +1 -1
  178. package/dist/{chunk-DRLHQQBH.mjs → chunk-TDJKGN5Q.mjs} +4 -4
  179. package/dist/{chunk-DRLHQQBH.mjs.map → chunk-TDJKGN5Q.mjs.map} +1 -1
  180. package/dist/{chunk-MNYM2XU4.js → chunk-TSZIACRC.js} +4 -4
  181. package/dist/{chunk-MNYM2XU4.js.map → chunk-TSZIACRC.js.map} +1 -1
  182. package/dist/{chunk-UZL2QU2V.mjs → chunk-UQ5YULFU.mjs} +4 -4
  183. package/dist/{chunk-UZL2QU2V.mjs.map → chunk-UQ5YULFU.mjs.map} +1 -1
  184. package/dist/{chunk-5TGAUWNO.mjs → chunk-V5THCFPG.mjs} +3 -3
  185. package/dist/{chunk-5TGAUWNO.mjs.map → chunk-V5THCFPG.mjs.map} +1 -1
  186. package/dist/{chunk-YNC5D3FT.js → chunk-VFGEY6FJ.js} +12 -12
  187. package/dist/{chunk-YNC5D3FT.js.map → chunk-VFGEY6FJ.js.map} +1 -1
  188. package/dist/{chunk-OFSA7LUH.mjs → chunk-XLPU3TEE.mjs} +4 -4
  189. package/dist/{chunk-OFSA7LUH.mjs.map → chunk-XLPU3TEE.mjs.map} +1 -1
  190. package/dist/{chunk-YYAFHIY7.js → chunk-YKUEFRZI.js} +14 -14
  191. package/dist/{chunk-YYAFHIY7.js.map → chunk-YKUEFRZI.js.map} +1 -1
  192. package/dist/{chunk-QFNSM77X.js → chunk-YYDZ2TYR.js} +3 -3
  193. package/dist/{chunk-QFNSM77X.js.map → chunk-YYDZ2TYR.js.map} +1 -1
  194. package/dist/cli/agent/checks.d.ts.map +1 -1
  195. package/dist/cli/api/{uptrade.d.ts → sonor.d.ts} +3 -2
  196. package/dist/cli/api/sonor.d.ts.map +1 -0
  197. package/dist/cli/commands/api-routes.d.ts.map +1 -1
  198. package/dist/cli/commands/config-regression.test.d.ts +2 -0
  199. package/dist/cli/commands/config-regression.test.d.ts.map +1 -0
  200. package/dist/cli/commands/faqs.d.ts.map +1 -1
  201. package/dist/cli/commands/geo.d.ts +4 -0
  202. package/dist/cli/commands/geo.d.ts.map +1 -1
  203. package/dist/cli/commands/geo.test.d.ts +2 -0
  204. package/dist/cli/commands/geo.test.d.ts.map +1 -0
  205. package/dist/cli/commands/images.d.ts.map +1 -1
  206. package/dist/cli/commands/locations.d.ts.map +1 -1
  207. package/dist/cli/commands/migrate.d.ts.map +1 -1
  208. package/dist/cli/commands/og.d.ts +10 -1
  209. package/dist/cli/commands/og.d.ts.map +1 -1
  210. package/dist/cli/commands/scaffold.d.ts +1 -2
  211. package/dist/cli/commands/scaffold.d.ts.map +1 -1
  212. package/dist/cli/commands/setup.d.ts.map +1 -1
  213. package/dist/cli/commands/sync.d.ts.map +1 -1
  214. package/dist/cli/config.d.ts +31 -0
  215. package/dist/cli/config.d.ts.map +1 -0
  216. package/dist/cli/config.test.d.ts +2 -0
  217. package/dist/cli/config.test.d.ts.map +1 -0
  218. package/dist/cli/generators/index.d.ts +5 -0
  219. package/dist/cli/generators/index.d.ts.map +1 -1
  220. package/dist/cli/generators/index.test.d.ts +2 -0
  221. package/dist/cli/generators/index.test.d.ts.map +1 -0
  222. package/dist/cli/index.js +717 -634
  223. package/dist/cli/index.js.map +1 -1
  224. package/dist/cli/index.mjs +708 -625
  225. package/dist/cli/index.mjs.map +1 -1
  226. package/dist/cli/migrator/index.d.ts +1 -0
  227. package/dist/cli/migrator/index.d.ts.map +1 -1
  228. package/dist/cli/state.d.ts +7 -0
  229. package/dist/cli/state.d.ts.map +1 -0
  230. package/dist/cli/state.test.d.ts +2 -0
  231. package/dist/cli/state.test.d.ts.map +1 -0
  232. package/dist/client/index.js +4 -4
  233. package/dist/client/index.mjs +3 -3
  234. package/dist/commerce/index.js +57 -57
  235. package/dist/commerce/index.mjs +6 -6
  236. package/dist/discover-FGTKWOL3.mjs +4 -0
  237. package/dist/{discover-BEJRYNFF.mjs.map → discover-FGTKWOL3.mjs.map} +1 -1
  238. package/dist/discover-NJZPWTDL.js +21 -0
  239. package/dist/{discover-WVDYDUJX.js.map → discover-NJZPWTDL.js.map} +1 -1
  240. package/dist/engage/EngageWidget.d.ts +3 -2
  241. package/dist/engage/EngageWidget.d.ts.map +1 -1
  242. package/dist/engage/index.js +11 -10
  243. package/dist/engage/index.js.map +1 -1
  244. package/dist/engage/index.mjs +8 -7
  245. package/dist/engage/index.mjs.map +1 -1
  246. package/dist/fleet/FleetHeartbeat.d.ts +3 -2
  247. package/dist/fleet/FleetHeartbeat.d.ts.map +1 -1
  248. package/dist/fleet/heartbeat.d.ts +3 -2
  249. package/dist/fleet/heartbeat.d.ts.map +1 -1
  250. package/dist/fleet/heartbeat.test.d.ts +2 -0
  251. package/dist/fleet/heartbeat.test.d.ts.map +1 -0
  252. package/dist/fleet/index.js +9 -8
  253. package/dist/fleet/index.mjs +5 -4
  254. package/dist/forms/index.js +16 -16
  255. package/dist/forms/index.mjs +9 -9
  256. package/dist/forms/server.js +10 -10
  257. package/dist/forms/server.mjs +8 -8
  258. package/dist/forms/static.js +7 -7
  259. package/dist/forms/static.mjs +6 -6
  260. package/dist/images/index.js +11 -11
  261. package/dist/images/index.mjs +4 -4
  262. package/dist/index.js +69 -69
  263. package/dist/index.mjs +11 -11
  264. package/dist/layout/SiteKitClientProviders.d.ts.map +1 -1
  265. package/dist/layout/client.d.ts.map +1 -1
  266. package/dist/layout/client.js +9 -8
  267. package/dist/layout/client.mjs +8 -7
  268. package/dist/layout/index.js +11 -10
  269. package/dist/layout/index.js.map +1 -1
  270. package/dist/layout/index.mjs +9 -8
  271. package/dist/layout/index.mjs.map +1 -1
  272. package/dist/layout/types.d.ts +2 -0
  273. package/dist/layout/types.d.ts.map +1 -1
  274. package/dist/llms/aiRobots.d.ts +4 -1
  275. package/dist/llms/aiRobots.d.ts.map +1 -1
  276. package/dist/llms/handlers.d.ts +20 -2
  277. package/dist/llms/handlers.d.ts.map +1 -1
  278. package/dist/llms/index.js +25 -18
  279. package/dist/llms/index.js.map +1 -1
  280. package/dist/llms/index.mjs +15 -8
  281. package/dist/llms/index.mjs.map +1 -1
  282. package/dist/llms/wiring.d.ts +81 -0
  283. package/dist/llms/wiring.d.ts.map +1 -0
  284. package/dist/llms/wiring.test.d.ts +2 -0
  285. package/dist/llms/wiring.test.d.ts.map +1 -0
  286. package/dist/maps/index.js +5 -5
  287. package/dist/maps/index.mjs +3 -3
  288. package/dist/og/wiring.d.ts +5 -1
  289. package/dist/og/wiring.d.ts.map +1 -1
  290. package/dist/proxy/index.d.ts +16 -11
  291. package/dist/proxy/index.d.ts.map +1 -1
  292. package/dist/proxy/index.js +3 -3
  293. package/dist/proxy/index.js.map +1 -1
  294. package/dist/proxy/index.mjs +1 -1
  295. package/dist/proxy/index.mjs.map +1 -1
  296. package/dist/redirects/index.d.ts +1 -1
  297. package/dist/redirects/index.js +8 -8
  298. package/dist/redirects/index.mjs +1 -1
  299. package/dist/redirects/not-found.d.ts +14 -29
  300. package/dist/redirects/not-found.d.ts.map +1 -1
  301. package/dist/redirects/not-found.js +12 -5
  302. package/dist/redirects/not-found.js.map +1 -1
  303. package/dist/redirects/not-found.mjs +8 -1
  304. package/dist/redirects/not-found.mjs.map +1 -1
  305. package/dist/robots/index.d.ts +5 -1
  306. package/dist/robots/index.d.ts.map +1 -1
  307. package/dist/robots/index.js +7 -1
  308. package/dist/robots/index.js.map +1 -1
  309. package/dist/robots/index.mjs +4 -1
  310. package/dist/robots/index.mjs.map +1 -1
  311. package/dist/robots/index.test.d.ts +2 -0
  312. package/dist/robots/index.test.d.ts.map +1 -0
  313. package/dist/robots/next-internals.d.ts +22 -0
  314. package/dist/robots/next-internals.d.ts.map +1 -0
  315. package/dist/search/index.js +4 -4
  316. package/dist/search/index.mjs +3 -3
  317. package/dist/seo/client.js +6 -6
  318. package/dist/seo/client.mjs +5 -5
  319. package/dist/seo/index.js +15 -15
  320. package/dist/seo/index.mjs +7 -7
  321. package/dist/seo/register-sitemap-cli.js +4 -4
  322. package/dist/seo/register-sitemap-cli.mjs +1 -1
  323. package/dist/seo/server.js +5 -5
  324. package/dist/seo/server.mjs +1 -1
  325. package/dist/server/index.js +3 -3
  326. package/dist/server/index.mjs +2 -2
  327. package/dist/shared/next-files.d.ts +35 -0
  328. package/dist/shared/next-files.d.ts.map +1 -0
  329. package/dist/shared/next-files.test.d.ts +2 -0
  330. package/dist/shared/next-files.test.d.ts.map +1 -0
  331. package/dist/shared/reporting-gate.d.ts +43 -0
  332. package/dist/shared/reporting-gate.d.ts.map +1 -0
  333. package/dist/shared/version.d.ts +1 -1
  334. package/dist/signal/index.js +11 -11
  335. package/dist/signal/index.mjs +2 -2
  336. package/dist/sitemap/discover.d.ts.map +1 -1
  337. package/dist/sitemap/index.d.ts +6 -1
  338. package/dist/sitemap/index.d.ts.map +1 -1
  339. package/dist/sitemap/index.js +5 -12
  340. package/dist/sitemap/index.js.map +1 -1
  341. package/dist/sitemap/index.mjs +4 -11
  342. package/dist/sitemap/index.mjs.map +1 -1
  343. package/dist/sync/AddToCalendar.d.ts +19 -0
  344. package/dist/sync/AddToCalendar.d.ts.map +1 -0
  345. package/dist/sync/BookingWidget.d.ts.map +1 -1
  346. package/dist/sync/add-to-calendar.test.d.ts +2 -0
  347. package/dist/sync/add-to-calendar.test.d.ts.map +1 -0
  348. package/dist/sync/api-errors.test.d.ts +2 -0
  349. package/dist/sync/api-errors.test.d.ts.map +1 -0
  350. package/dist/sync/api.d.ts.map +1 -1
  351. package/dist/sync/index.js +17 -17
  352. package/dist/sync/index.mjs +4 -4
  353. package/dist/sync/types.d.ts +14 -0
  354. package/dist/sync/types.d.ts.map +1 -1
  355. package/package.json +22 -24
  356. package/dist/AnalyticsProvider-KFXAH4GR.mjs +0 -11
  357. package/dist/AnalyticsProvider-WDDW3IJW.js +0 -32
  358. package/dist/ChatWidget-2ZYPYIMQ.js +0 -22
  359. package/dist/ChatWidget-FYCCLMQE.mjs +0 -13
  360. package/dist/EngageWidget-6HUZYOY7.mjs +0 -11
  361. package/dist/EngageWidget-MYQTBBW6.js +0 -20
  362. package/dist/ManagedForm-JWEXJEXK.js +0 -23
  363. package/dist/ManagedForm-OA3MNGXT.mjs +0 -14
  364. package/dist/SitemapSync-2PTDBH5E.mjs +0 -9
  365. package/dist/SitemapSync-3SFAI546.js +0 -18
  366. package/dist/chunk-746RKQHA.js.map +0 -1
  367. package/dist/chunk-7PPNXORV.mjs.map +0 -1
  368. package/dist/chunk-DYULWKDC.mjs.map +0 -1
  369. package/dist/chunk-EEQYKMGH.mjs.map +0 -1
  370. package/dist/chunk-HBI67P7Y.mjs.map +0 -1
  371. package/dist/chunk-KAUUGRYB.js.map +0 -1
  372. package/dist/chunk-LOS5D6B3.js +0 -72
  373. package/dist/chunk-LOS5D6B3.js.map +0 -1
  374. package/dist/chunk-NVSWTDWU.mjs +0 -25
  375. package/dist/chunk-NVSWTDWU.mjs.map +0 -1
  376. package/dist/chunk-OL2QBWAU.js +0 -29
  377. package/dist/chunk-OL2QBWAU.js.map +0 -1
  378. package/dist/chunk-PIPLBBDH.js.map +0 -1
  379. package/dist/chunk-RZUZMUTN.mjs.map +0 -1
  380. package/dist/chunk-S6FEC6UT.mjs.map +0 -1
  381. package/dist/chunk-SQVYLIIN.js.map +0 -1
  382. package/dist/chunk-SUZ3ZLB2.js +0 -8
  383. package/dist/chunk-UNPEMSLK.js.map +0 -1
  384. package/dist/chunk-VAS3LH5W.js.map +0 -1
  385. package/dist/chunk-WDBCXRTT.mjs +0 -6
  386. package/dist/chunk-XIJ4F6IE.mjs +0 -63
  387. package/dist/chunk-XIJ4F6IE.mjs.map +0 -1
  388. package/dist/chunk-XQYC4KMH.mjs.map +0 -1
  389. package/dist/chunk-Z6S4MWSR.js.map +0 -1
  390. package/dist/cli/api/uptrade.d.ts.map +0 -1
  391. package/dist/discover-BEJRYNFF.mjs +0 -4
  392. package/dist/discover-WVDYDUJX.js +0 -21
@@ -3,12 +3,12 @@ import { traverse, isJSXIdentifier, isJSXAttribute, isFunctionDeclaration, isVar
3
3
  import { parse } from '../chunk-5YA6SI4Z.mjs';
4
4
  import { buildOgHtml, TITLE_MAX_PX, OG_REPORT_ATTR } from '../chunk-UJ6CHZAI.mjs';
5
5
  import { require_main } from '../chunk-NNZDWY3L.mjs';
6
- import { findAppDirForDiscovery, discoverNextJsRoutes } from '../chunk-XIJ4F6IE.mjs';
7
- import { SITE_KIT_VERSION } from '../chunk-WDBCXRTT.mjs';
6
+ import { findAppDirForDiscovery, NEXT_PROXY_FILES, NEXT_MIDDLEWARE_FILES, findConventionFile, NEXT_APP_DIRS, findSitemapRoute, findProxyFiles, findRootLayout, discoverNextJsRoutes, hasPageFile } from '../chunk-L4V6TKMJ.mjs';
7
+ import { SITE_KIT_VERSION } from '../chunk-QRBPT6Z6.mjs';
8
8
  import { __commonJS, __require, __toESM, __export, __privateAdd, __publicField, __privateGet, __privateMethod, __privateSet, __privateWrapper } from '../chunk-BEXTDHO4.mjs';
9
9
  import { EventEmitter } from 'events';
10
10
  import childProcess, { execFile as execFile$1, execSync, spawnSync, spawn } from 'child_process';
11
- import path10, { win32, posix } from 'path';
11
+ import path12, { win32, posix } from 'path';
12
12
  import * as fs from 'fs';
13
13
  import fs__default, { realpathSync, existsSync, readFileSync, readdirSync, statSync, readlinkSync, readdir as readdir$1, lstatSync, rmSync, mkdtempSync, writeFileSync } from 'fs';
14
14
  import process2 from 'process';
@@ -6202,10 +6202,10 @@ var require_lib2 = __commonJS({
6202
6202
  exports.analyse = analyse;
6203
6203
  var detectFile = (filepath, opts = {}) => new Promise((resolve, reject) => {
6204
6204
  let fd;
6205
- const fs27 = (0, node_1.default)();
6205
+ const fs30 = (0, node_1.default)();
6206
6206
  const handler = (err, buffer) => {
6207
6207
  if (fd) {
6208
- fs27.closeSync(fd);
6208
+ fs30.closeSync(fd);
6209
6209
  }
6210
6210
  if (err) {
6211
6211
  reject(err);
@@ -6217,9 +6217,9 @@ var require_lib2 = __commonJS({
6217
6217
  };
6218
6218
  const sampleSize = (opts === null || opts === void 0 ? void 0 : opts.sampleSize) || 0;
6219
6219
  if (sampleSize > 0) {
6220
- fd = fs27.openSync(filepath, "r");
6220
+ fd = fs30.openSync(filepath, "r");
6221
6221
  let sample = Buffer.allocUnsafe(sampleSize);
6222
- fs27.read(fd, sample, 0, sampleSize, opts.offset, (err, bytesRead) => {
6222
+ fs30.read(fd, sample, 0, sampleSize, opts.offset, (err, bytesRead) => {
6223
6223
  if (err) {
6224
6224
  handler(err, null);
6225
6225
  } else {
@@ -6231,22 +6231,22 @@ var require_lib2 = __commonJS({
6231
6231
  });
6232
6232
  return;
6233
6233
  }
6234
- fs27.readFile(filepath, handler);
6234
+ fs30.readFile(filepath, handler);
6235
6235
  });
6236
6236
  exports.detectFile = detectFile;
6237
6237
  var detectFileSync = (filepath, opts = {}) => {
6238
- const fs27 = (0, node_1.default)();
6238
+ const fs30 = (0, node_1.default)();
6239
6239
  if (opts && opts.sampleSize) {
6240
- const fd = fs27.openSync(filepath, "r");
6240
+ const fd = fs30.openSync(filepath, "r");
6241
6241
  let sample = Buffer.allocUnsafe(opts.sampleSize);
6242
- const bytesRead = fs27.readSync(fd, sample, 0, opts.sampleSize, opts.offset);
6242
+ const bytesRead = fs30.readSync(fd, sample, 0, opts.sampleSize, opts.offset);
6243
6243
  if (bytesRead < opts.sampleSize) {
6244
6244
  sample = sample.subarray(0, bytesRead);
6245
6245
  }
6246
- fs27.closeSync(fd);
6246
+ fs30.closeSync(fd);
6247
6247
  return (0, exports.detect)(sample);
6248
6248
  }
6249
- return (0, exports.detect)(fs27.readFileSync(filepath));
6249
+ return (0, exports.detect)(fs30.readFileSync(filepath));
6250
6250
  };
6251
6251
  exports.detectFileSync = detectFileSync;
6252
6252
  exports.default = {
@@ -10135,7 +10135,7 @@ var require_run_async = __commonJS({
10135
10135
  });
10136
10136
 
10137
10137
  // src/cli/index.ts
10138
- var import_dotenv = __toESM(require_main());
10138
+ var import_dotenv2 = __toESM(require_main());
10139
10139
 
10140
10140
  // node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
10141
10141
  var CommanderError = class extends Error {
@@ -12264,9 +12264,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
12264
12264
  args = args.slice();
12265
12265
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
12266
12266
  function findFile(baseDir, baseName) {
12267
- const localBin = path10.resolve(baseDir, baseName);
12267
+ const localBin = path12.resolve(baseDir, baseName);
12268
12268
  if (fs__default.existsSync(localBin)) return localBin;
12269
- if (sourceExt.includes(path10.extname(baseName))) return void 0;
12269
+ if (sourceExt.includes(path12.extname(baseName))) return void 0;
12270
12270
  const foundExt = sourceExt.find(
12271
12271
  (ext2) => fs__default.existsSync(`${localBin}${ext2}`)
12272
12272
  );
@@ -12284,17 +12284,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
12284
12284
  } catch {
12285
12285
  resolvedScriptPath = this._scriptPath;
12286
12286
  }
12287
- executableDir = path10.resolve(
12288
- path10.dirname(resolvedScriptPath),
12287
+ executableDir = path12.resolve(
12288
+ path12.dirname(resolvedScriptPath),
12289
12289
  executableDir
12290
12290
  );
12291
12291
  }
12292
12292
  if (executableDir) {
12293
12293
  let localFile = findFile(executableDir, executableFile);
12294
12294
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
12295
- const legacyName = path10.basename(
12295
+ const legacyName = path12.basename(
12296
12296
  this._scriptPath,
12297
- path10.extname(this._scriptPath)
12297
+ path12.extname(this._scriptPath)
12298
12298
  );
12299
12299
  if (legacyName !== this._name) {
12300
12300
  localFile = findFile(
@@ -12305,7 +12305,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
12305
12305
  }
12306
12306
  executableFile = localFile || executableFile;
12307
12307
  }
12308
- const launchWithNode = sourceExt.includes(path10.extname(executableFile));
12308
+ const launchWithNode = sourceExt.includes(path12.extname(executableFile));
12309
12309
  let proc;
12310
12310
  if (process2.platform !== "win32") {
12311
12311
  if (launchWithNode) {
@@ -13222,7 +13222,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
13222
13222
  * @return {Command}
13223
13223
  */
13224
13224
  nameFromFilename(filename) {
13225
- this._name = path10.basename(filename, path10.extname(filename));
13225
+ this._name = path12.basename(filename, path12.extname(filename));
13226
13226
  return this;
13227
13227
  }
13228
13228
  /**
@@ -13236,9 +13236,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
13236
13236
  * @param {string} [path]
13237
13237
  * @return {(string|null|Command)}
13238
13238
  */
13239
- executableDir(path27) {
13240
- if (path27 === void 0) return this._executableDir;
13241
- this._executableDir = path27;
13239
+ executableDir(path30) {
13240
+ if (path30 === void 0) return this._executableDir;
13241
+ this._executableDir = path30;
13242
13242
  return this;
13243
13243
  }
13244
13244
  /**
@@ -18747,7 +18747,7 @@ function createPrompt(view) {
18747
18747
  if (nextView === void 0) {
18748
18748
  let callerFilename = callSites[1]?.getFileName();
18749
18749
  if (callerFilename && !callerFilename.startsWith("file://")) {
18750
- callerFilename = path10.resolve(callerFilename);
18750
+ callerFilename = path12.resolve(callerFilename);
18751
18751
  }
18752
18752
  throw new Error(`Prompt functions must return a string.
18753
18753
  at ${callerFilename}`);
@@ -19136,13 +19136,13 @@ var ExternalEditor = class {
19136
19136
  }
19137
19137
  createTempFile() {
19138
19138
  try {
19139
- const baseDir = path10.resolve(this.fileOptions.dir ?? os.tmpdir());
19140
- this.tempDir = mkdtempSync(path10.join(baseDir, "inquirer-editor-"));
19139
+ const baseDir = path12.resolve(this.fileOptions.dir ?? os.tmpdir());
19140
+ this.tempDir = mkdtempSync(path12.join(baseDir, "inquirer-editor-"));
19141
19141
  const id = randomUUID();
19142
19142
  const prefix = sanitizeAffix(this.fileOptions.prefix);
19143
19143
  const postfix = sanitizeAffix(this.fileOptions.postfix);
19144
19144
  const filename = `${prefix}${id}${postfix}`;
19145
- this.tempFile = path10.join(this.tempDir, filename);
19145
+ this.tempFile = path12.join(this.tempDir, filename);
19146
19146
  const opt = { encoding: "utf8", flag: "wx" };
19147
19147
  if (Object.prototype.hasOwnProperty.call(this.fileOptions, "mode")) {
19148
19148
  opt.mode = this.fileOptions.mode;
@@ -20345,9 +20345,9 @@ function observableToAsyncIterable(source) {
20345
20345
 
20346
20346
  // node_modules/.pnpm/inquirer@14.0.2_@types+node@26.2.0/node_modules/inquirer/dist/ui/prompt.js
20347
20347
  var _ = {
20348
- set: (obj, path27 = "", value) => {
20348
+ set: (obj, path30 = "", value) => {
20349
20349
  let pointer = obj;
20350
- path27.split(".").forEach((key, index, arr) => {
20350
+ path30.split(".").forEach((key, index, arr) => {
20351
20351
  if (key === "__proto__" || key === "constructor")
20352
20352
  return;
20353
20353
  if (index === arr.length - 1) {
@@ -20358,8 +20358,8 @@ var _ = {
20358
20358
  pointer = pointer[key];
20359
20359
  });
20360
20360
  },
20361
- get: (obj, path27 = "", defaultValue) => {
20362
- const travel = (regexp) => String.prototype.split.call(path27, regexp).filter(Boolean).reduce(
20361
+ get: (obj, path30 = "", defaultValue) => {
20362
+ const travel = (regexp) => String.prototype.split.call(path30, regexp).filter(Boolean).reduce(
20363
20363
  // @ts-expect-error implicit any on res[key]
20364
20364
  (res, key) => res == null ? res : res[key],
20365
20365
  obj
@@ -20649,7 +20649,7 @@ async function scanCodebase(rootDir) {
20649
20649
  for (const file of files) {
20650
20650
  try {
20651
20651
  const content = await fs3.readFile(file, "utf-8");
20652
- const relPath = path10.relative(rootDir, file);
20652
+ const relPath = path12.relative(rootDir, file);
20653
20653
  const ast = parse(content, {
20654
20654
  sourceType: "module",
20655
20655
  plugins: ["jsx", "typescript"]
@@ -20698,7 +20698,7 @@ async function scanCodebase(rootDir) {
20698
20698
  async function findSourceFiles(dir, files = []) {
20699
20699
  const entries = await fs3.readdir(dir, { withFileTypes: true });
20700
20700
  for (const entry of entries) {
20701
- const fullPath = path10.join(dir, entry.name);
20701
+ const fullPath = path12.join(dir, entry.name);
20702
20702
  if (entry.isDirectory()) {
20703
20703
  if (["node_modules", ".next", ".git", "dist", "build"].includes(entry.name)) {
20704
20704
  continue;
@@ -20716,18 +20716,18 @@ function scanForForms(ast, content, filePath) {
20716
20716
  const forms = [];
20717
20717
  content.split("\n");
20718
20718
  traverse(ast, {
20719
- JSXElement(path27) {
20720
- const opening = path27.node.openingElement;
20719
+ JSXElement(path30) {
20720
+ const opening = path30.node.openingElement;
20721
20721
  if (isJSXIdentifier(opening.name) && opening.name.name === "form") {
20722
- const fields = extractFieldsFromForm(path27);
20722
+ const fields = extractFieldsFromForm(path30);
20723
20723
  const hasOnSubmit = opening.attributes.some(
20724
20724
  (attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === "onSubmit"
20725
20725
  );
20726
20726
  if (hasOnSubmit && fields.length > 0) {
20727
- const startLine = path27.node.loc?.start.line || 0;
20728
- const endLine = path27.node.loc?.end.line || 0;
20727
+ const startLine = path30.node.loc?.start.line || 0;
20728
+ const endLine = path30.node.loc?.end.line || 0;
20729
20729
  let componentName = "UnknownForm";
20730
- let current = path27.parentPath;
20730
+ let current = path30.parentPath;
20731
20731
  while (current) {
20732
20732
  if (isFunctionDeclaration(current.node) && current.node.id) {
20733
20733
  componentName = current.node.id.name;
@@ -20760,7 +20760,7 @@ function scanForForms(ast, content, filePath) {
20760
20760
  }
20761
20761
  if (isJSXIdentifier(opening.name) && opening.name.name === "Form") {
20762
20762
  if (content.includes("Formik") || content.includes("formik")) {
20763
- const fields = extractFieldsFromFormik(path27);
20763
+ const fields = extractFieldsFromFormik(path30);
20764
20764
  if (fields.length > 0) {
20765
20765
  forms.push({
20766
20766
  filePath,
@@ -20771,8 +20771,8 @@ function scanForForms(ast, content, filePath) {
20771
20771
  submitsTo: null,
20772
20772
  complexity: "moderate",
20773
20773
  suggestedAction: "assisted",
20774
- startLine: path27.node.loc?.start.line || 0,
20775
- endLine: path27.node.loc?.end.line || 0
20774
+ startLine: path30.node.loc?.start.line || 0,
20775
+ endLine: path30.node.loc?.end.line || 0
20776
20776
  });
20777
20777
  }
20778
20778
  }
@@ -20790,8 +20790,8 @@ function extractFieldsFromForm(formPath) {
20790
20790
  const radioGroups = /* @__PURE__ */ new Map();
20791
20791
  const checkboxGroups = /* @__PURE__ */ new Map();
20792
20792
  formPath.traverse({
20793
- JSXElement(path27) {
20794
- const opening = path27.node.openingElement;
20793
+ JSXElement(path30) {
20794
+ const opening = path30.node.openingElement;
20795
20795
  const tagName = isJSXIdentifier(opening.name) ? opening.name.name : null;
20796
20796
  if (["input", "textarea", "select"].includes(tagName || "")) {
20797
20797
  const attrs = opening.attributes;
@@ -20838,7 +20838,7 @@ function extractFieldsFromForm(formPath) {
20838
20838
  }
20839
20839
  if (tagName === "select") {
20840
20840
  const selectOptions = [];
20841
- path27.traverse({
20841
+ path30.traverse({
20842
20842
  JSXElement(optionPath) {
20843
20843
  const optOpening = optionPath.node.openingElement;
20844
20844
  const optTagName = isJSXIdentifier(optOpening.name) ? optOpening.name.name : null;
@@ -20913,8 +20913,8 @@ function extractFieldsFromForm(formPath) {
20913
20913
  function extractFieldsFromFormik(formPath, content) {
20914
20914
  const fields = [];
20915
20915
  formPath.traverse({
20916
- JSXElement(path27) {
20917
- const opening = path27.node.openingElement;
20916
+ JSXElement(path30) {
20917
+ const opening = path30.node.openingElement;
20918
20918
  const tagName = isJSXIdentifier(opening.name) ? opening.name.name : null;
20919
20919
  if (tagName === "Field" || tagName === "FastField") {
20920
20920
  const attrs = opening.attributes;
@@ -21033,11 +21033,11 @@ function scanForMetadata(ast, content, filePath) {
21033
21033
  }
21034
21034
  let hasHeadComponent = false;
21035
21035
  traverse(ast, {
21036
- JSXElement(path27) {
21037
- const opening = path27.node.openingElement;
21036
+ JSXElement(path30) {
21037
+ const opening = path30.node.openingElement;
21038
21038
  if (isJSXIdentifier(opening.name) && opening.name.name === "Head") {
21039
21039
  hasHeadComponent = true;
21040
- path27.stop();
21040
+ path30.stop();
21041
21041
  }
21042
21042
  }
21043
21043
  });
@@ -21072,8 +21072,8 @@ function scanForWidgets(ast, content, filePath) {
21072
21072
  for (const { pattern, type } of widgetPatterns) {
21073
21073
  if (pattern.test(content)) {
21074
21074
  traverse(ast, {
21075
- JSXElement(path27) {
21076
- const opening = path27.node.openingElement;
21075
+ JSXElement(path30) {
21076
+ const opening = path30.node.openingElement;
21077
21077
  if (isJSXIdentifier(opening.name) && (opening.name.name === "script" || opening.name.name === "Script")) {
21078
21078
  const srcAttr = opening.attributes.find(
21079
21079
  (attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === "src"
@@ -21088,8 +21088,8 @@ function scanForWidgets(ast, content, filePath) {
21088
21088
  filePath,
21089
21089
  widgetType: type,
21090
21090
  scriptTag: src,
21091
- startLine: path27.node.loc?.start.line || 0,
21092
- endLine: path27.node.loc?.end.line || 0
21091
+ startLine: path30.node.loc?.start.line || 0,
21092
+ endLine: path30.node.loc?.end.line || 0
21093
21093
  });
21094
21094
  }
21095
21095
  }
@@ -21163,7 +21163,7 @@ async function scanForSitemapFiles(rootDir) {
21163
21163
  "next-sitemap.config.ts"
21164
21164
  ];
21165
21165
  for (const configPath of configPaths) {
21166
- const fullPath = path10.join(rootDir, configPath);
21166
+ const fullPath = path12.join(rootDir, configPath);
21167
21167
  try {
21168
21168
  await fs3.access(fullPath);
21169
21169
  const content = await fs3.readFile(fullPath, "utf-8");
@@ -21181,7 +21181,7 @@ async function scanForSitemapFiles(rootDir) {
21181
21181
  } catch {
21182
21182
  }
21183
21183
  }
21184
- const staticSitemapPath = path10.join(rootDir, "public", "sitemap.xml");
21184
+ const staticSitemapPath = path12.join(rootDir, "public", "sitemap.xml");
21185
21185
  try {
21186
21186
  await fs3.access(staticSitemapPath);
21187
21187
  const content = await fs3.readFile(staticSitemapPath, "utf-8");
@@ -21204,7 +21204,7 @@ async function scanForSitemapFiles(rootDir) {
21204
21204
  "out/sitemap.xml"
21205
21205
  ];
21206
21206
  for (const genPath of generatedPaths) {
21207
- const fullPath = path10.join(rootDir, genPath);
21207
+ const fullPath = path12.join(rootDir, genPath);
21208
21208
  try {
21209
21209
  await fs3.access(fullPath);
21210
21210
  } catch {
@@ -21228,8 +21228,8 @@ function scanForSchemas(ast, content, filePath) {
21228
21228
  return schemas;
21229
21229
  }
21230
21230
  traverse(ast, {
21231
- JSXElement(path27) {
21232
- const opening = path27.node.openingElement;
21231
+ JSXElement(path30) {
21232
+ const opening = path30.node.openingElement;
21233
21233
  if (isJSXIdentifier(opening.name) && (opening.name.name === "script" || opening.name.name === "Script")) {
21234
21234
  const typeAttr = opening.attributes.find(
21235
21235
  (attr) => isJSXAttribute(attr) && isJSXIdentifier(attr.name) && attr.name.name === "type"
@@ -21256,8 +21256,8 @@ function scanForSchemas(ast, content, filePath) {
21256
21256
  filePath,
21257
21257
  type: detectedType,
21258
21258
  schemaType,
21259
- startLine: path27.node.loc?.start.line || 0,
21260
- endLine: path27.node.loc?.end.line || 0
21259
+ startLine: path30.node.loc?.start.line || 0,
21260
+ endLine: path30.node.loc?.end.line || 0
21261
21261
  });
21262
21262
  }
21263
21263
  }
@@ -21290,8 +21290,8 @@ function scanForFAQs(ast, content, filePath) {
21290
21290
  /questions?\s*(?:and|&)?\s*answers?/i
21291
21291
  ];
21292
21292
  traverse(ast, {
21293
- JSXElement(path27) {
21294
- const opening = path27.node.openingElement;
21293
+ JSXElement(path30) {
21294
+ const opening = path30.node.openingElement;
21295
21295
  let tagName = "";
21296
21296
  if (isJSXIdentifier(opening.name)) {
21297
21297
  tagName = opening.name.name;
@@ -21304,8 +21304,8 @@ function scanForFAQs(ast, content, filePath) {
21304
21304
  faqs.push({
21305
21305
  filePath,
21306
21306
  type: "details-summary",
21307
- startLine: path27.node.loc?.start.line || 0,
21308
- endLine: path27.node.loc?.end.line || 0,
21307
+ startLine: path30.node.loc?.start.line || 0,
21308
+ endLine: path30.node.loc?.end.line || 0,
21309
21309
  hasSchema: content.includes("FAQPage") || content.includes("application/ld+json")
21310
21310
  });
21311
21311
  return;
@@ -21313,7 +21313,7 @@ function scanForFAQs(ast, content, filePath) {
21313
21313
  for (const pattern of faqPatterns) {
21314
21314
  if (pattern.test(tagName)) {
21315
21315
  let itemCount = 0;
21316
- path27.traverse({
21316
+ path30.traverse({
21317
21317
  JSXElement(itemPath) {
21318
21318
  const itemOpening = itemPath.node.openingElement;
21319
21319
  if (isJSXIdentifier(itemOpening.name)) {
@@ -21329,8 +21329,8 @@ function scanForFAQs(ast, content, filePath) {
21329
21329
  type: "accordion",
21330
21330
  componentName: tagName,
21331
21331
  itemCount: itemCount || void 0,
21332
- startLine: path27.node.loc?.start.line || 0,
21333
- endLine: path27.node.loc?.end.line || 0,
21332
+ startLine: path30.node.loc?.start.line || 0,
21333
+ endLine: path30.node.loc?.end.line || 0,
21334
21334
  hasSchema: content.includes("FAQPage") || content.includes("application/ld+json")
21335
21335
  });
21336
21336
  return;
@@ -21453,8 +21453,8 @@ function scanForImages(ast, content, filePath) {
21453
21453
  return images;
21454
21454
  }
21455
21455
  traverse(ast, {
21456
- JSXElement(path27) {
21457
- const opening = path27.node.openingElement;
21456
+ JSXElement(path30) {
21457
+ const opening = path30.node.openingElement;
21458
21458
  if (!isJSXIdentifier(opening.name)) return;
21459
21459
  const tagName = opening.name.name;
21460
21460
  if (tagName === "img" || tagName === "Image") {
@@ -21482,8 +21482,8 @@ function scanForImages(ast, content, filePath) {
21482
21482
  src: src || void 0,
21483
21483
  alt: alt || void 0,
21484
21484
  isLocal,
21485
- startLine: path27.node.loc?.start.line || 0,
21486
- endLine: path27.node.loc?.end.line || 0
21485
+ startLine: path30.node.loc?.start.line || 0,
21486
+ endLine: path30.node.loc?.end.line || 0
21487
21487
  });
21488
21488
  }
21489
21489
  }
@@ -21688,7 +21688,7 @@ async function migrateFiles(scanResults, options) {
21688
21688
  }
21689
21689
  async function migrateForm(form, options) {
21690
21690
  const changes = [];
21691
- const fullPath = path10.resolve(process.cwd(), form.filePath);
21691
+ const fullPath = path12.resolve(process.cwd(), form.filePath);
21692
21692
  const formSlug = generateSlug(form.componentName);
21693
21693
  let formId;
21694
21694
  if (!options.dryRun) {
@@ -21827,7 +21827,7 @@ export default ${componentName}
21827
21827
  `;
21828
21828
  }
21829
21829
  async function createFormInUptrade(form, slug, options) {
21830
- const response = await fetch("https://api.sonor.io/forms", {
21830
+ const response = await fetch(`${options.apiUrl || "https://api.sonor.io"}/forms`, {
21831
21831
  method: "POST",
21832
21832
  headers: {
21833
21833
  "Content-Type": "application/json",
@@ -21865,7 +21865,7 @@ async function migrateWidget(filePath, widget, options) {
21865
21865
  changes.push("[DRY RUN] Sonor Engage chat would come from SiteKitLayout (engage is on by default)");
21866
21866
  return { filePath, success: true, changes };
21867
21867
  }
21868
- const fullPath = path10.resolve(process.cwd(), filePath);
21868
+ const fullPath = path12.resolve(process.cwd(), filePath);
21869
21869
  let content = await fs3.readFile(fullPath, "utf-8");
21870
21870
  switch (widget.widgetType) {
21871
21871
  case "intercom":
@@ -21902,15 +21902,15 @@ function matchBalancedBraces(content, startIndex) {
21902
21902
  }
21903
21903
  async function migrateMetadata(filePath, metadata, options) {
21904
21904
  const changes = [];
21905
- const fullPath = path10.resolve(process.cwd(), filePath);
21905
+ const fullPath = path12.resolve(process.cwd(), filePath);
21906
21906
  let pagePath = filePath.replace(/^app\//, "/").replace(/^src\/app\//, "/").replace(/\/page\.(tsx?|jsx?)$/, "").replace(/\/layout\.(tsx?|jsx?)$/, "").replace(/\[([^\]]+)\]/g, ":$1");
21907
21907
  if (pagePath === "") pagePath = "/";
21908
21908
  let content = await fs3.readFile(fullPath, "utf-8");
21909
21909
  const isTypeScript = filePath.endsWith(".tsx") || filePath.endsWith(".ts");
21910
21910
  const ext2 = isTypeScript ? ".tsx" : ".jsx";
21911
21911
  if (isClientComponent(content)) {
21912
- const dir = path10.dirname(fullPath);
21913
- const layoutPath = path10.join(dir, `layout${ext2}`);
21912
+ const dir = path12.dirname(fullPath);
21913
+ const layoutPath = path12.join(dir, `layout${ext2}`);
21914
21914
  try {
21915
21915
  await fs3.access(layoutPath);
21916
21916
  const layoutContent = await fs3.readFile(layoutPath, "utf-8");
@@ -21933,7 +21933,7 @@ async function migrateMetadata(filePath, metadata, options) {
21933
21933
  } catch (error2) {
21934
21934
  changes.push(`Page metadata may already exist: ${pagePath}`);
21935
21935
  }
21936
- const dirName = path10.basename(dir).replace(/^\[\.\.\.([^\]]+)\]$/, "$1").replace(/^\[([^\]]+)\]$/, "$1");
21936
+ const dirName = path12.basename(dir).replace(/^\[\.\.\.([^\]]+)\]$/, "$1").replace(/^\[([^\]]+)\]$/, "$1");
21937
21937
  const layoutName = dirName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("") + "Layout";
21938
21938
  const layoutCode = `import { getManagedMetadata, ManagedSchema } from '@sonordev/site-kit/seo'
21939
21939
 
@@ -22042,7 +22042,7 @@ export async function generateMetadata() {
22042
22042
  return { filePath, success: true, changes };
22043
22043
  }
22044
22044
  async function createPageMetadata(pagePath, metadata, options) {
22045
- const response = await fetch("https://api.sonor.io/seo/pages", {
22045
+ const response = await fetch(`${options.apiUrl || "https://api.sonor.io"}/seo/pages`, {
22046
22046
  method: "POST",
22047
22047
  headers: {
22048
22048
  "Content-Type": "application/json",
@@ -22127,7 +22127,7 @@ async function createSchemaRecord(pagePath, schemaType, schemaJson, options) {
22127
22127
  }
22128
22128
  async function migrateSchema(filePath, schema, options) {
22129
22129
  const changes = [];
22130
- const fullPath = path10.resolve(process.cwd(), filePath);
22130
+ const fullPath = path12.resolve(process.cwd(), filePath);
22131
22131
  let pagePath = filePath.replace(/^app\//, "/").replace(/^src\/app\//, "/").replace(/\/page\.(tsx?|jsx?)$/, "").replace(/\[([^\]]+)\]/g, ":$1");
22132
22132
  if (pagePath === "") pagePath = "/";
22133
22133
  let content = await fs3.readFile(fullPath, "utf-8");
@@ -22238,7 +22238,7 @@ async function createFAQRecord(pagePath, items, options) {
22238
22238
  }
22239
22239
  async function migrateFAQ(filePath, faq, options) {
22240
22240
  const changes = [];
22241
- const fullPath = path10.resolve(process.cwd(), filePath);
22241
+ const fullPath = path12.resolve(process.cwd(), filePath);
22242
22242
  let pagePath = filePath.replace(/^app\//, "/").replace(/^src\/app\//, "/").replace(/\/page\.(tsx?|jsx?)$/, "").replace(/\[([^\]]+)\]/g, ":$1");
22243
22243
  if (pagePath === "") pagePath = "/";
22244
22244
  let content = await fs3.readFile(fullPath, "utf-8");
@@ -22306,7 +22306,7 @@ async function migrateFAQ(filePath, faq, options) {
22306
22306
  }
22307
22307
  async function migrateSitemap(filePath, sitemap, options) {
22308
22308
  const changes = [];
22309
- const fullPath = path10.resolve(process.cwd(), filePath);
22309
+ const fullPath = path12.resolve(process.cwd(), filePath);
22310
22310
  if (options.dryRun) {
22311
22311
  changes.push(`[DRY RUN] Would migrate ${sitemap.type} to Site-Kit sitemap`);
22312
22312
  if (sitemap.type === "next-sitemap-config") {
@@ -22348,8 +22348,8 @@ async function migrateAnalytics(filePath, analytics, options) {
22348
22348
  return { filePath, success: true, changes };
22349
22349
  }
22350
22350
  async function migrateFile(filePath, options) {
22351
- const fullPath = path10.resolve(filePath);
22352
- const relPath = path10.relative(process.cwd(), fullPath);
22351
+ const fullPath = path12.resolve(filePath);
22352
+ const relPath = path12.relative(process.cwd(), fullPath);
22353
22353
  const content = await fs3.readFile(fullPath, "utf-8");
22354
22354
  const hasFormTag = content.includes("<form") || content.includes("onSubmit");
22355
22355
  const hasWidget = /intercom|crisp|drift|hubspot|zendesk/i.test(content);
@@ -22366,26 +22366,26 @@ async function migrateFile(filePath, options) {
22366
22366
  return migrateWidget(relPath, {
22367
22367
  widgetType}, options);
22368
22368
  }
22369
- const { parse: parse2 } = await import('../lib-R7IQ4ZHE.mjs');
22370
- const ast = parse2(content, {
22369
+ const { parse: parse3 } = await import('../lib-R7IQ4ZHE.mjs');
22370
+ const ast = parse3(content, {
22371
22371
  sourceType: "module",
22372
22372
  plugins: ["jsx", "typescript"]
22373
22373
  });
22374
22374
  let componentName = "Form";
22375
22375
  const traverse2 = (await import('../lib-RSDMEKDQ.mjs')).default;
22376
22376
  traverse2(ast, {
22377
- ExportNamedDeclaration(path27) {
22378
- const decl = path27.node.declaration;
22377
+ ExportNamedDeclaration(path30) {
22378
+ const decl = path30.node.declaration;
22379
22379
  if (decl && decl.type === "FunctionDeclaration" && decl.id) {
22380
22380
  componentName = decl.id.name;
22381
- path27.stop();
22381
+ path30.stop();
22382
22382
  }
22383
22383
  },
22384
- ExportDefaultDeclaration(path27) {
22385
- const decl = path27.node.declaration;
22384
+ ExportDefaultDeclaration(path30) {
22385
+ const decl = path30.node.declaration;
22386
22386
  if (decl && decl.type === "FunctionDeclaration" && decl.id) {
22387
22387
  componentName = decl.id.name;
22388
- path27.stop();
22388
+ path30.stop();
22389
22389
  }
22390
22390
  }
22391
22391
  });
@@ -22442,7 +22442,7 @@ function detectFormType(form) {
22442
22442
  return "contact";
22443
22443
  }
22444
22444
  async function generateEnvFile(options) {
22445
- const envPath = path10.join(process.cwd(), ".env.local");
22445
+ const envPath = path12.join(process.cwd(), ".env.local");
22446
22446
  let existingContent = "";
22447
22447
  try {
22448
22448
  existingContent = await fs3.readFile(envPath, "utf-8");
@@ -22501,7 +22501,7 @@ function addImportSafely2(content, importStatement) {
22501
22501
  async function generateLayout() {
22502
22502
  const layoutPath = await findLayoutFile();
22503
22503
  if (!layoutPath) {
22504
- throw new Error("Could not find layout.tsx file");
22504
+ throw new Error("Could not find a root layout (app/layout.tsx, .jsx, .ts or .js)");
22505
22505
  }
22506
22506
  const content = await fs3.readFile(layoutPath, "utf-8");
22507
22507
  if (content.includes("SiteKitLayout") || content.includes("SiteKitProvider")) {
@@ -22535,22 +22535,7 @@ async function generateLayout() {
22535
22535
  await fs3.writeFile(layoutPath, newContent, "utf-8");
22536
22536
  }
22537
22537
  async function findLayoutFile() {
22538
- const possiblePaths = [
22539
- "src/app/layout.tsx",
22540
- "app/layout.tsx",
22541
- "src/app/layout.jsx",
22542
- "app/layout.jsx"
22543
- ];
22544
- for (const relativePath of possiblePaths) {
22545
- const fullPath = path10.join(process.cwd(), relativePath);
22546
- try {
22547
- await fs3.access(fullPath);
22548
- return fullPath;
22549
- } catch {
22550
- continue;
22551
- }
22552
- }
22553
- return null;
22538
+ return findRootLayout(process.cwd());
22554
22539
  }
22555
22540
  var isDockerCached;
22556
22541
  function hasDockerEnv() {
@@ -22712,15 +22697,15 @@ var wslDefaultBrowser = async () => {
22712
22697
  const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
22713
22698
  return stdout.trim();
22714
22699
  };
22715
- var convertWslPathToWindows = async (path27) => {
22716
- if (/^[a-z]+:\/\//i.test(path27)) {
22717
- return path27;
22700
+ var convertWslPathToWindows = async (path30) => {
22701
+ if (/^[a-z]+:\/\//i.test(path30)) {
22702
+ return path30;
22718
22703
  }
22719
22704
  try {
22720
- const { stdout } = await execFile2("wslpath", ["-aw", path27], { encoding: "utf8" });
22705
+ const { stdout } = await execFile2("wslpath", ["-aw", path30], { encoding: "utf8" });
22721
22706
  return stdout.trim();
22722
22707
  } catch {
22723
- return path27;
22708
+ return path30;
22724
22709
  }
22725
22710
  };
22726
22711
 
@@ -22840,8 +22825,8 @@ var is_in_ssh_default = isInSsh;
22840
22825
 
22841
22826
  // node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
22842
22827
  var fallbackAttemptSymbol = /* @__PURE__ */ Symbol("fallbackAttempt");
22843
- var __dirname2 = import.meta.url ? path10.dirname(fileURLToPath(import.meta.url)) : "";
22844
- var localXdgOpenPath = path10.join(__dirname2, "xdg-open");
22828
+ var __dirname2 = import.meta.url ? path12.dirname(fileURLToPath(import.meta.url)) : "";
22829
+ var localXdgOpenPath = path12.join(__dirname2, "xdg-open");
22845
22830
  var { platform, arch } = process2;
22846
22831
  var tryEachApp = async (apps2, opener) => {
22847
22832
  if (apps2.length === 0) {
@@ -23119,8 +23104,37 @@ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
23119
23104
  darwin: "Safari"
23120
23105
  }));
23121
23106
  var open_default = open;
23107
+ var SONOR_STATE_DIR = ".sonor";
23108
+ var IMAGE_MANIFEST = ".sonor-images.json";
23109
+ var LEGACY_IMAGE_MANIFEST = ".uptrade-images.json";
23110
+ var LEGACY_STATE_DIR = ".uptrade";
23111
+ function resolveStateReadPath(relativePath, root = process.cwd()) {
23112
+ return preferCurrent(path12.join(root, SONOR_STATE_DIR, relativePath), path12.join(root, LEGACY_STATE_DIR, relativePath));
23113
+ }
23114
+ function resolveImageManifestReadPath(root) {
23115
+ return preferCurrent(path12.join(root, IMAGE_MANIFEST), path12.join(root, LEGACY_IMAGE_MANIFEST));
23116
+ }
23117
+ function preferCurrent(current, legacy) {
23118
+ return existsSync(current) || !existsSync(legacy) ? current : legacy;
23119
+ }
23120
+ async function listLocalTemplates(root = process.cwd()) {
23121
+ const names = /* @__PURE__ */ new Set();
23122
+ for (const dir of [SONOR_STATE_DIR, LEGACY_STATE_DIR]) {
23123
+ try {
23124
+ const files = await fs3.readdir(path12.join(root, dir, "templates"));
23125
+ for (const file of files) if (file.endsWith(".json")) names.add(file);
23126
+ } catch (error2) {
23127
+ if (error2.code !== "ENOENT") throw error2;
23128
+ }
23129
+ }
23130
+ return [...names].sort();
23131
+ }
23132
+
23133
+ // src/cli/api/sonor.ts
23122
23134
  var PORTAL_URL = "https://app.sonor.io";
23123
- var API_URL = process.env.SONOR_API_URL || "https://api.sonor.io";
23135
+ function getSonorApiUrl() {
23136
+ return (process.env.SONOR_API_URL || "https://api.sonor.io").replace(/\/+$/, "");
23137
+ }
23124
23138
  async function authenticateWithSonor() {
23125
23139
  return new Promise((resolve, reject) => {
23126
23140
  const server = http.createServer(async (req, res) => {
@@ -23147,7 +23161,7 @@ async function authenticateWithSonor() {
23147
23161
  server.close();
23148
23162
  return;
23149
23163
  }
23150
- const tokenResponse = await fetch(`${API_URL}/auth/cli-token`, {
23164
+ const tokenResponse = await fetch(`${getSonorApiUrl()}/auth/cli-token`, {
23151
23165
  method: "POST",
23152
23166
  headers: { "Content-Type": "application/json" },
23153
23167
  body: JSON.stringify({ code, redirect_uri: `http://localhost:${port}/callback` })
@@ -23193,32 +23207,41 @@ async function authenticateWithSonor() {
23193
23207
  }, 5 * 60 * 1e3);
23194
23208
  });
23195
23209
  }
23196
- async function authenticateWithApiKey(apiKey) {
23197
- const response = await fetch(`${API_URL}/api/public/seo/verify-api-key`, {
23198
- headers: { "X-API-Key": apiKey }
23199
- });
23200
- if (response.ok) {
23201
- const data = await response.json();
23202
- if (data.valid) {
23203
- return {
23204
- accessToken: apiKey,
23205
- userId: "api-key-user",
23206
- email: data.project?.name ? `Project: ${data.project.name}` : `API Key verified`,
23207
- projectId: data.project?.id,
23208
- projectName: data.project?.name,
23209
- orgId: data.organization?.id,
23210
- orgName: data.organization?.name,
23211
- isApiKey: true
23212
- };
23213
- }
23210
+ async function authenticateWithApiKey(apiKey, apiUrl = getSonorApiUrl()) {
23211
+ let response;
23212
+ try {
23213
+ response = await fetch(`${apiUrl}/api/public/seo/verify-api-key`, {
23214
+ headers: { "X-API-Key": apiKey },
23215
+ signal: AbortSignal.timeout(15e3)
23216
+ });
23217
+ } catch {
23218
+ throw new NetworkError("PROJECT_LOOKUP_FAILED", "Could not reach the Sonor API to resolve the project. Check SONOR_API_URL and your connection.");
23214
23219
  }
23215
- if (response.status === 401) {
23216
- throw new Error("Invalid API key");
23220
+ if (!response.ok) {
23221
+ throw new NetworkError("PROJECT_LOOKUP_FAILED", `Sonor API verification failed (HTTP ${response.status}). Check SONOR_API_KEY and SONOR_API_URL.`);
23217
23222
  }
23218
- throw new Error(`API verification failed: ${response.status}`);
23223
+ let data;
23224
+ try {
23225
+ data = await response.json();
23226
+ } catch {
23227
+ throw new NetworkError("INVALID_PROJECT_RESPONSE", "Sonor API returned an invalid project response.");
23228
+ }
23229
+ if (data?.valid !== true || typeof data.project?.id !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(data.project.id)) {
23230
+ throw new NetworkError("INVALID_PROJECT_RESPONSE", "Sonor API did not return a valid full project UUID. Check SONOR_API_KEY.");
23231
+ }
23232
+ return {
23233
+ accessToken: apiKey,
23234
+ userId: "api-key-user",
23235
+ email: data.project.name ? `Project: ${data.project.name}` : "API Key verified",
23236
+ projectId: data.project.id,
23237
+ projectName: data.project.name,
23238
+ orgId: data.organization?.id,
23239
+ orgName: data.organization?.name,
23240
+ isApiKey: true
23241
+ };
23219
23242
  }
23220
23243
  async function fetchOrganizations(accessToken) {
23221
- const response = await fetch(`${API_URL}/organizations`, {
23244
+ const response = await fetch(`${getSonorApiUrl()}/organizations`, {
23222
23245
  headers: { "Authorization": `Bearer ${accessToken}` }
23223
23246
  });
23224
23247
  if (!response.ok) {
@@ -23227,7 +23250,7 @@ async function fetchOrganizations(accessToken) {
23227
23250
  return response.json();
23228
23251
  }
23229
23252
  async function fetchProjects(accessToken, orgId) {
23230
- const response = await fetch(`${API_URL}/organizations/${orgId}/projects`, {
23253
+ const response = await fetch(`${getSonorApiUrl()}/organizations/${orgId}/projects`, {
23231
23254
  headers: { "Authorization": `Bearer ${accessToken}` }
23232
23255
  });
23233
23256
  if (!response.ok) {
@@ -23236,7 +23259,7 @@ async function fetchProjects(accessToken, orgId) {
23236
23259
  return response.json();
23237
23260
  }
23238
23261
  async function createProject(accessToken, orgId, data) {
23239
- const response = await fetch(`${API_URL}/organizations/${orgId}/projects`, {
23262
+ const response = await fetch(`${getSonorApiUrl()}/organizations/${orgId}/projects`, {
23240
23263
  method: "POST",
23241
23264
  headers: {
23242
23265
  "Authorization": `Bearer ${accessToken}`,
@@ -23250,7 +23273,7 @@ async function createProject(accessToken, orgId, data) {
23250
23273
  return response.json();
23251
23274
  }
23252
23275
  async function generateApiKey(accessToken, projectId) {
23253
- const response = await fetch(`${API_URL}/projects/${projectId}/api-keys`, {
23276
+ const response = await fetch(`${getSonorApiUrl()}/projects/${projectId}/api-keys`, {
23254
23277
  method: "POST",
23255
23278
  headers: {
23256
23279
  "Authorization": `Bearer ${accessToken}`,
@@ -23454,7 +23477,7 @@ function progress(ctx, line) {
23454
23477
  // src/cli/commands/init.ts
23455
23478
  async function checkNextJsProject(cwd) {
23456
23479
  try {
23457
- const pkg = JSON.parse(await fs3.readFile(path10.join(cwd, "package.json"), "utf-8"));
23480
+ const pkg = JSON.parse(await fs3.readFile(path12.join(cwd, "package.json"), "utf-8"));
23458
23481
  return !!(pkg.dependencies?.next || pkg.devDependencies?.next);
23459
23482
  } catch {
23460
23483
  return false;
@@ -23534,7 +23557,7 @@ async function run(ctx, options) {
23534
23557
  ]);
23535
23558
  if (chosen === "new") {
23536
23559
  const answers = await dist_default14.prompt([
23537
- { type: "input", name: "name", message: "Project name:", default: path10.basename(ctx.cwd) },
23560
+ { type: "input", name: "name", message: "Project name:", default: path12.basename(ctx.cwd) },
23538
23561
  { type: "input", name: "domain", message: "Project domain (optional):" }
23539
23562
  ]);
23540
23563
  const project = await createProject(auth.accessToken, orgId, { name: answers.name, domain: answers.domain || "" });
@@ -23589,7 +23612,7 @@ async function run(ctx, options) {
23589
23612
  };
23590
23613
  }
23591
23614
  async function ensureSitemapPostbuild(ctx) {
23592
- const pkgPath = path10.join(ctx.cwd, "package.json");
23615
+ const pkgPath = path12.join(ctx.cwd, "package.json");
23593
23616
  try {
23594
23617
  const pkg = JSON.parse(await fs3.readFile(pkgPath, "utf-8"));
23595
23618
  if (!pkg.scripts) pkg.scripts = {};
@@ -23631,7 +23654,7 @@ async function scanCommand(options) {
23631
23654
  console.log("");
23632
23655
  console.log(source_default.bold(" Scanning codebase..."));
23633
23656
  console.log("");
23634
- const targetDir = path10.resolve(options.dir || ".");
23657
+ const targetDir = path12.resolve(options.dir || ".");
23635
23658
  const spinner = ora("Looking for forms, metadata, widgets, schemas, FAQs, analytics, and images...").start();
23636
23659
  let scanResults;
23637
23660
  try {
@@ -23809,6 +23832,48 @@ async function scanCommand(options) {
23809
23832
  process.exit(1);
23810
23833
  }
23811
23834
  }
23835
+
23836
+ // src/cli/config.ts
23837
+ var import_dotenv = __toESM(require_main());
23838
+ async function loadConfig({ resolveProject = false, cwd = process.cwd() } = {}) {
23839
+ const envFile = await readOptionalFile(path12.join(cwd, ".env.local"));
23840
+ const env3 = { ...(0, import_dotenv.parse)(envFile || ""), ...process.env };
23841
+ const configPath = resolveStateReadPath("config.json", cwd);
23842
+ const saved = await readOptionalFile(configPath);
23843
+ let stored = {};
23844
+ if (saved !== void 0) {
23845
+ try {
23846
+ stored = JSON.parse(saved);
23847
+ if (!stored || typeof stored !== "object" || Array.isArray(stored)) throw new Error();
23848
+ } catch {
23849
+ throw new ConfigError("INVALID_CONFIG", `Invalid JSON config: ${configPath}. Fix or remove it, then set SONOR_API_KEY in .env.local.`);
23850
+ }
23851
+ }
23852
+ const apiKey = String(env3.SONOR_API_KEY || stored.apiKey || stored.api_key || "").trim();
23853
+ if (!apiKey) {
23854
+ throw new ConfigError("MISSING_API_KEY", "Set SONOR_API_KEY in .env.local or run `sonor-setup init` first.");
23855
+ }
23856
+ if (!/^sonor_[0-9a-f]{8}_.+$/i.test(apiKey)) {
23857
+ throw new ConfigError("INVALID_API_KEY", "SONOR_API_KEY must be a sonor_ key from app.sonor.io.");
23858
+ }
23859
+ const config2 = {
23860
+ apiKey,
23861
+ apiUrl: (env3.SONOR_API_URL || getSonorApiUrl()).replace(/\/+$/, ""),
23862
+ siteUrl: env3.NEXT_PUBLIC_SITE_URL || env3.SITE_URL || stored.siteUrl || stored.site_url,
23863
+ businessInfo: stored.businessInfo || stored.business_info
23864
+ };
23865
+ if (!resolveProject) return config2;
23866
+ const auth = await authenticateWithApiKey(apiKey, config2.apiUrl);
23867
+ return { ...config2, projectId: auth.projectId };
23868
+ }
23869
+ async function readOptionalFile(file) {
23870
+ try {
23871
+ return await fs3.readFile(file, "utf-8");
23872
+ } catch (error2) {
23873
+ if (error2.code === "ENOENT") return void 0;
23874
+ throw new ConfigError("CONFIG_READ_FAILED", `Could not read ${file}. Check file permissions.`);
23875
+ }
23876
+ }
23812
23877
  var IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico", ".bmp", ".avif"];
23813
23878
  var MIME_TYPES = {
23814
23879
  ".jpg": "image/jpeg",
@@ -23831,7 +23896,7 @@ function filePathToPagePath(filePath) {
23831
23896
  }
23832
23897
  if (p.startsWith("pages/") || p.startsWith("src/pages/")) {
23833
23898
  p = p.replace(/^pages\//, "").replace(/^src\/pages\//, "");
23834
- const base = path10.basename(p, path10.extname(p));
23899
+ const base = path12.basename(p, path12.extname(p));
23835
23900
  return base === "index" ? "/" : "/" + base;
23836
23901
  }
23837
23902
  p = p.replace(/\.[^.]+$/, "").replace(/^\.\//, "").replace(/\\/g, "/");
@@ -23874,8 +23939,8 @@ async function imagesCommand(subcommand, options) {
23874
23939
  }
23875
23940
  }
23876
23941
  async function scanImages(options) {
23877
- const targetDir = path10.resolve(options.dir || ".");
23878
- const publicDir = path10.join(targetDir, "public");
23942
+ const targetDir = path12.resolve(options.dir || ".");
23943
+ const publicDir = path12.join(targetDir, "public");
23879
23944
  try {
23880
23945
  await fs3.access(publicDir);
23881
23946
  } catch {
@@ -23945,7 +24010,7 @@ async function uploadImages(options) {
23945
24010
  console.log("");
23946
24011
  process.exit(1);
23947
24012
  }
23948
- const targetDir = path10.resolve(options.dir || ".");
24013
+ const targetDir = path12.resolve(options.dir || ".");
23949
24014
  const spinner = ora("Scanning for images...").start();
23950
24015
  const results = await scanPublicImages(targetDir);
23951
24016
  spinner.stop();
@@ -23998,7 +24063,7 @@ async function uploadImages(options) {
23998
24063
  const uploadSpinner = ora(`Uploading ${img.filename}...`).start();
23999
24064
  try {
24000
24065
  const result = await uploadImageToPortal(
24001
- path10.join(targetDir, img.filePath),
24066
+ path12.join(targetDir, img.filePath),
24002
24067
  img,
24003
24068
  { apiUrl, apiKey, category: options.category }
24004
24069
  );
@@ -24017,7 +24082,7 @@ async function uploadImages(options) {
24017
24082
  }
24018
24083
  console.log("");
24019
24084
  if (uploaded.length > 0) {
24020
- const manifestPath = path10.join(targetDir, ".uptrade-images.json");
24085
+ const manifestPath = path12.join(targetDir, IMAGE_MANIFEST);
24021
24086
  await fs3.writeFile(manifestPath, JSON.stringify({
24022
24087
  uploaded,
24023
24088
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -24030,8 +24095,8 @@ async function uploadImages(options) {
24030
24095
  console.log("");
24031
24096
  }
24032
24097
  async function migrateImages(options) {
24033
- const targetDir = path10.resolve(options.dir || ".");
24034
- const manifestPath = path10.join(targetDir, ".uptrade-images.json");
24098
+ const targetDir = path12.resolve(options.dir || ".");
24099
+ const manifestPath = resolveImageManifestReadPath(targetDir);
24035
24100
  const apiUrl = process.env.SONOR_API_URL || "https://api.sonor.io";
24036
24101
  const apiKey = process.env.SONOR_API_KEY || "";
24037
24102
  if (!apiKey) {
@@ -24134,9 +24199,9 @@ async function migrateImages(options) {
24134
24199
  let successCount = 0;
24135
24200
  let failCount = 0;
24136
24201
  for (const [filePath, fileMigrations] of byFile) {
24137
- const fileSpinner = ora(`Migrating ${path10.basename(filePath)}...`).start();
24202
+ const fileSpinner = ora(`Migrating ${path12.basename(filePath)}...`).start();
24138
24203
  try {
24139
- await migrateFileImages(path10.join(targetDir, filePath), fileMigrations);
24204
+ await migrateFileImages(path12.join(targetDir, filePath), fileMigrations);
24140
24205
  successCount += fileMigrations.length;
24141
24206
  fileSpinner.succeed(`Migrated: ${filePath} (${fileMigrations.length} images)`);
24142
24207
  } catch (error2) {
@@ -24158,7 +24223,7 @@ async function migrateImages(options) {
24158
24223
  console.log("");
24159
24224
  }
24160
24225
  async function uploadAndMigrate(options) {
24161
- const targetDir = path10.resolve(options.dir || ".");
24226
+ const targetDir = path12.resolve(options.dir || ".");
24162
24227
  const apiUrl = process.env.SONOR_API_URL || "https://api.sonor.io";
24163
24228
  const apiKey = process.env.SONOR_API_KEY || "";
24164
24229
  if (!apiKey) {
@@ -24225,7 +24290,7 @@ async function uploadAndMigrate(options) {
24225
24290
  const uploadSpinner = ora(`Uploading ${img.filename}...`).start();
24226
24291
  try {
24227
24292
  const result = await uploadImageToPortal(
24228
- path10.join(targetDir, img.filePath),
24293
+ path12.join(targetDir, img.filePath),
24229
24294
  img,
24230
24295
  { apiUrl, apiKey, category: options.category }
24231
24296
  );
@@ -24297,9 +24362,9 @@ async function uploadAndMigrate(options) {
24297
24362
  let successCount = 0;
24298
24363
  let failCount = 0;
24299
24364
  for (const [filePath, fileMigrations] of byFile) {
24300
- const fileSpinner = ora(`Migrating ${path10.basename(filePath)}...`).start();
24365
+ const fileSpinner = ora(`Migrating ${path12.basename(filePath)}...`).start();
24301
24366
  try {
24302
- await migrateFileImages(path10.join(targetDir, filePath), fileMigrations);
24367
+ await migrateFileImages(path12.join(targetDir, filePath), fileMigrations);
24303
24368
  successCount += fileMigrations.length;
24304
24369
  fileSpinner.succeed(`Migrated: ${filePath} (${fileMigrations.length} images)`);
24305
24370
  } catch (error2) {
@@ -24307,7 +24372,7 @@ async function uploadAndMigrate(options) {
24307
24372
  fileSpinner.fail(`Failed: ${filePath} - ${error2.message}`);
24308
24373
  }
24309
24374
  }
24310
- const manifestPath = path10.join(targetDir, ".uptrade-images.json");
24375
+ const manifestPath = path12.join(targetDir, IMAGE_MANIFEST);
24311
24376
  await fs3.writeFile(manifestPath, JSON.stringify({
24312
24377
  uploaded,
24313
24378
  criticalKeptLocal: criticalImages.map((i) => i.filename),
@@ -24334,8 +24399,8 @@ async function uploadAndMigrate(options) {
24334
24399
  console.log("");
24335
24400
  }
24336
24401
  async function replaceWithCdnUrls(options) {
24337
- const targetDir = path10.resolve(options.dir || ".");
24338
- const manifestPath = path10.join(targetDir, ".uptrade-images.json");
24402
+ const targetDir = path12.resolve(options.dir || ".");
24403
+ const manifestPath = resolveImageManifestReadPath(targetDir);
24339
24404
  let manifest;
24340
24405
  try {
24341
24406
  const content = await fs3.readFile(manifestPath, "utf-8");
@@ -24383,7 +24448,7 @@ async function replaceWithCdnUrls(options) {
24383
24448
  if (!seenFileLines.has(key)) {
24384
24449
  seenFileLines.add(key);
24385
24450
  replacements2.push({
24386
- file: path10.relative(targetDir, file),
24451
+ file: path12.relative(targetDir, file),
24387
24452
  localPath: pattern,
24388
24453
  cdnUrl: img.publicUrl,
24389
24454
  line: i + 1
@@ -24431,9 +24496,9 @@ async function replaceWithCdnUrls(options) {
24431
24496
  let successCount = 0;
24432
24497
  let failCount = 0;
24433
24498
  for (const [filePath, fileReplacements] of byFile) {
24434
- const fileSpinner = ora(`Updating ${path10.basename(filePath)}...`).start();
24499
+ const fileSpinner = ora(`Updating ${path12.basename(filePath)}...`).start();
24435
24500
  try {
24436
- const fullPath = path10.join(targetDir, filePath);
24501
+ const fullPath = path12.join(targetDir, filePath);
24437
24502
  let content = await fs3.readFile(fullPath, "utf-8");
24438
24503
  for (const r of fileReplacements) {
24439
24504
  const escaped = r.localPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -24461,8 +24526,8 @@ async function replaceWithCdnUrls(options) {
24461
24526
  console.log("");
24462
24527
  }
24463
24528
  async function refreshManifest(options) {
24464
- const targetDir = path10.resolve(options.dir || ".");
24465
- const manifestPath = path10.join(targetDir, ".uptrade-images.json");
24529
+ const targetDir = path12.resolve(options.dir || ".");
24530
+ const manifestPath = path12.join(targetDir, IMAGE_MANIFEST);
24466
24531
  const apiUrl = process.env.SONOR_API_URL || "https://api.sonor.io";
24467
24532
  const apiKey = process.env.SONOR_API_KEY || "";
24468
24533
  if (!apiKey) {
@@ -24471,7 +24536,7 @@ async function refreshManifest(options) {
24471
24536
  }
24472
24537
  let manifest;
24473
24538
  try {
24474
- const content = await fs3.readFile(manifestPath, "utf-8");
24539
+ const content = await fs3.readFile(resolveImageManifestReadPath(targetDir), "utf-8");
24475
24540
  manifest = JSON.parse(content);
24476
24541
  } catch {
24477
24542
  console.log(source_default.yellow(" \u26A0 No upload manifest found"));
@@ -24524,12 +24589,12 @@ async function refreshManifest(options) {
24524
24589
  }
24525
24590
  async function findDataFiles(rootDir) {
24526
24591
  const files = [];
24527
- const excludeFiles = [".uptrade-images.json"];
24592
+ const excludeFiles = [IMAGE_MANIFEST, LEGACY_IMAGE_MANIFEST];
24528
24593
  async function scan(dir) {
24529
24594
  try {
24530
24595
  const entries = await fs3.readdir(dir, { withFileTypes: true });
24531
24596
  for (const entry of entries) {
24532
- const fullPath = path10.join(dir, entry.name);
24597
+ const fullPath = path12.join(dir, entry.name);
24533
24598
  if (entry.isDirectory()) {
24534
24599
  if (["node_modules", ".next", ".git", "dist", "build"].includes(entry.name)) {
24535
24600
  continue;
@@ -24539,7 +24604,7 @@ async function findDataFiles(rootDir) {
24539
24604
  if (excludeFiles.includes(entry.name)) {
24540
24605
  continue;
24541
24606
  }
24542
- const ext2 = path10.extname(entry.name).toLowerCase();
24607
+ const ext2 = path12.extname(entry.name).toLowerCase();
24543
24608
  if ([".js", ".ts", ".json", ".jsx", ".tsx", ".mjs", ".cjs"].includes(ext2)) {
24544
24609
  files.push(fullPath);
24545
24610
  }
@@ -24552,16 +24617,16 @@ async function findDataFiles(rootDir) {
24552
24617
  return files;
24553
24618
  }
24554
24619
  async function scanPublicImages(rootDir) {
24555
- const publicDir = path10.join(rootDir, "public");
24620
+ const publicDir = path12.join(rootDir, "public");
24556
24621
  const images = [];
24557
24622
  let totalSize = 0;
24558
24623
  let usageCount = 0;
24559
24624
  const imageFiles = await findImagesRecursive(publicDir);
24560
24625
  const sourceFiles = await findSourceFiles2(rootDir);
24561
24626
  for (const imagePath of imageFiles) {
24562
- const relPath = path10.relative(rootDir, imagePath);
24563
- const filename = path10.basename(imagePath);
24564
- const ext2 = path10.extname(filename).toLowerCase();
24627
+ const relPath = path12.relative(rootDir, imagePath);
24628
+ const filename = path12.basename(imagePath);
24629
+ const ext2 = path12.extname(filename).toLowerCase();
24565
24630
  const stat = await fs3.stat(imagePath);
24566
24631
  const category = getCategoryFromPath(relPath);
24567
24632
  const suggestedSlotId = generateSlotId(relPath);
@@ -24587,11 +24652,11 @@ async function findImagesRecursive(dir, files = []) {
24587
24652
  try {
24588
24653
  const entries = await fs3.readdir(dir, { withFileTypes: true });
24589
24654
  for (const entry of entries) {
24590
- const fullPath = path10.join(dir, entry.name);
24655
+ const fullPath = path12.join(dir, entry.name);
24591
24656
  if (entry.isDirectory()) {
24592
24657
  await findImagesRecursive(fullPath, files);
24593
24658
  } else if (entry.isFile()) {
24594
- const ext2 = path10.extname(entry.name).toLowerCase();
24659
+ const ext2 = path12.extname(entry.name).toLowerCase();
24595
24660
  if (IMAGE_EXTENSIONS.includes(ext2)) {
24596
24661
  files.push(fullPath);
24597
24662
  }
@@ -24604,7 +24669,7 @@ async function findImagesRecursive(dir, files = []) {
24604
24669
  async function findSourceFiles2(dir, files = []) {
24605
24670
  const entries = await fs3.readdir(dir, { withFileTypes: true });
24606
24671
  for (const entry of entries) {
24607
- const fullPath = path10.join(dir, entry.name);
24672
+ const fullPath = path12.join(dir, entry.name);
24608
24673
  if (entry.isDirectory()) {
24609
24674
  if (["node_modules", ".next", ".git", "dist", "build", "public"].includes(entry.name)) {
24610
24675
  continue;
@@ -24620,8 +24685,8 @@ async function findSourceFiles2(dir, files = []) {
24620
24685
  }
24621
24686
  async function findImageUsages(imagePath, sourceFiles, rootDir) {
24622
24687
  const usages = [];
24623
- const filename = path10.basename(imagePath);
24624
- const relPath = path10.relative(path10.join(rootDir, "public"), imagePath);
24688
+ const filename = path12.basename(imagePath);
24689
+ const relPath = path12.relative(path12.join(rootDir, "public"), imagePath);
24625
24690
  const patterns = [
24626
24691
  `/${relPath}`,
24627
24692
  // /images/hero.jpg
@@ -24643,7 +24708,7 @@ async function findImageUsages(imagePath, sourceFiles, rootDir) {
24643
24708
  const elementType = detectElementType(line);
24644
24709
  const canAutoMigrate = ["img", "Image"].includes(elementType);
24645
24710
  usages.push({
24646
- filePath: path10.relative(rootDir, sourceFile),
24711
+ filePath: path12.relative(rootDir, sourceFile),
24647
24712
  line: i + 1,
24648
24713
  elementType,
24649
24714
  altText: extractAltText(line),
@@ -24715,7 +24780,7 @@ function detectCriticalImage(filename, relPath, usages, fileSize) {
24715
24780
  (u) => u.filePath.includes("layout.") || u.filePath.includes("/layout/")
24716
24781
  );
24717
24782
  const usedInCriticalComponent = usages.some((u) => {
24718
- const fileName = path10.basename(u.filePath).toLowerCase();
24783
+ const fileName = path12.basename(u.filePath).toLowerCase();
24719
24784
  return fileName.includes("header") || fileName.includes("navbar") || fileName.includes("nav.") || fileName.includes("hero") || fileName.includes("footer");
24720
24785
  });
24721
24786
  const isSiteLogo = SITE_LOGO_PATTERNS.some((p) => p.test(filename));
@@ -24851,7 +24916,7 @@ async function uploadAndMigrateImages(scanResults, options) {
24851
24916
  for (const img of scanResults.images) {
24852
24917
  try {
24853
24918
  const uploadResult = await uploadImageToPortal(
24854
- path10.join(rootDir, img.filePath),
24919
+ path12.join(rootDir, img.filePath),
24855
24920
  img,
24856
24921
  {
24857
24922
  apiUrl: options.apiUrl,
@@ -24879,7 +24944,7 @@ async function uploadAndMigrateImages(scanResults, options) {
24879
24944
  }
24880
24945
  for (const [filePath, migrations] of byFile) {
24881
24946
  try {
24882
- await migrateFileImages(path10.join(rootDir, filePath), migrations);
24947
+ await migrateFileImages(path12.join(rootDir, filePath), migrations);
24883
24948
  result.migrated += migrations.length;
24884
24949
  } catch (error2) {
24885
24950
  result.errors.push(`Migration failed for ${filePath}: ${error2.message}`);
@@ -24893,31 +24958,25 @@ async function migrateCommand(options) {
24893
24958
  console.log("");
24894
24959
  console.log(source_default.bold(" Site-Kit Migration"));
24895
24960
  console.log("");
24896
- const apiKey = process.env.SONOR_API_KEY;
24897
- const projectId = process.env.SONOR_PROJECT_ID;
24898
- if (!apiKey || !projectId) {
24899
- console.log(source_default.red(" \u2717 Missing environment variables"));
24900
- console.log(source_default.gray(" Run `sonor-setup init` first to configure your project."));
24901
- console.log("");
24902
- process.exit(1);
24903
- }
24961
+ const { apiKey, projectId, apiUrl } = await loadConfig({ resolveProject: true });
24904
24962
  if (options.dryRun) {
24905
24963
  console.log(source_default.yellow(" Running in dry-run mode - no files will be modified"));
24906
24964
  console.log("");
24907
24965
  }
24908
24966
  if (options.file) {
24909
- const filePath = path10.resolve(options.file);
24967
+ const filePath = path12.resolve(options.file);
24910
24968
  try {
24911
24969
  await fs3.access(filePath);
24912
24970
  } catch {
24913
24971
  console.log(source_default.red(` \u2717 File not found: ${filePath}`));
24914
24972
  process.exit(1);
24915
24973
  }
24916
- const spinner = ora(`Migrating ${path10.basename(filePath)}...`).start();
24974
+ const spinner = ora(`Migrating ${path12.basename(filePath)}...`).start();
24917
24975
  try {
24918
24976
  const result = await migrateFile(filePath, {
24919
24977
  projectId,
24920
24978
  apiKey,
24979
+ apiUrl,
24921
24980
  dryRun: options.dryRun
24922
24981
  });
24923
24982
  if (result.success) {
@@ -24980,6 +25039,7 @@ async function migrateCommand(options) {
24980
25039
  const results = await migrateFiles(scanResults, {
24981
25040
  projectId,
24982
25041
  apiKey,
25042
+ apiUrl,
24983
25043
  dryRun: options.dryRun
24984
25044
  });
24985
25045
  const successful = results.filter((r) => r.success);
@@ -25009,10 +25069,9 @@ async function migrateCommand(options) {
25009
25069
  process.exit(1);
25010
25070
  }
25011
25071
  console.log("");
25012
- await handleImageMigration(options, apiKey);
25072
+ await handleImageMigration(options, apiKey, apiUrl);
25013
25073
  }
25014
- async function handleImageMigration(options, apiKey, projectId) {
25015
- const apiUrl = process.env.SONOR_API_URL || "https://api.sonor.io";
25074
+ async function handleImageMigration(options, apiKey, apiUrl) {
25016
25075
  const imageScanSpinner = ora("Scanning for images...").start();
25017
25076
  let imageResults;
25018
25077
  try {
@@ -25076,17 +25135,11 @@ function formatBytes2(bytes) {
25076
25135
  return `${parseFloat((bytes / Math.pow(k2, i)).toFixed(1))} ${sizes[i]}`;
25077
25136
  }
25078
25137
  var SKIP_PROPS = ["href", "src", "className", "style", "onClick", "ref", "key", "id", "target", "rel", "type", "name", "variant", "size", "icon"];
25079
- var API_URL2 = process.env.SONOR_API_URL || "https://api.sonor.io";
25080
- var TEMPLATES_DIR = ".uptrade/templates";
25138
+ var TEMPLATES_DIR = path12.join(SONOR_STATE_DIR, "templates");
25081
25139
  async function locationsCommand(subcommand, arg, options) {
25082
25140
  console.log("");
25083
25141
  console.log(source_default.bold(" \u{1F4CD} Site-Kit Location Page Manager"));
25084
25142
  console.log("");
25085
- const config2 = await loadConfig();
25086
- if (!config2?.projectId) {
25087
- console.log(source_default.red(" \u2717 Not configured. Run `npx sonor-setup init` first."));
25088
- return;
25089
- }
25090
25143
  switch (subcommand) {
25091
25144
  case "template":
25092
25145
  if (!arg) {
@@ -25094,6 +25147,7 @@ async function locationsCommand(subcommand, arg, options) {
25094
25147
  console.log(source_default.gray(" Example: locations template ./app/services/plumbing/page.tsx"));
25095
25148
  return;
25096
25149
  }
25150
+ await loadConfig();
25097
25151
  await templateCommand(arg, options);
25098
25152
  break;
25099
25153
  case "upload":
@@ -25101,17 +25155,17 @@ async function locationsCommand(subcommand, arg, options) {
25101
25155
  console.log(source_default.red(" \u2717 Usage: locations upload --template <name>"));
25102
25156
  return;
25103
25157
  }
25104
- await uploadCommand(options.template, config2);
25158
+ await uploadCommand(options.template, await loadConfig({ resolveProject: true }));
25105
25159
  break;
25106
25160
  case "generate":
25107
25161
  if (!options.template) {
25108
25162
  console.log(source_default.red(' \u2717 Usage: locations generate --template <name> --locations "City, ST" ...'));
25109
25163
  return;
25110
25164
  }
25111
- await generateCommand(options, config2);
25165
+ await generateCommand(options, await loadConfig({ resolveProject: true }));
25112
25166
  break;
25113
25167
  case "list":
25114
- await listCommand(config2);
25168
+ await listCommand(await loadConfig({ resolveProject: true }));
25115
25169
  break;
25116
25170
  default:
25117
25171
  console.log(source_default.yellow(" Available subcommands:"));
@@ -25123,10 +25177,10 @@ async function locationsCommand(subcommand, arg, options) {
25123
25177
  console.log("");
25124
25178
  }
25125
25179
  }
25126
- async function templateCommand(sourcePath, options, config2) {
25180
+ async function templateCommand(sourcePath, options) {
25127
25181
  const spinner = ora("Analyzing source page...").start();
25128
25182
  try {
25129
- const resolvedPath = path10.resolve(sourcePath);
25183
+ const resolvedPath = path12.resolve(sourcePath);
25130
25184
  if (!existsSync(resolvedPath)) {
25131
25185
  spinner.fail(`File not found: ${sourcePath}`);
25132
25186
  return;
@@ -25139,8 +25193,8 @@ async function templateCommand(sourcePath, options, config2) {
25139
25193
  const slots = [];
25140
25194
  const componentNames = [];
25141
25195
  traverse(ast, {
25142
- JSXElement(path27) {
25143
- const openingElement = path27.node.openingElement;
25196
+ JSXElement(path30) {
25197
+ const openingElement = path30.node.openingElement;
25144
25198
  if (isJSXIdentifier(openingElement.name)) {
25145
25199
  const componentName = openingElement.name.name;
25146
25200
  if (componentName[0] === componentName[0].toUpperCase()) {
@@ -25180,8 +25234,9 @@ async function templateCommand(sourcePath, options, config2) {
25180
25234
  },
25181
25235
  managed_components: ["schema", "faqs", "metadata"]
25182
25236
  };
25183
- await fs3.mkdir(TEMPLATES_DIR, { recursive: true });
25184
- const templatePath = path10.join(TEMPLATES_DIR, `${templateName}.json`);
25237
+ const templatesDir = path12.join(process.cwd(), TEMPLATES_DIR);
25238
+ await fs3.mkdir(templatesDir, { recursive: true });
25239
+ const templatePath = path12.join(templatesDir, `${templateName}.json`);
25185
25240
  await fs3.writeFile(templatePath, JSON.stringify(template, null, 2));
25186
25241
  console.log("");
25187
25242
  console.log(source_default.green(" \u2713 Template created:"), source_default.cyan(templatePath));
@@ -25260,7 +25315,7 @@ function inferGenerationHint(propName) {
25260
25315
  return void 0;
25261
25316
  }
25262
25317
  function inferTemplateName(sourcePath) {
25263
- const parts = sourcePath.split(path10.sep);
25318
+ const parts = sourcePath.split(path12.sep);
25264
25319
  const pageIndex = parts.findIndex((p) => p === "page.tsx" || p === "page.jsx");
25265
25320
  if (pageIndex > 0) {
25266
25321
  return parts[pageIndex - 1];
@@ -25269,14 +25324,14 @@ function inferTemplateName(sourcePath) {
25269
25324
  return filtered[filtered.length - 1] || "template";
25270
25325
  }
25271
25326
  function inferSourcePagePath(sourcePath) {
25272
- const parts = sourcePath.split(path10.sep);
25327
+ const parts = sourcePath.split(path12.sep);
25273
25328
  const appIndex = parts.findIndex((p) => p === "app" || p === "pages");
25274
25329
  if (appIndex >= 0) {
25275
25330
  const pathParts = parts.slice(appIndex + 1);
25276
25331
  const filtered = pathParts.filter((p) => !["page.tsx", "page.jsx", "index.tsx", "index.jsx"].includes(p));
25277
25332
  return "/" + filtered.join("/");
25278
25333
  }
25279
- return "/" + path10.basename(sourcePath, path10.extname(sourcePath));
25334
+ return "/" + path12.basename(sourcePath, path12.extname(sourcePath));
25280
25335
  }
25281
25336
  function toSnakeCase(str) {
25282
25337
  return str.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
@@ -25288,22 +25343,22 @@ function truncate(str, maxLength) {
25288
25343
  async function uploadCommand(templateName, config2) {
25289
25344
  const spinner = ora("Uploading template to Portal...").start();
25290
25345
  try {
25291
- const templatePath = path10.join(TEMPLATES_DIR, `${templateName}.json`);
25346
+ const templatePath = resolveStateReadPath(path12.join("templates", `${templateName}.json`));
25292
25347
  if (!existsSync(templatePath)) {
25293
25348
  spinner.fail(`Template not found: ${templatePath}`);
25294
25349
  console.log(source_default.gray(` Run: npx sonor-setup locations template <page> --name ${templateName}`));
25295
25350
  return;
25296
25351
  }
25297
25352
  const template = JSON.parse(readFileSync(templatePath, "utf-8"));
25298
- const response = await fetch(`${API_URL2}/seo/location-templates`, {
25353
+ const response = await fetch(`${config2.apiUrl}/seo/location-templates`, {
25299
25354
  method: "POST",
25300
25355
  headers: {
25301
25356
  "Content-Type": "application/json",
25302
25357
  "Authorization": `Bearer ${config2.apiKey}`
25303
25358
  },
25304
25359
  body: JSON.stringify({
25305
- project_id: config2.projectId,
25306
- ...template
25360
+ ...template,
25361
+ project_id: config2.projectId
25307
25362
  })
25308
25363
  });
25309
25364
  if (!response.ok) {
@@ -25311,11 +25366,11 @@ async function uploadCommand(templateName, config2) {
25311
25366
  if (response.status === 409) {
25312
25367
  spinner.text = "Template exists, updating...";
25313
25368
  const existing = await fetch(
25314
- `${API_URL2}/seo/location-templates/by-name/${templateName}?project_id=${config2.projectId}`,
25369
+ `${config2.apiUrl}/seo/location-templates/by-name/${templateName}?project_id=${config2.projectId}`,
25315
25370
  { headers: { "Authorization": `Bearer ${config2.apiKey}` } }
25316
25371
  );
25317
25372
  const existingData = await existing.json();
25318
- const updateResponse = await fetch(`${API_URL2}/seo/location-templates/${existingData.id}`, {
25373
+ const updateResponse = await fetch(`${config2.apiUrl}/seo/location-templates/${existingData.id}`, {
25319
25374
  method: "PUT",
25320
25375
  headers: {
25321
25376
  "Content-Type": "application/json",
@@ -25364,7 +25419,7 @@ async function generateCommand(options, config2) {
25364
25419
  }
25365
25420
  const spinner = ora(`Generating ${type || "service-location"} pages...`).start();
25366
25421
  try {
25367
- const response = await fetch(`${API_URL2}/seo/location-pages/generate`, {
25422
+ const response = await fetch(`${config2.apiUrl}/seo/location-pages/generate`, {
25368
25423
  method: "POST",
25369
25424
  headers: {
25370
25425
  "Content-Type": "application/json",
@@ -25404,7 +25459,7 @@ async function listCommand(config2) {
25404
25459
  const spinner = ora("Fetching templates...").start();
25405
25460
  try {
25406
25461
  const response = await fetch(
25407
- `${API_URL2}/seo/location-templates?project_id=${config2.projectId}`,
25462
+ `${config2.apiUrl}/seo/location-templates?project_id=${config2.projectId}`,
25408
25463
  { headers: { "Authorization": `Bearer ${config2.apiKey}` } }
25409
25464
  );
25410
25465
  if (!response.ok) {
@@ -25429,69 +25484,21 @@ async function listCommand(config2) {
25429
25484
  });
25430
25485
  }
25431
25486
  console.log("");
25432
- if (existsSync(TEMPLATES_DIR)) {
25433
- const files = await fs3.readdir(TEMPLATES_DIR);
25434
- const localTemplates = files.filter((f) => f.endsWith(".json"));
25435
- if (localTemplates.length > 0) {
25436
- console.log(source_default.gray(" Local (not uploaded):"));
25437
- localTemplates.forEach((f) => {
25438
- console.log(source_default.gray(` \u2022 ${f.replace(".json", "")}`));
25439
- });
25440
- console.log("");
25441
- }
25487
+ const localTemplates = await listLocalTemplates();
25488
+ if (localTemplates.length > 0) {
25489
+ console.log(source_default.gray(" Local (not uploaded):"));
25490
+ localTemplates.forEach((f) => {
25491
+ console.log(source_default.gray(` \u2022 ${f.replace(".json", "")}`));
25492
+ });
25493
+ console.log("");
25442
25494
  }
25443
25495
  } catch (error2) {
25444
25496
  spinner.fail(`Failed to fetch templates: ${error2.message}`);
25445
25497
  }
25446
25498
  }
25447
- async function loadConfig() {
25448
- const configPath = path10.join(".uptrade", "config.json");
25449
- if (existsSync(configPath)) {
25450
- try {
25451
- const config2 = JSON.parse(readFileSync(configPath, "utf-8"));
25452
- return {
25453
- projectId: config2.projectId || config2.project_id,
25454
- apiKey: config2.apiKey || config2.api_key
25455
- };
25456
- } catch {
25457
- return null;
25458
- }
25459
- }
25460
- const projectId = process.env.SONOR_PROJECT_ID;
25461
- const apiKey = process.env.SONOR_API_KEY;
25462
- if (projectId && apiKey) {
25463
- return { projectId, apiKey };
25464
- }
25465
- return null;
25466
- }
25467
- var API_URL3 = process.env.SONOR_API_URL || "https://api.sonor.io";
25468
- async function loadConfig2() {
25469
- const configPath = path10.join(".uptrade", "config.json");
25470
- if (existsSync(configPath)) {
25471
- try {
25472
- const config2 = JSON.parse(readFileSync(configPath, "utf-8"));
25473
- return {
25474
- projectId: config2.projectId || config2.project_id,
25475
- apiKey: config2.apiKey || config2.api_key
25476
- };
25477
- } catch {
25478
- return null;
25479
- }
25480
- }
25481
- const projectId = process.env.SONOR_PROJECT_ID;
25482
- const apiKey = process.env.SONOR_API_KEY;
25483
- if (projectId && apiKey) return { projectId, apiKey };
25484
- return null;
25485
- }
25486
25499
  async function faqsCommand(subcommand, options) {
25487
25500
  console.log("");
25488
- const config2 = await loadConfig2();
25489
- if (!config2?.projectId || !config2?.apiKey) {
25490
- console.log(source_default.red(" \u2717 Not configured. Run `npx sonor-setup init` first."));
25491
- console.log(source_default.gray(" Set SONOR_API_KEY, or use .uptrade/config.json"));
25492
- console.log("");
25493
- return;
25494
- }
25501
+ const config2 = await loadConfig({ resolveProject: true });
25495
25502
  switch (subcommand) {
25496
25503
  case "extract":
25497
25504
  await extractCommand(options, config2);
@@ -25541,7 +25548,7 @@ async function extractCommand(options, config2) {
25541
25548
  const faqContexts = [];
25542
25549
  for (const faq of faqSections) {
25543
25550
  try {
25544
- const fullPath = path10.resolve(process.cwd(), faq.filePath);
25551
+ const fullPath = path12.resolve(process.cwd(), faq.filePath);
25545
25552
  const content = await fs3.readFile(fullPath, "utf-8");
25546
25553
  let pagePath = faq.filePath.replace(/^app\//, "/").replace(/^src\/app\//, "/").replace(/\/page\.(tsx?|jsx?)$/, "").replace(/\[([^\]]+)\]/g, ":$1");
25547
25554
  if (pagePath === "" || pagePath === "/page") pagePath = "/";
@@ -25556,7 +25563,7 @@ async function extractCommand(options, config2) {
25556
25563
  if (importPath.startsWith("@/")) {
25557
25564
  resolvedPath = importPath.replace("@/", "./");
25558
25565
  } else if (importPath.startsWith(".")) {
25559
- resolvedPath = path10.resolve(path10.dirname(fullPath), importPath);
25566
+ resolvedPath = path12.resolve(path12.dirname(fullPath), importPath);
25560
25567
  }
25561
25568
  const extensions = ["", ".js", ".ts", ".jsx", ".tsx", ".json"];
25562
25569
  for (const ext2 of extensions) {
@@ -25601,7 +25608,7 @@ async function extractCommand(options, config2) {
25601
25608
  }
25602
25609
  const extractSpinner = ora("Extracting FAQs via AI...").start();
25603
25610
  try {
25604
- const response = await fetch(`${API_URL3}/seo/managed/faqs/extract`, {
25611
+ const response = await fetch(`${config2.apiUrl}/seo/managed/faqs/extract`, {
25605
25612
  method: "POST",
25606
25613
  headers: {
25607
25614
  "Content-Type": "application/json",
@@ -25636,7 +25643,7 @@ async function extractCommand(options, config2) {
25636
25643
  let failed = 0;
25637
25644
  for (const faq of extractedFaqs) {
25638
25645
  try {
25639
- const res = await fetch(`${API_URL3}/seo/managed/faqs`, {
25646
+ const res = await fetch(`${config2.apiUrl}/seo/managed/faqs`, {
25640
25647
  method: "POST",
25641
25648
  headers: {
25642
25649
  "Content-Type": "application/json",
@@ -25661,7 +25668,7 @@ async function extractCommand(options, config2) {
25661
25668
  uploaded++;
25662
25669
  console.log(source_default.green(` \u2713 ${faq.path}`) + source_default.gray(` (${faq.items.length} items)`));
25663
25670
  } else if (res.status === 409 || res.status === 400) {
25664
- const updateRes = await fetch(`${API_URL3}/seo/managed/faqs/by-path`, {
25671
+ const updateRes = await fetch(`${config2.apiUrl}/seo/managed/faqs/by-path`, {
25665
25672
  method: "PUT",
25666
25673
  headers: {
25667
25674
  "Content-Type": "application/json",
@@ -25748,7 +25755,7 @@ async function syncCommand(options, config2) {
25748
25755
  const listSpinner = ora("Fetching existing FAQ sections from Portal...").start();
25749
25756
  let existing = [];
25750
25757
  try {
25751
- const res = await fetch(`${API_URL3}/seo/managed/faqs/project/${config2.projectId}`, {
25758
+ const res = await fetch(`${config2.apiUrl}/seo/managed/faqs/project/${config2.projectId}`, {
25752
25759
  headers: { Authorization: `Bearer ${config2.apiKey}` }
25753
25760
  });
25754
25761
  if (!res.ok) {
@@ -25777,7 +25784,7 @@ async function syncCommand(options, config2) {
25777
25784
  let failed = 0;
25778
25785
  for (const p of toCreate) {
25779
25786
  try {
25780
- const res = await fetch(`${API_URL3}/seo/managed/faqs`, {
25787
+ const res = await fetch(`${config2.apiUrl}/seo/managed/faqs`, {
25781
25788
  method: "POST",
25782
25789
  headers: {
25783
25790
  "Content-Type": "application/json",
@@ -25814,44 +25821,12 @@ async function syncCommand(options, config2) {
25814
25821
  console.log(source_default.gray(" Add questions and answers there; they will appear on your site."));
25815
25822
  console.log("");
25816
25823
  }
25817
- function getApiUrl() {
25818
- return process.env.SONOR_API_URL || "https://api.sonor.io";
25819
- }
25820
- async function loadConfig3() {
25821
- const configPath = path10.join(".uptrade", "config.json");
25822
- if (existsSync(configPath)) {
25823
- try {
25824
- const config2 = JSON.parse(readFileSync(configPath, "utf-8"));
25825
- return {
25826
- projectId: config2.projectId || config2.project_id,
25827
- apiKey: config2.apiKey || config2.api_key,
25828
- siteUrl: config2.siteUrl || config2.site_url,
25829
- businessInfo: config2.businessInfo || config2.business_info
25830
- };
25831
- } catch {
25832
- return null;
25833
- }
25834
- }
25835
- const projectId = process.env.SONOR_PROJECT_ID;
25836
- const apiKey = process.env.SONOR_API_KEY;
25837
- const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || process.env.SITE_URL;
25838
- if (projectId && apiKey) {
25839
- return { projectId, apiKey, siteUrl };
25840
- }
25841
- return null;
25842
- }
25843
25824
  async function setupCommand(options) {
25844
25825
  console.log("");
25845
25826
  console.log(source_default.bold.blue(" \u{1F680} Signal-Enhanced SEO Setup"));
25846
25827
  console.log(source_default.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
25847
25828
  console.log("");
25848
- const config2 = await loadConfig3();
25849
- if (!config2?.projectId || !config2?.apiKey) {
25850
- console.log(source_default.red(" \u2717 Not configured. Run `npx sonor-setup init` first."));
25851
- console.log(source_default.gray(" Set SONOR_API_KEY"));
25852
- console.log("");
25853
- return;
25854
- }
25829
+ const config2 = await loadConfig();
25855
25830
  const capabilities = [];
25856
25831
  if (options.faqsOnly) {
25857
25832
  capabilities.push("extract_faqs");
@@ -25949,14 +25924,13 @@ async function setupCommand(options) {
25949
25924
  const batch = batches[batchIndex];
25950
25925
  const batchSpinner = ora(`Batch ${batchIndex + 1}/${batches.length}: Analyzing ${batch.length} pages...`).start();
25951
25926
  try {
25952
- const response = await fetch(`${getApiUrl()}/api/public/seo/site-setup`, {
25927
+ const response = await fetch(`${config2.apiUrl}/api/public/seo/site-setup`, {
25953
25928
  method: "POST",
25954
25929
  headers: {
25955
25930
  "Content-Type": "application/json",
25956
25931
  "x-api-key": config2.apiKey
25957
25932
  },
25958
25933
  body: JSON.stringify({
25959
- project_id: config2.projectId,
25960
25934
  site_url: config2.siteUrl || "https://example.com",
25961
25935
  // Only send business_info on first batch (for org schema)
25962
25936
  business_info: batchIndex === 0 ? config2.businessInfo : void 0,
@@ -26048,10 +26022,10 @@ async function setupCommand(options) {
26048
26022
  }
26049
26023
  async function scanForPageFiles(rootDir) {
26050
26024
  const pages = [];
26051
- const appDir = path10.join(rootDir, "app");
26052
- const srcAppDir = path10.join(rootDir, "src", "app");
26053
- const pagesDir = path10.join(rootDir, "pages");
26054
- const srcPagesDir = path10.join(rootDir, "src", "pages");
26025
+ const appDir = path12.join(rootDir, "app");
26026
+ const srcAppDir = path12.join(rootDir, "src", "app");
26027
+ const pagesDir = path12.join(rootDir, "pages");
26028
+ const srcPagesDir = path12.join(rootDir, "src", "pages");
26055
26029
  const dirs = [appDir, srcAppDir, pagesDir, srcPagesDir];
26056
26030
  for (const dir of dirs) {
26057
26031
  if (existsSync(dir)) {
@@ -26063,7 +26037,7 @@ async function scanForPageFiles(rootDir) {
26063
26037
  async function scanDirectory(dir, baseDir, pages) {
26064
26038
  const entries = await fs3.readdir(dir, { withFileTypes: true });
26065
26039
  for (const entry of entries) {
26066
- const fullPath = path10.join(dir, entry.name);
26040
+ const fullPath = path12.join(dir, entry.name);
26067
26041
  if (entry.isDirectory()) {
26068
26042
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "api") {
26069
26043
  continue;
@@ -26074,8 +26048,8 @@ async function scanDirectory(dir, baseDir, pages) {
26074
26048
  const isLegacyPage = baseDir.includes("/pages") && entry.name.match(/\.(tsx?|jsx?)$/) && !entry.name.startsWith("_");
26075
26049
  if (isPage || isLegacyPage) {
26076
26050
  const content = await fs3.readFile(fullPath, "utf-8");
26077
- const relativePath = path10.relative(baseDir, fullPath);
26078
- let pagePath = "/" + path10.dirname(relativePath).replace(/\\/g, "/").replace(/\/page$/, "");
26051
+ const relativePath = path12.relative(baseDir, fullPath);
26052
+ let pagePath = "/" + path12.dirname(relativePath).replace(/\\/g, "/").replace(/\/page$/, "");
26079
26053
  pagePath = pagePath.replace(/\[([^\]]+)\]/g, ":$1").replace(/^\/\.$/, "/");
26080
26054
  if (pagePath === "/.") pagePath = "/";
26081
26055
  pages.push({
@@ -26095,10 +26069,10 @@ async function gatherImportedFiles(page, rootDir) {
26095
26069
  if (importPath.toLowerCase().includes("faq") || importPath.includes("@/data") || importPath.includes("./data") || importPath.includes("../data") || importPath.includes("/constants") || importPath.includes("/content") || importPath.includes("practice-areas") || importPath.includes("subpages") || importPath.includes("pages-data")) {
26096
26070
  let resolvedPath = importPath;
26097
26071
  if (importPath.startsWith("@/")) {
26098
- resolvedPath = path10.join(rootDir, importPath.replace("@/", ""));
26072
+ resolvedPath = path12.join(rootDir, importPath.replace("@/", ""));
26099
26073
  } else if (importPath.startsWith(".")) {
26100
- const pageDir = path10.dirname(path10.join(rootDir, "app", page.filePath));
26101
- resolvedPath = path10.resolve(pageDir, importPath);
26074
+ const pageDir = path12.dirname(path12.join(rootDir, "app", page.filePath));
26075
+ resolvedPath = path12.resolve(pageDir, importPath);
26102
26076
  }
26103
26077
  const extensions = ["", ".js", ".ts", ".jsx", ".tsx", ".json"];
26104
26078
  for (const ext2 of extensions) {
@@ -26154,20 +26128,20 @@ async function expandDynamicRoutes(pages, rootDir) {
26154
26128
  async function findDynamicRouteData(page, parentPath, rootDir) {
26155
26129
  const results = [];
26156
26130
  const dataFilePaths = [
26157
- path10.join(rootDir, "data", "practice-areas.js"),
26158
- path10.join(rootDir, "data", "practice-areas.ts"),
26159
- path10.join(rootDir, "data", "personal-injury-pages.js"),
26160
- path10.join(rootDir, "data", "personal-injury-pages.ts"),
26161
- path10.join(rootDir, "data", "pages.js"),
26162
- path10.join(rootDir, "data", "pages.ts"),
26163
- path10.join(rootDir, "data", "content.js"),
26164
- path10.join(rootDir, "data", "content.ts"),
26165
- path10.join(rootDir, "data", "services.js"),
26166
- path10.join(rootDir, "data", "services.ts"),
26167
- path10.join(rootDir, "data", "subpages.js"),
26168
- path10.join(rootDir, "data", "subpages.ts"),
26169
- path10.join(rootDir, "src", "data", "practice-areas.js"),
26170
- path10.join(rootDir, "src", "data", "practice-areas.ts")
26131
+ path12.join(rootDir, "data", "practice-areas.js"),
26132
+ path12.join(rootDir, "data", "practice-areas.ts"),
26133
+ path12.join(rootDir, "data", "personal-injury-pages.js"),
26134
+ path12.join(rootDir, "data", "personal-injury-pages.ts"),
26135
+ path12.join(rootDir, "data", "pages.js"),
26136
+ path12.join(rootDir, "data", "pages.ts"),
26137
+ path12.join(rootDir, "data", "content.js"),
26138
+ path12.join(rootDir, "data", "content.ts"),
26139
+ path12.join(rootDir, "data", "services.js"),
26140
+ path12.join(rootDir, "data", "services.ts"),
26141
+ path12.join(rootDir, "data", "subpages.js"),
26142
+ path12.join(rootDir, "data", "subpages.ts"),
26143
+ path12.join(rootDir, "src", "data", "practice-areas.js"),
26144
+ path12.join(rootDir, "src", "data", "practice-areas.ts")
26171
26145
  ];
26172
26146
  const routeSegment = parentPath.replace(/^\//, "").split("/")[0];
26173
26147
  const routeSegmentNormalized = routeSegment.replace(/-/g, "");
@@ -26259,7 +26233,7 @@ async function uploadFaqs(pages, config2) {
26259
26233
  for (const page of pages) {
26260
26234
  if (!page.faqs?.items?.length) continue;
26261
26235
  try {
26262
- const res = await fetch(`${getApiUrl()}/api/public/seo/register-faq`, {
26236
+ const res = await fetch(`${config2.apiUrl}/api/public/seo/register-faq`, {
26263
26237
  method: "POST",
26264
26238
  headers: {
26265
26239
  "Content-Type": "application/json",
@@ -26294,7 +26268,7 @@ async function uploadFaqs(pages, config2) {
26294
26268
  async function uploadSchemas(pages, globalSchema, config2) {
26295
26269
  if (globalSchema) {
26296
26270
  try {
26297
- const res = await fetch(`${getApiUrl()}/api/public/seo/register-schema`, {
26271
+ const res = await fetch(`${config2.apiUrl}/api/public/seo/register-schema`, {
26298
26272
  method: "POST",
26299
26273
  headers: {
26300
26274
  "Content-Type": "application/json",
@@ -26320,7 +26294,7 @@ async function uploadSchemas(pages, globalSchema, config2) {
26320
26294
  if (!page.schemas?.length) continue;
26321
26295
  for (const schema of page.schemas) {
26322
26296
  try {
26323
- const res = await fetch(`${getApiUrl()}/api/public/seo/register-schema`, {
26297
+ const res = await fetch(`${config2.apiUrl}/api/public/seo/register-schema`, {
26324
26298
  method: "POST",
26325
26299
  headers: {
26326
26300
  "Content-Type": "application/json",
@@ -26344,8 +26318,7 @@ async function uploadSchemas(pages, globalSchema, config2) {
26344
26318
  }
26345
26319
  }
26346
26320
  }
26347
- var APP_DIRS = ["app", path10.join("src", "app")];
26348
- var CARD_FILE = /^(opengraph-image|twitter-image)\b.*\.(png|jpe?g|gif|webp)$/i;
26321
+ var CARD_FILE = /^(opengraph-image|twitter-image)\b.*\.(png|jpe?g|gif|webp|tsx|ts|jsx|js)$/i;
26349
26322
  function safeExists(p) {
26350
26323
  try {
26351
26324
  return fs__default.existsSync(p);
@@ -26364,19 +26337,19 @@ function findPageCards(cwd) {
26364
26337
  }
26365
26338
  for (const entry of entries) {
26366
26339
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
26367
- const full = path10.join(dir, entry.name);
26340
+ const full = path12.join(dir, entry.name);
26368
26341
  if (entry.isDirectory()) walk(full);
26369
26342
  else if (CARD_FILE.test(entry.name)) found.push(full);
26370
26343
  }
26371
26344
  };
26372
- for (const rel of APP_DIRS) walk(path10.join(cwd, rel));
26345
+ for (const rel of NEXT_APP_DIRS) walk(path12.join(cwd, rel));
26373
26346
  return found;
26374
26347
  }
26375
26348
  function readOgWiring(cwd) {
26376
26349
  const siteCard = ["public/og.png", "public/og.jpg", "public/opengraph.png"].some(
26377
- (rel) => safeExists(path10.join(cwd, rel))
26350
+ (rel) => safeExists(path12.join(cwd, rel))
26378
26351
  );
26379
- const layoutPath = ["app/layout.tsx", "src/app/layout.tsx"].map((rel) => path10.join(cwd, rel)).find(safeExists);
26352
+ const layoutPath = findRootLayout(cwd);
26380
26353
  let layout = "";
26381
26354
  if (layoutPath) {
26382
26355
  try {
@@ -26396,7 +26369,12 @@ function readOgWiring(cwd) {
26396
26369
  function judgeOgWiring(facts) {
26397
26370
  const problems = [];
26398
26371
  if (!facts.layoutFound) {
26399
- return [{ message: "no app/layout.tsx found to verify metadata", fix: "Run this from the site root." }];
26372
+ return [
26373
+ {
26374
+ message: "no root layout (app/layout.{tsx,ts,jsx,js} or src/app/layout.*) found to verify metadata",
26375
+ fix: "Run this from the site root."
26376
+ }
26377
+ ];
26400
26378
  }
26401
26379
  if (!facts.siteCard && !facts.pageCards.length) {
26402
26380
  return [
@@ -26443,7 +26421,7 @@ var SSR_BAILOUT_FIX = `Keep the layout: ${LAYOUT_ALREADY_DEFERS}, so it is not t
26443
26421
  var ANALYTICS_WRAPPER_FIX = `Remove the <AnalyticsProvider> wrapper: ${LAYOUT_ALREADY_DEFERS} (configure it with analytics={{ ... }}). Track custom events with trackEvent / trackConversion from @sonordev/site-kit/analytics, which need no provider, instead of useAnalytics(). ` + LEGACY_STOPGAP;
26444
26422
 
26445
26423
  // src/cli/agent/checks.ts
26446
- var API_URL4 = process.env.SONOR_API_URL || "https://api.sonor.io";
26424
+ var API_URL = process.env.SONOR_API_URL || "https://api.sonor.io";
26447
26425
  async function readFileOrNull(p) {
26448
26426
  try {
26449
26427
  return await fs3.readFile(p, "utf-8");
@@ -26451,26 +26429,6 @@ async function readFileOrNull(p) {
26451
26429
  return null;
26452
26430
  }
26453
26431
  }
26454
- async function findFirst(cwd, candidates) {
26455
- for (const rel of candidates) {
26456
- const full = path10.join(cwd, rel);
26457
- if (await readFileOrNull(full)) return full;
26458
- }
26459
- return null;
26460
- }
26461
- var LAYOUT_CANDIDATES = [
26462
- "app/layout.tsx",
26463
- "app/layout.jsx",
26464
- "src/app/layout.tsx",
26465
- "src/app/layout.jsx"
26466
- ];
26467
- var SITEMAP_CANDIDATES = [
26468
- "app/sitemap.ts",
26469
- "app/sitemap.tsx",
26470
- "app/sitemap.js",
26471
- "src/app/sitemap.ts",
26472
- "src/app/sitemap.tsx"
26473
- ];
26474
26432
  function checkApiKeyEnv() {
26475
26433
  const key = process.env.SONOR_API_KEY;
26476
26434
  if (key && key.startsWith("sonor_")) {
@@ -26505,7 +26463,7 @@ function checkApiKeyEnv() {
26505
26463
  };
26506
26464
  }
26507
26465
  async function checkPackageInstalled(cwd) {
26508
- const raw = await readFileOrNull(path10.join(cwd, "package.json"));
26466
+ const raw = await readFileOrNull(path12.join(cwd, "package.json"));
26509
26467
  if (!raw) {
26510
26468
  return {
26511
26469
  id: "package.installed",
@@ -26557,7 +26515,7 @@ async function checkPackageInstalled(cwd) {
26557
26515
  };
26558
26516
  }
26559
26517
  async function checkSiteKitLayout(cwd) {
26560
- const layoutPath = await findFirst(cwd, LAYOUT_CANDIDATES);
26518
+ const layoutPath = findRootLayout(cwd);
26561
26519
  if (!layoutPath) {
26562
26520
  return {
26563
26521
  id: "layout.sitekit",
@@ -26569,7 +26527,7 @@ async function checkSiteKitLayout(cwd) {
26569
26527
  };
26570
26528
  }
26571
26529
  const content = await readFileOrNull(layoutPath) || "";
26572
- const rel = path10.relative(cwd, layoutPath);
26530
+ const rel = path12.relative(cwd, layoutPath);
26573
26531
  if (content.includes("SiteKitLayout")) {
26574
26532
  return {
26575
26533
  id: "layout.sitekit",
@@ -26601,8 +26559,8 @@ async function checkSiteKitLayout(cwd) {
26601
26559
  };
26602
26560
  }
26603
26561
  async function checkSitemap(cwd) {
26604
- const sitemapPath = await findFirst(cwd, SITEMAP_CANDIDATES);
26605
- if (!sitemapPath) {
26562
+ const sitemapRel = findSitemapRoute(cwd);
26563
+ if (!sitemapRel) {
26606
26564
  return {
26607
26565
  id: "sitemap.managed",
26608
26566
  title: "Sitemap",
@@ -26612,7 +26570,7 @@ async function checkSitemap(cwd) {
26612
26570
  fixCommand: "npx sonor-setup scaffold --yes"
26613
26571
  };
26614
26572
  }
26615
- const content = await readFileOrNull(sitemapPath) || "";
26573
+ const content = await readFileOrNull(path12.join(cwd, sitemapRel)) || "";
26616
26574
  if (content.includes("createSitemap") || content.includes("@sonordev/site-kit")) {
26617
26575
  return { id: "sitemap.managed", title: "Sitemap", level: "ok", message: "Using Site-Kit sitemap" };
26618
26576
  }
@@ -26625,7 +26583,7 @@ async function checkSitemap(cwd) {
26625
26583
  };
26626
26584
  }
26627
26585
  async function checkPostbuildSitemap(cwd) {
26628
- const raw = await readFileOrNull(path10.join(cwd, "package.json"));
26586
+ const raw = await readFileOrNull(path12.join(cwd, "package.json"));
26629
26587
  let pkg = {};
26630
26588
  try {
26631
26589
  pkg = raw ? JSON.parse(raw) : {};
@@ -26662,18 +26620,18 @@ async function checkPostbuildSitemap(cwd) {
26662
26620
  async function checkApiReachable(timeoutMs = 5e3) {
26663
26621
  const key = process.env.SONOR_API_KEY;
26664
26622
  try {
26665
- const res = await fetch(`${API_URL4}/health`, {
26623
+ const res = await fetch(`${API_URL}/health`, {
26666
26624
  headers: key ? { "x-api-key": key } : {},
26667
26625
  signal: AbortSignal.timeout(timeoutMs)
26668
26626
  });
26669
26627
  if (res.ok) {
26670
- return { id: "api.reachable", title: "Sonor API", level: "ok", message: `Reachable (${API_URL4})` };
26628
+ return { id: "api.reachable", title: "Sonor API", level: "ok", message: `Reachable (${API_URL})` };
26671
26629
  }
26672
26630
  return {
26673
26631
  id: "api.reachable",
26674
26632
  title: "Sonor API",
26675
26633
  level: "warn",
26676
- message: `HTTP ${res.status} from ${API_URL4}`
26634
+ message: `HTTP ${res.status} from ${API_URL}`
26677
26635
  };
26678
26636
  } catch (err) {
26679
26637
  return {
@@ -26698,7 +26656,7 @@ async function checkKeyValid(timeoutMs = 8e3) {
26698
26656
  };
26699
26657
  }
26700
26658
  try {
26701
- const res = await fetch(`${API_URL4}/api/public/seo/verify-api-key`, {
26659
+ const res = await fetch(`${API_URL}/api/public/seo/verify-api-key`, {
26702
26660
  headers: { "x-api-key": key },
26703
26661
  signal: AbortSignal.timeout(timeoutMs)
26704
26662
  });
@@ -26801,7 +26759,7 @@ async function checkClientAuth(timeoutMs = 8e3) {
26801
26759
  }
26802
26760
  const qs2 = host ? `?host=${encodeURIComponent(host)}` : "";
26803
26761
  try {
26804
- const res = await fetch(`${API_URL4}/api/public/site-token/status${qs2}`, {
26762
+ const res = await fetch(`${API_URL}/api/public/site-token/status${qs2}`, {
26805
26763
  headers: { "x-api-key": key },
26806
26764
  signal: AbortSignal.timeout(timeoutMs)
26807
26765
  });
@@ -26946,7 +26904,7 @@ async function checkSsrRenderFromUrl(url, timeoutMs = 12e3) {
26946
26904
  }
26947
26905
  }
26948
26906
  async function checkSsrRenderFromBuild(cwd) {
26949
- const appDir = path10.join(cwd, ".next", "server", "app");
26907
+ const appDir = path12.join(cwd, ".next", "server", "app");
26950
26908
  let entries;
26951
26909
  try {
26952
26910
  entries = await fs3.readdir(appDir);
@@ -26969,7 +26927,7 @@ async function checkSsrRenderFromBuild(cwd) {
26969
26927
  detail: "The root route may be fully dynamic. Pass --url to verify a running instance."
26970
26928
  };
26971
26929
  }
26972
- const html = await readFileOrNull(path10.join(appDir, htmlName)) || "";
26930
+ const html = await readFileOrNull(path12.join(appDir, htmlName)) || "";
26973
26931
  const { rendered, contentTags } = looksServerRendered(html);
26974
26932
  if (rendered) {
26975
26933
  return {
@@ -26990,9 +26948,8 @@ async function checkSsrRenderFromBuild(cwd) {
26990
26948
  }
26991
26949
  async function checkNetlifyMiddleware(cwd) {
26992
26950
  const runtimeRe = /runtime\s*[:=]\s*['"](nodejs|edge)['"]/;
26993
- const proxyFiles = ["proxy.ts", "proxy.js", "src/proxy.ts", "src/proxy.js"];
26994
- for (const rel of proxyFiles) {
26995
- const content = await readFileOrNull(path10.join(cwd, rel));
26951
+ for (const rel of NEXT_PROXY_FILES) {
26952
+ const content = await readFileOrNull(path12.join(cwd, rel));
26996
26953
  if (content === null) continue;
26997
26954
  if (runtimeRe.test(content)) {
26998
26955
  return {
@@ -27007,9 +26964,8 @@ async function checkNetlifyMiddleware(cwd) {
27007
26964
  }
27008
26965
  return { id: "middleware.netlify", title: "Proxy / middleware", level: "ok", message: `${rel} present` };
27009
26966
  }
27010
- const middlewareFiles = ["middleware.ts", "middleware.js", "src/middleware.ts", "src/middleware.js"];
27011
- for (const rel of middlewareFiles) {
27012
- const content = await readFileOrNull(path10.join(cwd, rel));
26967
+ for (const rel of NEXT_MIDDLEWARE_FILES) {
26968
+ const content = await readFileOrNull(path12.join(cwd, rel));
27013
26969
  if (content === null) continue;
27014
26970
  if (/runtime\s*[:=]\s*['"]nodejs['"]/.test(content)) {
27015
26971
  return {
@@ -27036,7 +26992,7 @@ async function checkNetlifyMiddleware(cwd) {
27036
26992
  }
27037
26993
  async function checkImageDimsDrift(cwd) {
27038
26994
  const scanRoots = ["app", "src/app", "components", "src/components"];
27039
- const publicDir = path10.join(cwd, "public");
26995
+ const publicDir = path12.join(cwd, "public");
27040
26996
  const files = [];
27041
26997
  async function walk(dir, depth) {
27042
26998
  if (depth > 4) return;
@@ -27048,19 +27004,19 @@ async function checkImageDimsDrift(cwd) {
27048
27004
  }
27049
27005
  for (const e of entries) {
27050
27006
  if (e.name === "node_modules" || e.name.startsWith(".")) continue;
27051
- const full = path10.join(dir, e.name);
27007
+ const full = path12.join(dir, e.name);
27052
27008
  if (e.isDirectory()) await walk(full, depth + 1);
27053
27009
  else if (/\.(tsx|jsx)$/.test(e.name)) files.push(full);
27054
27010
  }
27055
27011
  }
27056
- for (const root of scanRoots) await walk(path10.join(cwd, root), 0);
27012
+ for (const root of scanRoots) await walk(path12.join(cwd, root), 0);
27057
27013
  if (files.length === 0) {
27058
27014
  return { id: "images.dims-drift", title: "Image dims vs SVG", level: "skip", message: "No component files found" };
27059
27015
  }
27060
27016
  const viewBoxCache = /* @__PURE__ */ new Map();
27061
27017
  async function svgAspect(publicPath) {
27062
27018
  if (viewBoxCache.has(publicPath)) return viewBoxCache.get(publicPath);
27063
- const svg = await readFileOrNull(path10.join(publicDir, publicPath.replace(/^\//, "")));
27019
+ const svg = await readFileOrNull(path12.join(publicDir, publicPath.replace(/^\//, "")));
27064
27020
  let aspect = null;
27065
27021
  if (svg) {
27066
27022
  const vb = svg.match(/viewBox="([\d.\s-]+)"/);
@@ -27087,7 +27043,7 @@ async function checkImageDimsDrift(cwd) {
27087
27043
  const drift = Math.abs(declared - actual) / actual;
27088
27044
  if (drift > 0.02) {
27089
27045
  drifts.push(
27090
- `${path10.relative(cwd, file)}: ${src} is ${actual.toFixed(2)}:1 but width/height declare ${declared.toFixed(2)}:1 (${Math.round(drift * 100)}% off)`
27046
+ `${path12.relative(cwd, file)}: ${src} is ${actual.toFixed(2)}:1 but width/height declare ${declared.toFixed(2)}:1 (${Math.round(drift * 100)}% off)`
27091
27047
  );
27092
27048
  }
27093
27049
  }
@@ -27203,8 +27159,8 @@ async function statusCommand(options) {
27203
27159
 
27204
27160
  // src/og/pages.ts
27205
27161
  var DYNAMIC = "*";
27206
- function pathSegments(path27) {
27207
- return path27.split("/").filter(Boolean);
27162
+ function pathSegments(path30) {
27163
+ return path30.split("/").filter(Boolean);
27208
27164
  }
27209
27165
  function stripBrandSuffix(title, brand) {
27210
27166
  const cleaned = title.replace(/\s*[|–—-]\s*[^|–—-]+$/, "").trim();
@@ -27212,13 +27168,13 @@ function stripBrandSuffix(title, brand) {
27212
27168
  if (brand && cleaned.toLowerCase() === brand.toLowerCase()) return title.trim();
27213
27169
  return cleaned;
27214
27170
  }
27215
- function titleFromPath(path27) {
27216
- const last = pathSegments(path27).filter((s) => s !== DYNAMIC).pop();
27171
+ function titleFromPath(path30) {
27172
+ const last = pathSegments(path30).filter((s) => s !== DYNAMIC).pop();
27217
27173
  if (!last) return "Home";
27218
27174
  return last.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
27219
27175
  }
27220
- function kickerFromPath(path27, fallback) {
27221
- const parts = pathSegments(path27);
27176
+ function kickerFromPath(path30, fallback) {
27177
+ const parts = pathSegments(path30);
27222
27178
  const section = parts.includes(DYNAMIC) ? parts.filter((s) => s !== DYNAMIC) : parts.slice(0, -1);
27223
27179
  if (!section.length) return fallback;
27224
27180
  return section.join(" / ").replace(/[-_]+/g, " ");
@@ -27242,8 +27198,8 @@ function kickerIsRedundant(kicker, title) {
27242
27198
  const titleWords = new Set(t.split(" "));
27243
27199
  return k2.split(" ").every((w) => titleWords.has(w));
27244
27200
  }
27245
- function slugForPath(path27) {
27246
- const segments = pathSegments(path27);
27201
+ function slugForPath(path30) {
27202
+ const segments = pathSegments(path30);
27247
27203
  if (!segments.length) return "home";
27248
27204
  return segments.map((s) => s === DYNAMIC ? "any" : s).join("-").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
27249
27205
  }
@@ -27297,10 +27253,10 @@ function findChrome() {
27297
27253
  }
27298
27254
  return null;
27299
27255
  }
27300
- async function loadConfig4(cwd) {
27256
+ async function loadConfig2(cwd) {
27301
27257
  const candidates = ["og.config.ts", "og.config.mts", "og.config.mjs", "og.config.js"];
27302
27258
  for (const rel of candidates) {
27303
- const full = path10.join(cwd, rel);
27259
+ const full = path12.join(cwd, rel);
27304
27260
  if (!existsSync(full)) continue;
27305
27261
  try {
27306
27262
  const mod = await import(
@@ -27325,7 +27281,7 @@ async function loadConfig4(cwd) {
27325
27281
  return null;
27326
27282
  }
27327
27283
  async function seedConfig(cwd) {
27328
- let name = path10.basename(cwd).replace(/-nextjs$/, "").replace(/-/g, " ");
27284
+ let name = path12.basename(cwd).replace(/-nextjs$/, "").replace(/-/g, " ");
27329
27285
  let accent = "#111111";
27330
27286
  let logo;
27331
27287
  try {
@@ -27338,7 +27294,7 @@ async function seedConfig(cwd) {
27338
27294
  } catch {
27339
27295
  }
27340
27296
  for (const candidate of ["/logo-mark.svg", "/logo.svg", "/logohorizontal.svg"]) {
27341
- if (existsSync(path10.join(cwd, "public", candidate))) {
27297
+ if (existsSync(path12.join(cwd, "public", candidate))) {
27342
27298
  logo = candidate;
27343
27299
  break;
27344
27300
  }
@@ -27352,14 +27308,14 @@ async function seedConfig(cwd) {
27352
27308
  }
27353
27309
  function inlinePublicPaths(html, cwd) {
27354
27310
  return html.replace(/src="(\/[^"]+)"/g, (_3, p) => {
27355
- const full = path10.join(cwd, "public", p);
27311
+ const full = path12.join(cwd, "public", p);
27356
27312
  return existsSync(full) ? `src="file://${full}"` : `src="${p}"`;
27357
27313
  });
27358
27314
  }
27359
27315
  async function renderCard(config2, outPath, cwd, chrome, tmpSuffix) {
27360
- const tmpHtml = path10.join(cwd, `.sonor-og-${tmpSuffix}.html`);
27316
+ const tmpHtml = path12.join(cwd, `.sonor-og-${tmpSuffix}.html`);
27361
27317
  try {
27362
- await fs3.mkdir(path10.dirname(outPath), { recursive: true });
27318
+ await fs3.mkdir(path12.dirname(outPath), { recursive: true });
27363
27319
  await fs3.writeFile(tmpHtml, inlinePublicPaths(buildOgHtml(config2), cwd));
27364
27320
  const { stdout } = await execFileAsync5(
27365
27321
  chrome,
@@ -27394,7 +27350,7 @@ function parseReport(dom) {
27394
27350
  }
27395
27351
  async function compressCard(pngPath, cwd) {
27396
27352
  try {
27397
- const require_ = (await import('module')).createRequire(path10.join(cwd, "package.json"));
27353
+ const require_ = (await import('module')).createRequire(path12.join(cwd, "package.json"));
27398
27354
  const sharp = require_("sharp");
27399
27355
  const jpgPath = pngPath.replace(/\.png$/, ".jpg");
27400
27356
  await sharp(pngPath).jpeg({ quality: 84, mozjpeg: true }).toFile(jpgPath);
@@ -27404,6 +27360,9 @@ async function compressCard(pngPath, cwd) {
27404
27360
  return pngPath;
27405
27361
  }
27406
27362
  }
27363
+ function codeOgImageFile(dir) {
27364
+ return findConventionFile(dir, "opengraph-image");
27365
+ }
27407
27366
  function discoverDynamicSegments(appDir) {
27408
27367
  const found = [];
27409
27368
  const walk = (dir, urlSegments, pattern) => {
@@ -27411,14 +27370,13 @@ function discoverDynamicSegments(appDir) {
27411
27370
  if (!entry.isDirectory()) continue;
27412
27371
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
27413
27372
  if (entry.name === "api" || entry.name === "node_modules") continue;
27414
- const full = path10.join(dir, entry.name);
27373
+ const full = path12.join(dir, entry.name);
27415
27374
  const isGroup = entry.name.startsWith("(") && entry.name.endsWith(")");
27416
27375
  const isDynamic = entry.name.startsWith("[") && entry.name.endsWith("]");
27417
27376
  const nextUrl = isGroup || isDynamic ? urlSegments : [...urlSegments, entry.name];
27418
27377
  const nextPattern = isGroup ? pattern : [...pattern, isDynamic ? DYNAMIC : entry.name];
27419
27378
  if (isDynamic) {
27420
- const hasPage = ["tsx", "jsx", "ts", "js"].some((ext2) => existsSync(path10.join(full, `page.${ext2}`)));
27421
- if (hasPage) {
27379
+ if (hasPageFile(full)) {
27422
27380
  found.push({ dir: full, path: `/${nextPattern.join("/")}`, parent: `/${urlSegments.join("/")}` });
27423
27381
  }
27424
27382
  }
@@ -27493,7 +27451,7 @@ async function runOg(options) {
27493
27451
  errors: [{ code: "chrome_missing", message: "No Chrome or Chromium binary found", fix: "Install Chrome, or set SONOR_CHROME_PATH to its path." }]
27494
27452
  };
27495
27453
  }
27496
- let config2 = await loadConfig4(cwd);
27454
+ let config2 = await loadConfig2(cwd);
27497
27455
  let seeded = false;
27498
27456
  if (!config2) {
27499
27457
  config2 = await seedConfig(cwd);
@@ -27501,7 +27459,7 @@ async function runOg(options) {
27501
27459
  console.log(source_default.yellow(" ! No og.config.ts \u2014 generating a seed card from Sonor brand data."));
27502
27460
  console.log(source_default.gray(" The site owns its theme: add og.config.ts (defineOgCard) with the real palette."));
27503
27461
  }
27504
- const outPath = path10.resolve(cwd, options.out || "public/og.png");
27462
+ const outPath = path12.resolve(cwd, options.out || "public/og.png");
27505
27463
  let clean = true;
27506
27464
  let cardKeyFix = null;
27507
27465
  let pageCardsWritten = 0;
@@ -27511,8 +27469,8 @@ async function runOg(options) {
27511
27469
  const report = await renderCard(config2, outPath, cwd, chrome, "site");
27512
27470
  spinner.stop();
27513
27471
  console.log(source_default.bold(` Site card${seeded ? source_default.gray(" (seed)") : ""}`));
27514
- clean = reportCard(`${path10.relative(cwd, outPath)} \u2014 1200x630`, report) && clean;
27515
- checks.push(cardCheck("site card", path10.relative(cwd, outPath), report));
27472
+ clean = reportCard(`${path12.relative(cwd, outPath)} \u2014 1200x630`, report) && clean;
27473
+ checks.push(cardCheck("site card", path12.relative(cwd, outPath), report));
27516
27474
  } catch (err) {
27517
27475
  const message = err instanceof Error ? err.message.split("\n")[0] : String(err);
27518
27476
  spinner.fail(`Render failed: ${message}`);
@@ -27571,20 +27529,30 @@ async function runOg(options) {
27571
27529
  });
27572
27530
  cardKeyFix = CARD_KEY_FIX;
27573
27531
  }
27574
- const reports = await pooled(targets, RENDER_CONCURRENCY, async (route, i) => {
27532
+ const placed = targets.map((route) => ({ ...route, dir: route.dir ?? routeOutputDir(appDir, route.path) }));
27533
+ const toRender = placed.filter((route) => !codeOgImageFile(route.dir));
27534
+ for (const route of placed.filter((r) => codeOgImageFile(r.dir))) {
27535
+ for (const ext2 of ["png", "jpg", "jpeg"]) {
27536
+ await fs3.rm(path12.join(route.dir, `opengraph-image.${ext2}`), { force: true });
27537
+ }
27538
+ const file = path12.relative(cwd, codeOgImageFile(route.dir));
27539
+ console.log(source_default.gray(` \u21B7 ${route.path} keeps its own ${file}`));
27540
+ checks.push({ id: "og.code-card", title: route.path, level: "ok", message: `Code-based card kept: ${file}` });
27541
+ }
27542
+ const reports = await pooled(toRender, RENDER_CONCURRENCY, async (route, i) => {
27575
27543
  const pageConfig = pageCardConfig(config2, route, brand);
27576
- const dir = route.dir ?? routeOutputDir(appDir, route.path);
27544
+ const dir = route.dir;
27577
27545
  for (const ext2 of ["png", "jpg", "jpeg"]) {
27578
- await fs3.rm(path10.join(dir, `opengraph-image.${ext2}`), { force: true });
27546
+ await fs3.rm(path12.join(dir, `opengraph-image.${ext2}`), { force: true });
27579
27547
  }
27580
- const png = path10.join(dir, "opengraph-image.png");
27548
+ const png = path12.join(dir, "opengraph-image.png");
27581
27549
  const report = await renderCard(pageConfig, png, cwd, chrome, `page-${i}`);
27582
27550
  const file = await compressCard(png, cwd);
27583
27551
  return { route, file, report };
27584
27552
  });
27585
27553
  for (const { route, file, report } of reports) {
27586
- clean = reportCard(`${route.path} ${source_default.gray(path10.relative(cwd, file))}`, report) && clean;
27587
- checks.push(cardCheck(route.path, path10.relative(cwd, file), report));
27554
+ clean = reportCard(`${route.path} ${source_default.gray(path12.relative(cwd, file))}`, report) && clean;
27555
+ checks.push(cardCheck(route.path, path12.relative(cwd, file), report));
27588
27556
  }
27589
27557
  pageCardsWritten = reports.length;
27590
27558
  const bytes = await totalBytes(reports.map((r) => r.file));
@@ -27595,13 +27563,13 @@ async function runOg(options) {
27595
27563
  }
27596
27564
  if (options.preview !== false) {
27597
27565
  try {
27598
- const require_ = (await import('module')).createRequire(path10.join(cwd, "package.json"));
27566
+ const require_ = (await import('module')).createRequire(path12.join(cwd, "package.json"));
27599
27567
  const sharp = require_("sharp");
27600
- const previewPath = path10.join(cwd, ".sonor", "og-preview.png");
27601
- await fs3.mkdir(path10.dirname(previewPath), { recursive: true });
27568
+ const previewPath = path12.join(cwd, ".sonor", "og-preview.png");
27569
+ await fs3.mkdir(path12.dirname(previewPath), { recursive: true });
27602
27570
  await sharp(outPath).resize(300).toFile(previewPath);
27603
27571
  console.log("");
27604
- console.log(source_default.gray(` Thumbnail check: ${path10.relative(cwd, previewPath)} \u2014 if text is mush there, fix the card.`));
27572
+ console.log(source_default.gray(` Thumbnail check: ${path12.relative(cwd, previewPath)} \u2014 if text is mush there, fix the card.`));
27605
27573
  } catch {
27606
27574
  console.log(source_default.gray(" (sharp not resolvable \u2014 skipped the 300px preview)"));
27607
27575
  }
@@ -27660,15 +27628,15 @@ function routeOutputDir(appDir, urlPath) {
27660
27628
  const segments = urlPath.split("/").filter(Boolean);
27661
27629
  let dir = appDir;
27662
27630
  for (const segment of segments) {
27663
- const direct = path10.join(dir, segment);
27631
+ const direct = path12.join(dir, segment);
27664
27632
  if (existsSync(direct)) {
27665
27633
  dir = direct;
27666
27634
  continue;
27667
27635
  }
27668
27636
  const group = existsSync(dir) ? readdirSync(dir, { withFileTypes: true }).find(
27669
- (e) => e.isDirectory() && e.name.startsWith("(") && e.name.endsWith(")") && existsSync(path10.join(dir, e.name, segment))
27637
+ (e) => e.isDirectory() && e.name.startsWith("(") && e.name.endsWith(")") && existsSync(path12.join(dir, e.name, segment))
27670
27638
  ) : void 0;
27671
- dir = group ? path10.join(dir, group.name, segment) : direct;
27639
+ dir = group ? path12.join(dir, group.name, segment) : direct;
27672
27640
  }
27673
27641
  return dir;
27674
27642
  }
@@ -27683,7 +27651,7 @@ async function totalBytes(files) {
27683
27651
  return total;
27684
27652
  }
27685
27653
  async function siteDomain(cwd) {
27686
- const envFile = path10.join(cwd, ".env.local");
27654
+ const envFile = path12.join(cwd, ".env.local");
27687
27655
  if (existsSync(envFile)) {
27688
27656
  const env3 = await fs3.readFile(envFile, "utf-8").catch(() => "");
27689
27657
  const url = env3.match(/^NEXT_PUBLIC_SITE_URL=(.+)$/m)?.[1]?.trim();
@@ -27808,14 +27776,14 @@ var hs = new RegExp(pe, "g");
27808
27776
  var as = /\\\\/g;
27809
27777
  var ls = /\\{/g;
27810
27778
  var cs = /\\}/g;
27811
- var fs20 = /\\,/g;
27779
+ var fs22 = /\\,/g;
27812
27780
  var us = /\\./g;
27813
27781
  var ds = 1e5;
27814
27782
  function Ht(n5) {
27815
27783
  return isNaN(n5) ? n5.charCodeAt(0) : parseInt(n5, 10);
27816
27784
  }
27817
27785
  function ps(n5) {
27818
- return n5.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs20, de).replace(us, pe);
27786
+ return n5.replace(as, fe).replace(ls, ue).replace(cs, qt).replace(fs22, de).replace(us, pe);
27819
27787
  }
27820
27788
  function ms(n5) {
27821
27789
  return n5.replace(is, "\\").replace(rs, "{").replace(ns, "}").replace(os5, ",").replace(hs, ".");
@@ -30847,10 +30815,10 @@ function unifiedDiff(before, after, filePath, context = 2) {
30847
30815
  return lines.join("\n");
30848
30816
  }
30849
30817
  function ext(filePath) {
30850
- return path10.extname(filePath).toLowerCase();
30818
+ return path12.extname(filePath).toLowerCase();
30851
30819
  }
30852
30820
  function basename(filePath) {
30853
- return path10.basename(filePath).toLowerCase();
30821
+ return path12.basename(filePath).toLowerCase();
30854
30822
  }
30855
30823
  var CODE_EXT = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
30856
30824
  var TEXT_EXT = /* @__PURE__ */ new Set([...CODE_EXT, ".css", ".scss", ".json", ".md", ".mdx"]);
@@ -31004,7 +30972,7 @@ var IGNORE = [
31004
30972
  ];
31005
30973
  async function listFiles(cwd, onlyPath) {
31006
30974
  if (onlyPath) {
31007
- const rel = path10.isAbsolute(onlyPath) ? path10.relative(cwd, onlyPath) : onlyPath;
30975
+ const rel = path12.isAbsolute(onlyPath) ? path12.relative(cwd, onlyPath) : onlyPath;
31008
30976
  return [rel];
31009
30977
  }
31010
30978
  const matches = await Ze(SCAN_PATTERNS, { cwd, ignore: IGNORE, dot: true, nodir: true });
@@ -31016,7 +30984,7 @@ async function runCodemod(options) {
31016
30984
  const files = await listFiles(cwd, onlyPath);
31017
30985
  const changes = [];
31018
30986
  for (const rel of files) {
31019
- const full = path10.join(cwd, rel);
30987
+ const full = path12.join(cwd, rel);
31020
30988
  let source;
31021
30989
  try {
31022
30990
  source = await fs3.readFile(full, "utf-8");
@@ -31165,9 +31133,9 @@ function findManifestPath() {
31165
31133
  const baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
31166
31134
  let dir = baseDir;
31167
31135
  for (let i = 0; i < 8; i++) {
31168
- const candidate = path10.join(dir, "agent-manifest.json");
31136
+ const candidate = path12.join(dir, "agent-manifest.json");
31169
31137
  if (fs__default.existsSync(candidate)) return candidate;
31170
- const parent = path10.dirname(dir);
31138
+ const parent = path12.dirname(dir);
31171
31139
  if (parent === dir) break;
31172
31140
  dir = parent;
31173
31141
  }
@@ -31246,7 +31214,7 @@ async function syncCommand2(options) {
31246
31214
  }
31247
31215
  async function syncPagesToPortal(apiUrl, apiKey, dryRun) {
31248
31216
  const spinner = ora("Discovering pages...").start();
31249
- const appDir = findAppDir();
31217
+ const appDir = findAppDirForDiscovery();
31250
31218
  if (!appDir) {
31251
31219
  spinner.fail("Could not find app directory");
31252
31220
  return;
@@ -31307,20 +31275,8 @@ async function syncPagesToPortal(apiUrl, apiKey, dryRun) {
31307
31275
  syncSpinner.fail(`Sync failed: ${error2.message}`);
31308
31276
  }
31309
31277
  }
31310
- function findAppDir() {
31311
- const candidates = [
31312
- path10.join(process.cwd(), "app"),
31313
- path10.join(process.cwd(), "src", "app")
31314
- ];
31315
- for (const candidate of candidates) {
31316
- if (existsSync(candidate)) {
31317
- return candidate;
31318
- }
31319
- }
31320
- return null;
31321
- }
31322
31278
  function discoverPages(appDir, currentPath = "", pages = []) {
31323
- const fullPath = path10.join(appDir, currentPath);
31279
+ const fullPath = path12.join(appDir, currentPath);
31324
31280
  if (!existsSync(fullPath)) {
31325
31281
  return pages;
31326
31282
  }
@@ -31342,7 +31298,7 @@ function discoverPages(appDir, currentPath = "", pages = []) {
31342
31298
  });
31343
31299
  }
31344
31300
  for (const entry of entries) {
31345
- const entryPath = path10.join(fullPath, entry);
31301
+ const entryPath = path12.join(fullPath, entry);
31346
31302
  const stat = statSync(entryPath);
31347
31303
  if (stat.isDirectory()) {
31348
31304
  const folderName = entry.toLowerCase();
@@ -31355,21 +31311,21 @@ function discoverPages(appDir, currentPath = "", pages = []) {
31355
31311
  if (entry.startsWith("_")) {
31356
31312
  continue;
31357
31313
  }
31358
- discoverPages(appDir, path10.join(currentPath, entry), pages);
31314
+ discoverPages(appDir, path12.join(currentPath, entry), pages);
31359
31315
  }
31360
31316
  }
31361
31317
  return pages;
31362
31318
  }
31363
31319
  function findNextBuildDir() {
31364
31320
  const cwd = process.cwd();
31365
- const candidate = path10.join(cwd, ".next", "server", "app");
31321
+ const candidate = path12.join(cwd, ".next", "server", "app");
31366
31322
  return existsSync(candidate) ? candidate : null;
31367
31323
  }
31368
31324
  function extractPageContent(buildDir, pagePath) {
31369
31325
  const baseName = pagePath === "/" ? "index" : pagePath.replace(/^\//, "");
31370
31326
  const htmlCandidates = [
31371
- path10.join(buildDir, `${baseName}.html`),
31372
- path10.join(buildDir, baseName, "index.html")
31327
+ path12.join(buildDir, `${baseName}.html`),
31328
+ path12.join(buildDir, baseName, "index.html")
31373
31329
  ];
31374
31330
  let html = null;
31375
31331
  for (const candidate of htmlCandidates) {
@@ -31383,8 +31339,8 @@ function extractPageContent(buildDir, pagePath) {
31383
31339
  }
31384
31340
  }
31385
31341
  const rscCandidates = [
31386
- path10.join(buildDir, `${baseName}.rsc`),
31387
- path10.join(buildDir, baseName, "index.rsc")
31342
+ path12.join(buildDir, `${baseName}.rsc`),
31343
+ path12.join(buildDir, baseName, "index.rsc")
31388
31344
  ];
31389
31345
  let rsc = null;
31390
31346
  for (const candidate of rscCandidates) {
@@ -31495,7 +31451,7 @@ var BLOG_EXTENSIONS = [".mdx", ".md"];
31495
31451
  function findBlogDir() {
31496
31452
  const cwd = process.cwd();
31497
31453
  for (const dir of BLOG_DIRS) {
31498
- const full = path10.join(cwd, dir);
31454
+ const full = path12.join(cwd, dir);
31499
31455
  if (existsSync(full)) return full;
31500
31456
  }
31501
31457
  return null;
@@ -31505,7 +31461,7 @@ async function discoverBlogPosts(dir) {
31505
31461
  async function walk(currentDir) {
31506
31462
  const entries = readdirSync(currentDir);
31507
31463
  for (const entry of entries) {
31508
- const fullPath = path10.join(currentDir, entry);
31464
+ const fullPath = path12.join(currentDir, entry);
31509
31465
  const stat = statSync(fullPath);
31510
31466
  if (stat.isDirectory()) {
31511
31467
  await walk(fullPath);
@@ -31522,7 +31478,7 @@ async function discoverBlogPosts(dir) {
31522
31478
  date: frontmatter.date,
31523
31479
  tags: frontmatter.tags,
31524
31480
  author: frontmatter.author,
31525
- filePath: path10.relative(process.cwd(), fullPath)
31481
+ filePath: path12.relative(process.cwd(), fullPath)
31526
31482
  });
31527
31483
  }
31528
31484
  }
@@ -31555,7 +31511,7 @@ async function syncBlogToPortal(_apiUrl, _apiKey, _dryRun) {
31555
31511
  }
31556
31512
  const spinner = ora("Discovering blog posts...").start();
31557
31513
  const posts = await discoverBlogPosts(blogDir);
31558
- spinner.succeed(`Found ${posts.length} local markdown post(s) in ${path10.relative(process.cwd(), blogDir)}`);
31514
+ spinner.succeed(`Found ${posts.length} local markdown post(s) in ${path12.relative(process.cwd(), blogDir)}`);
31559
31515
  if (posts.length === 0) return;
31560
31516
  for (const post of posts.slice(0, 10)) {
31561
31517
  console.log(source_default.gray(` ${post.slug}: ${post.title || "(no title)"}`));
@@ -31572,11 +31528,11 @@ async function discoverSchemaUsage(appDir) {
31572
31528
  async function walk(currentDir, currentPath = "") {
31573
31529
  const entries = readdirSync(currentDir);
31574
31530
  for (const entry of entries) {
31575
- const fullPath = path10.join(currentDir, entry);
31531
+ const fullPath = path12.join(currentDir, entry);
31576
31532
  const stat = statSync(fullPath);
31577
31533
  if (stat.isDirectory()) {
31578
31534
  if (entry.startsWith(".") || entry === "node_modules") continue;
31579
- await walk(fullPath, path10.join(currentPath, entry));
31535
+ await walk(fullPath, path12.join(currentPath, entry));
31580
31536
  continue;
31581
31537
  }
31582
31538
  if (!/\.(tsx?|jsx?)$/.test(entry)) continue;
@@ -31590,7 +31546,7 @@ async function discoverSchemaUsage(appDir) {
31590
31546
  pagePath: pathMatch[1],
31591
31547
  schemaTypes: ["managed"],
31592
31548
  source: "ManagedSchema",
31593
- filePath: path10.relative(process.cwd(), fullPath)
31549
+ filePath: path12.relative(process.cwd(), fullPath)
31594
31550
  });
31595
31551
  }
31596
31552
  }
@@ -31608,7 +31564,7 @@ async function discoverSchemaUsage(appDir) {
31608
31564
  pagePath,
31609
31565
  schemaTypes: [...new Set(types)],
31610
31566
  source: "json-ld",
31611
- filePath: path10.relative(process.cwd(), fullPath)
31567
+ filePath: path12.relative(process.cwd(), fullPath)
31612
31568
  });
31613
31569
  }
31614
31570
  }
@@ -31618,7 +31574,7 @@ async function discoverSchemaUsage(appDir) {
31618
31574
  return usages;
31619
31575
  }
31620
31576
  async function syncSchemasToPortal(apiUrl, apiKey, dryRun) {
31621
- const appDir = findAppDir();
31577
+ const appDir = findAppDirForDiscovery();
31622
31578
  if (!appDir) {
31623
31579
  console.log(source_default.gray(" No app directory found"));
31624
31580
  return;
@@ -31661,15 +31617,15 @@ async function apiRoutesCommand(options) {
31661
31617
  console.log("");
31662
31618
  console.log(source_default.bold(" Site-Kit API Routes"));
31663
31619
  console.log("");
31664
- const appDir = findAppDir2();
31620
+ const appDir = findAppDirForDiscovery();
31665
31621
  if (!appDir) {
31666
31622
  console.log(source_default.red(" \u2717 Could not find app directory"));
31667
31623
  console.log(source_default.gray(" Make sure you are in a Next.js project with an app directory"));
31668
31624
  console.log("");
31669
31625
  process.exit(1);
31670
31626
  }
31671
- const routeDir = path10.join(appDir, "_uptrade", "api", "[...path]");
31672
- const routeFile = path10.join(routeDir, "route.ts");
31627
+ const routeDir = path12.join(appDir, "_uptrade", "api", "[...path]");
31628
+ const routeFile = path12.join(routeDir, "route.ts");
31673
31629
  if (existsSync(routeFile) && !options.force) {
31674
31630
  console.log(source_default.yellow(" \u26A0 API routes already exist"));
31675
31631
  console.log(source_default.gray(` ${routeFile}`));
@@ -31704,18 +31660,6 @@ async function apiRoutesCommand(options) {
31704
31660
  spinner.fail(`Failed to create API routes: ${error2.message}`);
31705
31661
  }
31706
31662
  }
31707
- function findAppDir2() {
31708
- const candidates = [
31709
- path10.join(process.cwd(), "app"),
31710
- path10.join(process.cwd(), "src", "app")
31711
- ];
31712
- for (const candidate of candidates) {
31713
- if (existsSync(candidate)) {
31714
- return candidate;
31715
- }
31716
- }
31717
- return null;
31718
- }
31719
31663
  function generateRouteHandler() {
31720
31664
  return `/**
31721
31665
  * Sonor API Proxy
@@ -31820,12 +31764,12 @@ async function handleRequest(
31820
31764
  `;
31821
31765
  }
31822
31766
  function detectPackageManager(cwd) {
31823
- if (existsSync(path10.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
31824
- if (existsSync(path10.join(cwd, "yarn.lock"))) return "yarn";
31767
+ if (existsSync(path12.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
31768
+ if (existsSync(path12.join(cwd, "yarn.lock"))) return "yarn";
31825
31769
  return "npm";
31826
31770
  }
31827
31771
  async function run6(ctx, options) {
31828
- if (!existsSync(path10.join(ctx.cwd, "package.json"))) {
31772
+ if (!existsSync(path12.join(ctx.cwd, "package.json"))) {
31829
31773
  throw new UsageError(
31830
31774
  "NO_PACKAGE_JSON",
31831
31775
  "No package.json found",
@@ -31870,12 +31814,12 @@ async function installCommand(options) {
31870
31814
  await runCommand(ctx, (c) => run6(c, options), renderHuman4);
31871
31815
  }
31872
31816
  function detectPackageManager2(cwd) {
31873
- if (existsSync(path10.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
31874
- if (existsSync(path10.join(cwd, "yarn.lock"))) return "yarn";
31817
+ if (existsSync(path12.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
31818
+ if (existsSync(path12.join(cwd, "yarn.lock"))) return "yarn";
31875
31819
  return "npm";
31876
31820
  }
31877
31821
  async function run7(ctx, options) {
31878
- const pkgPath = path10.join(ctx.cwd, "package.json");
31822
+ const pkgPath = path12.join(ctx.cwd, "package.json");
31879
31823
  if (!existsSync(pkgPath)) {
31880
31824
  throw new UsageError("NO_PACKAGE_JSON", "No package.json found", "Run this from your project root.");
31881
31825
  }
@@ -31930,21 +31874,21 @@ async function scaffoldCommand(options) {
31930
31874
  );
31931
31875
  console.log("");
31932
31876
  const cwd = process.cwd();
31933
- const appDir = await findAppDir3();
31877
+ const appDir = findAppDirForDiscovery(cwd);
31934
31878
  if (!appDir) {
31935
31879
  console.log(source_default.red(" \u2717 No app directory found (app/ or src/app/)"));
31936
31880
  process.exit(1);
31937
31881
  }
31938
31882
  const files = [
31939
31883
  {
31940
- path: path10.join(appDir, "sitemap.ts"),
31884
+ path: path12.join(appDir, "sitemap.ts"),
31941
31885
  label: "Sitemap",
31942
31886
  content: `import { createSitemap } from '@sonordev/site-kit/sitemap'
31943
31887
 
31944
31888
  export default createSitemap({
31945
31889
  // baseUrl auto-resolved from Portal via API key
31946
- includeLlmsTxtInSitemap: true,
31947
- includeLlmsFullTxtInSitemap: true,
31890
+ // llms.txt stays out of the sitemap on purpose: it's a plain-text duplicate
31891
+ // of these pages, and AI crawlers find it at /llms.txt anyway.
31948
31892
  // optimizedLLMsTxt: true, // optional: static build writes optimized llms (CI)
31949
31893
  // llmsPublicSummaryOnly: true, // optional: page list from Portal public summaries only
31950
31894
  // additionalPaths: async () => [...],
@@ -31952,7 +31896,7 @@ export default createSitemap({
31952
31896
  `
31953
31897
  },
31954
31898
  {
31955
- path: path10.join(appDir, "robots.txt", "route.ts"),
31899
+ path: path12.join(appDir, "robots.txt", "route.ts"),
31956
31900
  label: "Robots.txt",
31957
31901
  content: `import { createRobots } from '@sonordev/site-kit/robots'
31958
31902
 
@@ -31960,7 +31904,7 @@ export const GET = createRobots({})
31960
31904
  `
31961
31905
  },
31962
31906
  {
31963
- path: path10.join(appDir, "llms.txt", "route.ts"),
31907
+ path: path12.join(appDir, "llms.txt", "route.ts"),
31964
31908
  label: "llms.txt",
31965
31909
  content: `import { createLLMsTxtHandler } from '@sonordev/site-kit/llms'
31966
31910
 
@@ -31968,7 +31912,7 @@ export const GET = createLLMsTxtHandler({ preferStatic: true })
31968
31912
  `
31969
31913
  },
31970
31914
  {
31971
- path: path10.join(appDir, "llms-full.txt", "route.ts"),
31915
+ path: path12.join(appDir, "llms-full.txt", "route.ts"),
31972
31916
  label: "llms-full.txt",
31973
31917
  content: `import { createLLMsFullTxtHandler } from '@sonordev/site-kit/llms'
31974
31918
 
@@ -31979,14 +31923,14 @@ export const GET = createLLMsFullTxtHandler({ preferStatic: true })
31979
31923
  if (!options.minimal) {
31980
31924
  files.push(
31981
31925
  {
31982
- path: path10.join(cwd, "proxy.ts"),
31983
- label: "Proxy (security headers; redirects resolve at the 404 boundary)",
31926
+ path: path12.join(cwd, "proxy.ts"),
31927
+ label: "Proxy (security headers, managed redirects)",
31984
31928
  content: `import { createProxy } from '@sonordev/site-kit/proxy'
31985
31929
 
31986
- // redirects: false \u2014 managed redirects resolve in app/not-found.tsx via
31987
- // resolveManagedRedirect() instead of on every request. The proxy still
31988
- // stamps x-sk-path so the 404 boundary knows the requested URL.
31989
- export default createProxy({ redirects: false })
31930
+ // Sonor-managed redirects apply here. The rule list is cached in memory for
31931
+ // five minutes, so page loads rarely wait on it. Don't move them into
31932
+ // app/not-found.tsx: reading request headers there makes every page dynamic.
31933
+ export default createProxy({ redirects: true })
31990
31934
 
31991
31935
  // Inlined on purpose: Next statically parses \`config.matcher\` at build time
31992
31936
  // and rejects an imported value (Turbopack build error). Keep in sync with
@@ -31999,7 +31943,7 @@ export const config = {
31999
31943
  `
32000
31944
  },
32001
31945
  {
32002
- path: path10.join(appDir, "manifest.webmanifest", "route.ts"),
31946
+ path: path12.join(appDir, "manifest.webmanifest", "route.ts"),
32003
31947
  label: "PWA Manifest",
32004
31948
  content: `import { createManifest } from '@sonordev/site-kit/manifest'
32005
31949
 
@@ -32007,19 +31951,12 @@ export const GET = createManifest()
32007
31951
  `
32008
31952
  },
32009
31953
  {
32010
- path: path10.join(appDir, "not-found.tsx"),
32011
- label: "404 Page (resolves managed redirects)",
32012
- content: `import { redirect, permanentRedirect } from 'next/navigation'
32013
- import { resolveManagedRedirect } from '@sonordev/site-kit/redirects/not-found'
32014
-
32015
- export default async function NotFound() {
32016
- // Sonor-managed redirects resolve here, at the only place they can matter:
32017
- // a URL that would otherwise 404. Successful page loads pay nothing.
32018
- const managed = await resolveManagedRedirect()
32019
- if (managed) {
32020
- ;(managed.permanent ? permanentRedirect : redirect)(managed.destination)
32021
- }
32022
-
31954
+ path: path12.join(appDir, "not-found.tsx"),
31955
+ label: "404 Page",
31956
+ content: `// Keep this component free of request APIs (headers, cookies). Next
31957
+ // renders the root 404 inside every page, so one headers() call here makes
31958
+ // the whole site dynamic. Managed redirects run in proxy.ts instead.
31959
+ export default function NotFound() {
32023
31960
  return (
32024
31961
  <div style={{ textAlign: 'center', padding: '4rem 1rem' }}>
32025
31962
  <h1 style={{ fontSize: '3rem', fontWeight: 700, marginBottom: '0.5rem' }}>404</h1>
@@ -32047,7 +31984,7 @@ export default async function NotFound() {
32047
31984
  `
32048
31985
  },
32049
31986
  {
32050
- path: path10.join(appDir, "error.tsx"),
31987
+ path: path12.join(appDir, "error.tsx"),
32051
31988
  label: "Error Boundary",
32052
31989
  content: `'use client'
32053
31990
 
@@ -32087,7 +32024,7 @@ export default function Error({
32087
32024
  `
32088
32025
  },
32089
32026
  {
32090
- path: path10.join(cwd, "og.config.ts"),
32027
+ path: path12.join(cwd, "og.config.ts"),
32091
32028
  label: "OG card config (run: sonor-setup og)",
32092
32029
  content: `import { defineOgCard } from '@sonordev/site-kit/og'
32093
32030
 
@@ -32116,7 +32053,7 @@ export default defineOgCard({
32116
32053
  // .env.local, not .env.example: one real env file per project. The
32117
32054
  // deployer copies these values into the host's env settings. Skipped
32118
32055
  // when the file already exists, so real keys are never touched.
32119
- path: path10.join(cwd, ".env.local"),
32056
+ path: path12.join(cwd, ".env.local"),
32120
32057
  label: ".env.local",
32121
32058
  content: `# ===================================
32122
32059
  # @sonordev/site-kit \u2014 Environment Variables
@@ -32138,10 +32075,10 @@ SONOR_API_KEY=sonor_your-project-uuid_your-secret-key
32138
32075
  if (options.dryRun) {
32139
32076
  console.log(source_default.yellow(" [DRY RUN] Would create:"));
32140
32077
  for (const f of files) {
32141
- const rel = path10.relative(cwd, f.path);
32142
- const exists = existsSync(f.path);
32078
+ const rel = path12.relative(cwd, f.path);
32079
+ const exists2 = existsSync(f.path);
32143
32080
  console.log(
32144
- source_default.gray(` ${rel}`) + (exists ? source_default.yellow(" (exists, would skip)") : "")
32081
+ source_default.gray(` ${rel}`) + (exists2 ? source_default.yellow(" (exists, would skip)") : "")
32145
32082
  );
32146
32083
  }
32147
32084
  console.log("");
@@ -32153,13 +32090,13 @@ SONOR_API_KEY=sonor_your-project-uuid_your-secret-key
32153
32090
  for (const f of files) {
32154
32091
  try {
32155
32092
  if (existsSync(f.path) && !options.force) {
32156
- spinner.warn(`Skipped (exists): ${path10.relative(cwd, f.path)}`);
32093
+ spinner.warn(`Skipped (exists): ${path12.relative(cwd, f.path)}`);
32157
32094
  skipped++;
32158
32095
  continue;
32159
32096
  }
32160
- await fs3.mkdir(path10.dirname(f.path), { recursive: true });
32097
+ await fs3.mkdir(path12.dirname(f.path), { recursive: true });
32161
32098
  await fs3.writeFile(f.path, f.content, "utf-8");
32162
- spinner.succeed(`${f.label}: ${path10.relative(cwd, f.path)}`);
32099
+ spinner.succeed(`${f.label}: ${path12.relative(cwd, f.path)}`);
32163
32100
  created++;
32164
32101
  } catch (err) {
32165
32102
  spinner.fail(`Failed: ${f.path}`);
@@ -32205,17 +32142,209 @@ SONOR_API_KEY=sonor_your-project-uuid_your-secret-key
32205
32142
  console.log("");
32206
32143
  }
32207
32144
  }
32208
- async function findAppDir3() {
32209
- const cwd = process.cwd();
32210
- const candidates = [
32211
- path10.join(cwd, "app"),
32212
- path10.join(cwd, "src", "app")
32213
- ];
32214
- for (const dir of candidates) {
32215
- if (existsSync(dir)) return dir;
32145
+ var LLMS_FILES = [
32146
+ { path: "/llms.txt", handler: "createLLMsTxtHandler" },
32147
+ { path: "/llms-full.txt", handler: "createLLMsFullTxtHandler" }
32148
+ ];
32149
+ var NEXT_CONFIGS = ["next.config.ts", "next.config.mts", "next.config.mjs", "next.config.js", "next.config.cjs"];
32150
+ function read(cwd, rel) {
32151
+ try {
32152
+ return fs__default.readFileSync(path12.join(cwd, rel), "utf-8");
32153
+ } catch {
32154
+ return "";
32155
+ }
32156
+ }
32157
+ function exists(cwd, rel) {
32158
+ try {
32159
+ return fs__default.existsSync(path12.join(cwd, rel));
32160
+ } catch {
32161
+ return false;
32162
+ }
32163
+ }
32164
+ function patternMatches(pattern, urlPath) {
32165
+ const re2 = pattern.trim().split(/\(\.\*\)|:\w+\*|\*/).map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
32166
+ return new RegExp(`^${re2}$`).test(urlPath);
32167
+ }
32168
+ var NOINDEX = /noindex/i;
32169
+ function netlifyTomlNoindex(toml, urlPath) {
32170
+ const blocks = [];
32171
+ for (const line of toml.split("\n")) {
32172
+ const header = line.match(/^\s*\[\[?\s*([^\]]+?)\s*\]\]?\s*$/);
32173
+ if (header && header[1] !== "headers.values") blocks.push(line);
32174
+ else if (blocks.length) blocks[blocks.length - 1] += `
32175
+ ${line}`;
32176
+ }
32177
+ return blocks.some((block) => {
32178
+ if (!/^\s*\[\[\s*headers\s*\]\]/.test(block)) return false;
32179
+ const pattern = block.match(/^\s*for\s*=\s*["']([^"']+)["']/m)?.[1];
32180
+ const value = block.match(/^\s*["']?X-Robots-Tag["']?\s*=\s*["']([^"']*)["']/im)?.[1];
32181
+ return !!pattern && !!value && NOINDEX.test(value) && patternMatches(pattern, urlPath);
32182
+ });
32183
+ }
32184
+ function headersFileNoindex(text, urlPath) {
32185
+ let current = null;
32186
+ for (const line of text.split("\n")) {
32187
+ if (!line.trim() || line.trim().startsWith("#")) continue;
32188
+ if (!/^\s/.test(line)) {
32189
+ current = line.trim();
32190
+ continue;
32191
+ }
32192
+ const m = line.match(/^\s+X-Robots-Tag\s*:\s*(.+)$/i);
32193
+ if (current && m && NOINDEX.test(m[1]) && patternMatches(current, urlPath)) return true;
32194
+ }
32195
+ return false;
32196
+ }
32197
+ function vercelJsonNoindex(text, urlPath) {
32198
+ try {
32199
+ const json = JSON.parse(text);
32200
+ return (json.headers ?? []).some(
32201
+ (rule) => !!rule.source && patternMatches(rule.source, urlPath) && (rule.headers ?? []).some((h) => /^x-robots-tag$/i.test(h.key ?? "") && NOINDEX.test(h.value ?? ""))
32202
+ );
32203
+ } catch {
32204
+ return false;
32205
+ }
32206
+ }
32207
+ function findHostNoindex(cwd, urlPath) {
32208
+ const toml = read(cwd, "netlify.toml");
32209
+ if (toml && netlifyTomlNoindex(toml, urlPath)) return "netlify.toml";
32210
+ const headers = read(cwd, "public/_headers");
32211
+ if (headers && headersFileNoindex(headers, urlPath)) return "public/_headers";
32212
+ const vercel = read(cwd, "vercel.json");
32213
+ if (vercel && vercelJsonNoindex(vercel, urlPath)) return "vercel.json";
32214
+ return null;
32215
+ }
32216
+ var LINK_DISCOVERY_LINE = /^.*\bLink\b.*(llms[^\n]*describedby|describedby[^\n]*llms).*$/im;
32217
+ function findDiscoverySource(cwd) {
32218
+ for (const rel of findProxyFiles(cwd)) {
32219
+ const src = read(cwd, rel);
32220
+ const viaFactory = /\bcreate(Proxy|Middleware)\s*\(/.test(src) && /\bllmsDiscovery\b(?!\s*:\s*false\b)/.test(src);
32221
+ if (viaFactory) return `${rel} (createProxy llmsDiscovery)`;
32222
+ if (src.includes("buildAiDiscoveryHeaders")) return `${rel} (buildAiDiscoveryHeaders)`;
32223
+ }
32224
+ for (const rel of NEXT_CONFIGS) {
32225
+ const src = read(cwd, rel);
32226
+ if (!src) continue;
32227
+ if (/\bllmsTxtDiscoveryLink\s*:(?!\s*false\b)/.test(src)) return `${rel} (llmsTxtDiscoveryLink)`;
32228
+ if (src.includes("buildAiDiscoveryHeaders")) return `${rel} (buildAiDiscoveryHeaders)`;
32229
+ break;
32230
+ }
32231
+ const layout = findRootLayout(cwd);
32232
+ if (layout) {
32233
+ const src = read(cwd, path12.relative(cwd, layout));
32234
+ if (src.includes("buildAiDiscoveryHeaders") || src.includes("llmsTxtDiscoveryLink")) {
32235
+ return path12.relative(cwd, layout);
32236
+ }
32237
+ }
32238
+ for (const rel of ["netlify.toml", "public/_headers"]) {
32239
+ if (LINK_DISCOVERY_LINE.test(read(cwd, rel))) return rel;
32216
32240
  }
32217
32241
  return null;
32218
32242
  }
32243
+ function readGeoWiring(cwd) {
32244
+ const appDir = NEXT_APP_DIRS.find((rel) => exists(cwd, rel)) ?? null;
32245
+ const sitemap = findSitemapRoute(cwd);
32246
+ const sitemapSrc = sitemap ? read(cwd, sitemap) : "";
32247
+ const sitemapListsLlms = /\bincludeLlms(Full)?TxtInSitemap\s*:\s*true\b/.test(sitemapSrc) || /['"`/]llms(-full)?\.txt['"`]/.test(sitemapSrc);
32248
+ const sitemapWritesStatic = /\bcreateSitemap\s*\(/.test(sitemapSrc);
32249
+ const writesLlms = sitemapWritesStatic && !/\boptimizedLLMsTxt\s*:\s*false\b/.test(sitemapSrc);
32250
+ const writesLlmsFull = writesLlms && /\boptimizedLLMsFullTxt\s*:\s*true\b/.test(sitemapSrc);
32251
+ const llms = LLMS_FILES.map(({ path: urlPath, handler }) => {
32252
+ const file = urlPath.slice(1);
32253
+ const routeAbs = appDir ? findConventionFile(path12.join(cwd, appDir, file), "route") : null;
32254
+ const route = routeAbs ? path12.relative(cwd, routeAbs) : null;
32255
+ const routeSrc = route ? read(cwd, route) : "";
32256
+ const publicFile = exists(cwd, path12.join("public", file));
32257
+ const built = urlPath === "/llms.txt" ? writesLlms : writesLlmsFull;
32258
+ return {
32259
+ path: urlPath,
32260
+ route,
32261
+ routeUsesKitHandler: routeSrc.includes(handler),
32262
+ routeOptsOutOfNoindex: /\bnoindex\s*:\s*false\b/.test(routeSrc),
32263
+ routeSetsNoindex: /X-Robots-Tag/i.test(routeSrc) && NOINDEX.test(routeSrc),
32264
+ servedStatic: publicFile || built,
32265
+ staticReason: publicFile ? `public/${file}` : built ? `public/${file} (written by createSitemap at build)` : null,
32266
+ hostNoindex: findHostNoindex(cwd, urlPath)
32267
+ };
32268
+ });
32269
+ return { appDir, llms, sitemap, sitemapListsLlms, discovery: findDiscoverySource(cwd) };
32270
+ }
32271
+ var DISCOVERY_FIX = "Add llmsDiscovery to the proxy: createProxy({ llmsDiscovery: { siteUrl } }) in proxy.ts. Or withSiteKitConfig({ llmsTxtDiscoveryLink: true }) in next.config.";
32272
+ var SITEMAP_FIX = "Drop includeLlmsTxtInSitemap / includeLlmsFullTxtInSitemap (and any hand-added /llms*.txt entry) from the sitemap. A sitemap lists indexable HTML pages; AI crawlers find llms.txt at /llms.txt.";
32273
+ function hostNoindexFix(urlPath) {
32274
+ return `The CDN serves it before any route handler runs, so set the header in host config. netlify.toml: [[headers]] for = "${urlPath}" [headers.values] X-Robots-Tag = "noindex"`;
32275
+ }
32276
+ function judgeGeoWiring(facts) {
32277
+ const rows = [];
32278
+ for (const f of facts.llms) {
32279
+ const name = f.path.slice(1);
32280
+ const id = f.path === "/llms.txt" ? "llms" : "llms-full";
32281
+ const served = !!f.route || f.servedStatic;
32282
+ rows.push(
32283
+ served ? { id: `${id}.served`, label: `${name} served`, level: "ok", detail: f.route ?? f.staticReason ?? void 0 } : {
32284
+ id: `${id}.served`,
32285
+ label: `${name} served`,
32286
+ level: "fail",
32287
+ detail: `no ${facts.appDir ?? "app"}/${name}/route.* and no public/${name}`,
32288
+ fix: "Run: sonor-setup geo --ensure-routes"
32289
+ }
32290
+ );
32291
+ }
32292
+ if (!facts.sitemap) {
32293
+ rows.push({ id: "geo.sitemap", label: "sitemap leaves llms files out", level: "info", detail: "no sitemap route to check" });
32294
+ } else if (facts.sitemapListsLlms) {
32295
+ rows.push({
32296
+ id: "geo.sitemap",
32297
+ label: "sitemap leaves llms files out",
32298
+ level: "warn",
32299
+ detail: `${facts.sitemap} lists /llms.txt, inviting search engines to index a thin plain-text duplicate`,
32300
+ fix: SITEMAP_FIX
32301
+ });
32302
+ } else {
32303
+ rows.push({ id: "geo.sitemap", label: "sitemap leaves llms files out", level: "ok", detail: facts.sitemap });
32304
+ }
32305
+ rows.push(
32306
+ facts.discovery ? { id: "geo.discovery", label: 'discovery header (Link rel="describedby")', level: "ok", detail: facts.discovery } : {
32307
+ id: "geo.discovery",
32308
+ label: 'discovery header (Link rel="describedby")',
32309
+ level: "fail",
32310
+ detail: "not wired in proxy, next.config, root layout, or host config",
32311
+ fix: DISCOVERY_FIX
32312
+ }
32313
+ );
32314
+ for (const f of facts.llms) {
32315
+ if (!f.route && !f.servedStatic) continue;
32316
+ const name = f.path.slice(1);
32317
+ const id = `${f.path === "/llms.txt" ? "llms" : "llms-full"}.noindex`;
32318
+ const label = `${name} sends X-Robots-Tag: noindex`;
32319
+ if (f.servedStatic) {
32320
+ rows.push(
32321
+ f.hostNoindex ? { id, label, level: "ok", detail: f.hostNoindex } : { id, label, level: "warn", detail: `${f.staticReason} is served without it`, fix: hostNoindexFix(f.path) }
32322
+ );
32323
+ continue;
32324
+ }
32325
+ if (f.hostNoindex) {
32326
+ rows.push({ id, label, level: "ok", detail: f.hostNoindex });
32327
+ } else if (f.routeUsesKitHandler && !f.routeOptsOutOfNoindex) {
32328
+ rows.push({ id, label, level: "ok", detail: `${f.route} (site-kit handler default)` });
32329
+ } else if (f.routeSetsNoindex) {
32330
+ rows.push({ id, label, level: "ok", detail: f.route });
32331
+ } else {
32332
+ rows.push({
32333
+ id,
32334
+ label,
32335
+ level: "warn",
32336
+ detail: f.routeOptsOutOfNoindex ? `${f.route} passes noindex: false` : `${f.route} doesn't set it`,
32337
+ fix: f.routeOptsOutOfNoindex ? "Drop noindex: false unless you want llms.txt in search results." : "Serve it with createLLMsTxtHandler (sends the header by default), or add X-Robots-Tag: noindex to the response."
32338
+ });
32339
+ }
32340
+ }
32341
+ return rows;
32342
+ }
32343
+ function checkGeoWiring(cwd) {
32344
+ return judgeGeoWiring(readGeoWiring(cwd));
32345
+ }
32346
+
32347
+ // src/cli/commands/geo.ts
32219
32348
  var LLMS_ROUTE = `import { createLLMsTxtHandler } from '@sonordev/site-kit/llms'
32220
32349
 
32221
32350
  export const GET = createLLMsTxtHandler({ preferStatic: true })
@@ -32224,40 +32353,36 @@ var LLMS_FULL_ROUTE = `import { createLLMsFullTxtHandler } from '@sonordev/site-
32224
32353
 
32225
32354
  export const GET = createLLMsFullTxtHandler({ preferStatic: true })
32226
32355
  `;
32227
- async function readIfExists(p) {
32228
- if (!existsSync(p)) return "";
32229
- try {
32230
- return await fs3.readFile(p, "utf-8");
32231
- } catch {
32232
- return "";
32233
- }
32234
- }
32356
+ var ICON = {
32357
+ ok: source_default.green(" \u2713 "),
32358
+ info: source_default.gray(" \xB7 "),
32359
+ warn: source_default.yellow(" ! "),
32360
+ fail: source_default.red(" \u2717 ")
32361
+ };
32235
32362
  async function ensureLlmsRouteFiles(appDir, dryRun) {
32236
- const llms = path10.join(appDir, "llms.txt", "route.ts");
32237
- const llmsFull = path10.join(appDir, "llms-full.txt", "route.ts");
32238
32363
  let n5 = 0;
32239
32364
  if (dryRun) return 0;
32240
- if (!existsSync(llms)) {
32241
- await fs3.mkdir(path10.dirname(llms), { recursive: true });
32242
- await fs3.writeFile(llms, LLMS_ROUTE, "utf-8");
32243
- n5++;
32244
- }
32245
- if (!existsSync(llmsFull)) {
32246
- await fs3.mkdir(path10.dirname(llmsFull), { recursive: true });
32247
- await fs3.writeFile(llmsFull, LLMS_FULL_ROUTE, "utf-8");
32365
+ for (const [dir, source] of [
32366
+ ["llms.txt", LLMS_ROUTE],
32367
+ ["llms-full.txt", LLMS_FULL_ROUTE]
32368
+ ]) {
32369
+ if (findConventionFile(path12.join(appDir, dir), "route")) continue;
32370
+ const file = path12.join(appDir, dir, "route.ts");
32371
+ await fs3.mkdir(path12.dirname(file), { recursive: true });
32372
+ await fs3.writeFile(file, source, "utf-8");
32248
32373
  n5++;
32249
32374
  }
32250
32375
  return n5;
32251
32376
  }
32252
32377
  async function geoCommand(options) {
32253
32378
  if (options.forInstall) {
32254
- const appDir2 = await findAppDir3();
32379
+ const appDir2 = findAppDirForDiscovery();
32255
32380
  if (!appDir2) return;
32256
32381
  const created = await ensureLlmsRouteFiles(appDir2, options.dryRun);
32257
32382
  if (created > 0) {
32258
32383
  console.log(
32259
32384
  source_default.cyan(
32260
- `[@sonordev/site-kit] Created ${created} llms route file(s). Set NEXT_PUBLIC_SITE_URL, use createSitemap({ includeLlmsTxtInSitemap: true }), and withSiteKitConfig({ llmsTxtDiscoveryLink: true }) when ready.`
32385
+ `[@sonordev/site-kit] Created ${created} llms route file(s). Set NEXT_PUBLIC_SITE_URL and add createProxy({ llmsDiscovery: { siteUrl } }) to proxy.ts when ready.`
32261
32386
  )
32262
32387
  );
32263
32388
  }
@@ -32272,59 +32397,20 @@ async function geoCommand(options) {
32272
32397
  )
32273
32398
  );
32274
32399
  console.log("");
32275
- const appDir = await findAppDir3();
32400
+ const appDir = findAppDirForDiscovery();
32276
32401
  if (!appDir) {
32277
32402
  console.log(source_default.red(" \u2717 No app directory (app/ or src/app/)"));
32278
32403
  process.exit(1);
32279
32404
  }
32280
- const llms = path10.join(appDir, "llms.txt", "route.ts");
32281
- const llmsFull = path10.join(appDir, "llms-full.txt", "route.ts");
32282
- const sitemap = path10.join(appDir, "sitemap.ts");
32283
32405
  let allOk = true;
32284
- const row = (label, pass) => {
32285
- if (!pass) allOk = false;
32286
- console.log(
32287
- (pass ? source_default.green(" \u2713 ") : source_default.red(" \u2717 ")) + label
32288
- );
32289
- };
32290
- row("llms.txt route", existsSync(llms));
32291
- row("llms-full.txt route", existsSync(llmsFull));
32292
- let sitemapHasLlms = false;
32293
- if (existsSync(sitemap)) {
32294
- const txt = await readIfExists(sitemap);
32295
- sitemapHasLlms = txt.includes("includeLlmsTxtInSitemap") || txt.includes("includeLlmsFullTxtInSitemap");
32296
- row("sitemap.ts lists llms URLs", sitemapHasLlms);
32297
- } else {
32298
- row("sitemap.ts lists llms URLs", false);
32299
- }
32300
- const nextConfigs = [
32301
- path10.join(cwd, "next.config.ts"),
32302
- path10.join(cwd, "next.config.mjs"),
32303
- path10.join(cwd, "next.config.js")
32304
- ];
32305
- let nextCfg = "";
32306
- for (const p of nextConfigs) {
32307
- if (existsSync(p)) {
32308
- nextCfg = await readIfExists(p);
32309
- break;
32406
+ for (const row of checkGeoWiring(cwd)) {
32407
+ if (row.level === "fail") allOk = false;
32408
+ const detail = row.detail ? source_default.gray(` ${row.detail}`) : "";
32409
+ console.log(`${ICON[row.level]}${row.label}${detail}`);
32410
+ if (row.fix && (row.level === "fail" || row.level === "warn")) {
32411
+ console.log(source_default.gray(` ${row.fix}`));
32310
32412
  }
32311
32413
  }
32312
- const layoutCandidates = [
32313
- path10.join(appDir, "layout.tsx"),
32314
- path10.join(appDir, "layout.jsx"),
32315
- path10.join(appDir, "layout.js")
32316
- ];
32317
- let layoutTxt = "";
32318
- for (const p of layoutCandidates) {
32319
- layoutTxt = await readIfExists(p);
32320
- if (layoutTxt) break;
32321
- }
32322
- const hasLayoutDiscovery = layoutTxt.includes("buildAiDiscoveryHeaders") || layoutTxt.includes("llmsTxtDiscoveryLink");
32323
- const hasConfigDiscovery = nextCfg.includes("llmsTxtDiscoveryLink");
32324
- row(
32325
- "discovery header (next.config or root layout)",
32326
- hasConfigDiscovery || hasLayoutDiscovery
32327
- );
32328
32414
  const siteUrl = process.env.NEXT_PUBLIC_SITE_URL?.trim() || process.env.SITE_BASE_URL?.trim() || (process.env.VERCEL_URL?.trim() ? `https://${process.env.VERCEL_URL.replace(/\/$/, "")}` : "");
32329
32415
  if (siteUrl) {
32330
32416
  console.log(source_default.gray(` Public origin (env): ${siteUrl}`));
@@ -32350,19 +32436,16 @@ async function geoCommand(options) {
32350
32436
  console.log(source_default.bold(" Automation"));
32351
32437
  console.log("");
32352
32438
  console.log(
32353
- source_default.gray(
32354
- " \u2022 next.config: withSiteKitConfig({ llmsTxtDiscoveryLink: true })"
32355
- )
32439
+ source_default.gray(' \u2022 proxy.ts: createProxy({ llmsDiscovery: { siteUrl } }) (Link rel="describedby")')
32356
32440
  );
32357
32441
  console.log(
32358
- source_default.gray(
32359
- " (If you define your own headers() on nextConfig, merge Link manually.)"
32360
- )
32442
+ source_default.gray(" or next.config: withSiteKitConfig({ llmsTxtDiscoveryLink: true })")
32361
32443
  );
32362
32444
  console.log(
32363
- source_default.gray(
32364
- " \u2022 createSitemap({ includeLlmsTxtInSitemap: true, includeLlmsFullTxtInSitemap: true })"
32365
- )
32445
+ source_default.gray(" \u2022 createLLMsTxtHandler sends X-Robots-Tag: noindex; a static public/llms.txt needs it in netlify.toml")
32446
+ );
32447
+ console.log(
32448
+ source_default.gray(" \u2022 Keep llms.txt out of the sitemap: AI crawlers find it at /llms.txt")
32366
32449
  );
32367
32450
  console.log(
32368
32451
  source_default.gray(" \u2022 npx sonor-setup scaffold --minimal (routes + sitemap template)")
@@ -32372,8 +32455,8 @@ async function geoCommand(options) {
32372
32455
  }
32373
32456
 
32374
32457
  // src/cli/index.ts
32375
- (0, import_dotenv.config)({ path: ".env.local", quiet: true });
32376
- (0, import_dotenv.config)({ path: ".env", quiet: true });
32458
+ (0, import_dotenv2.config)({ path: ".env.local", quiet: true });
32459
+ (0, import_dotenv2.config)({ path: ".env", quiet: true });
32377
32460
  var program2 = new Command();
32378
32461
  program2.name("sonor-setup").description("Setup + verification toolchain for @sonordev/site-kit").version(SITE_KIT_VERSION);
32379
32462
  withAgentFlags(