@sonordev/site-kit 5.0.0 → 5.3.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 (271) hide show
  1. package/README.md +15 -0
  2. package/agent-manifest.json +30 -6
  3. package/dist/AnalyticsProvider-2YV4ZVZD.js +31 -0
  4. package/dist/{AnalyticsProvider-TXM3DRLI.js.map → AnalyticsProvider-2YV4ZVZD.js.map} +1 -1
  5. package/dist/AnalyticsProvider-XSPROVHM.mjs +10 -0
  6. package/dist/{AnalyticsProvider-KCLRFOX6.mjs.map → AnalyticsProvider-XSPROVHM.mjs.map} +1 -1
  7. package/dist/{BlogViewTracker-J6LRGUHU.js → BlogViewTracker-BQBJTL5L.js} +6 -6
  8. package/dist/{BlogViewTracker-J6LRGUHU.js.map → BlogViewTracker-BQBJTL5L.js.map} +1 -1
  9. package/dist/{BlogViewTracker-PZWAWB3O.mjs → BlogViewTracker-FEAXIUEW.mjs} +5 -5
  10. package/dist/{BlogViewTracker-PZWAWB3O.mjs.map → BlogViewTracker-FEAXIUEW.mjs.map} +1 -1
  11. package/dist/ChatWidget-B2DI2OWH.mjs +11 -0
  12. package/dist/{ChatWidget-PMDPSZXG.mjs.map → ChatWidget-B2DI2OWH.mjs.map} +1 -1
  13. package/dist/ChatWidget-GPBFJ4A3.js +20 -0
  14. package/dist/{ChatWidget-LD54Z2PQ.js.map → ChatWidget-GPBFJ4A3.js.map} +1 -1
  15. package/dist/EngageWidget-JXJSFONK.js +18 -0
  16. package/dist/{EngageWidget-BF5NMQ5A.js.map → EngageWidget-JXJSFONK.js.map} +1 -1
  17. package/dist/EngageWidget-KF4HU4YA.mjs +9 -0
  18. package/dist/{EngageWidget-4CBFRN4Y.mjs.map → EngageWidget-KF4HU4YA.mjs.map} +1 -1
  19. package/dist/{FileField-VXADIOMN.js → FileField-22BB34L3.js} +6 -6
  20. package/dist/{FileField-VXADIOMN.js.map → FileField-22BB34L3.js.map} +1 -1
  21. package/dist/{FileField-FFRHS3XP.mjs → FileField-WI6SADBA.mjs} +5 -5
  22. package/dist/{FileField-FFRHS3XP.mjs.map → FileField-WI6SADBA.mjs.map} +1 -1
  23. package/dist/{FormSpotlight-KE46EDP5.mjs → FormSpotlight-6FZV6JOA.mjs} +3 -3
  24. package/dist/{FormSpotlight-KE46EDP5.mjs.map → FormSpotlight-6FZV6JOA.mjs.map} +1 -1
  25. package/dist/{FormSpotlight-JG4ZHS56.js → FormSpotlight-QCIN67NB.js} +15 -15
  26. package/dist/{FormSpotlight-JG4ZHS56.js.map → FormSpotlight-QCIN67NB.js.map} +1 -1
  27. package/dist/{FormStage-PZKWEXZE.mjs → FormStage-P3IIHVCC.mjs} +3 -3
  28. package/dist/{FormStage-PZKWEXZE.mjs.map → FormStage-P3IIHVCC.mjs.map} +1 -1
  29. package/dist/{FormStage-5Z53Z2WY.js → FormStage-SBQQZDW6.js} +13 -13
  30. package/dist/{FormStage-5Z53Z2WY.js.map → FormStage-SBQQZDW6.js.map} +1 -1
  31. package/dist/ManagedForm-6LII4DED.js +23 -0
  32. package/dist/{ManagedForm-E4WHMARH.js.map → ManagedForm-6LII4DED.js.map} +1 -1
  33. package/dist/ManagedForm-O3JRRWZ6.mjs +14 -0
  34. package/dist/{ManagedForm-VU2TKV6J.mjs.map → ManagedForm-O3JRRWZ6.mjs.map} +1 -1
  35. package/dist/{ManagedNewsletterForm-6DET3VGZ.mjs → ManagedNewsletterForm-FFFF5UEX.mjs} +7 -7
  36. package/dist/{ManagedNewsletterForm-6DET3VGZ.mjs.map → ManagedNewsletterForm-FFFF5UEX.mjs.map} +1 -1
  37. package/dist/{ManagedNewsletterForm-PG4EX3W6.js → ManagedNewsletterForm-Z7NYZPAN.js} +8 -8
  38. package/dist/{ManagedNewsletterForm-PG4EX3W6.js.map → ManagedNewsletterForm-Z7NYZPAN.js.map} +1 -1
  39. package/dist/{SignalCore-RZVTLUC2.mjs → SignalCore-IUOSVYUE.mjs} +5 -5
  40. package/dist/{SignalCore-RZVTLUC2.mjs.map → SignalCore-IUOSVYUE.mjs.map} +1 -1
  41. package/dist/{SignalCore-TCUVXVMN.js → SignalCore-WL5WKQEI.js} +11 -11
  42. package/dist/{SignalCore-TCUVXVMN.js.map → SignalCore-WL5WKQEI.js.map} +1 -1
  43. package/dist/SitemapSync-2O5UM4GM.mjs +8 -0
  44. package/dist/{SitemapSync-T75NAFB3.mjs.map → SitemapSync-2O5UM4GM.mjs.map} +1 -1
  45. package/dist/SitemapSync-LA67GKKS.js +17 -0
  46. package/dist/{SitemapSync-AJU4DM3G.js.map → SitemapSync-LA67GKKS.js.map} +1 -1
  47. package/dist/analytics/index.js +9 -9
  48. package/dist/analytics/index.mjs +4 -4
  49. package/dist/blog/index.d.ts +9 -5
  50. package/dist/blog/index.d.ts.map +1 -1
  51. package/dist/blog/index.js +20 -20
  52. package/dist/blog/index.mjs +3 -3
  53. package/dist/blog/server-ui.js +14 -14
  54. package/dist/blog/server-ui.mjs +2 -2
  55. package/dist/{chunk-LZY374FB.js → chunk-2OZ2SMZH.js} +4 -4
  56. package/dist/{chunk-LZY374FB.js.map → chunk-2OZ2SMZH.js.map} +1 -1
  57. package/dist/{chunk-BQY3FJ3R.js → chunk-3DQXXYCS.js} +8 -8
  58. package/dist/{chunk-BQY3FJ3R.js.map → chunk-3DQXXYCS.js.map} +1 -1
  59. package/dist/chunk-3PTKHSF7.mjs +6 -0
  60. package/dist/{chunk-JPTJGLKS.mjs.map → chunk-3PTKHSF7.mjs.map} +1 -1
  61. package/dist/{chunk-PPCTL4B5.mjs → chunk-4TU246Q4.mjs} +10 -3
  62. package/dist/chunk-4TU246Q4.mjs.map +1 -0
  63. package/dist/{chunk-3FZ76VI5.js → chunk-4YJFC6FC.js} +14 -14
  64. package/dist/{chunk-3FZ76VI5.js.map → chunk-4YJFC6FC.js.map} +1 -1
  65. package/dist/{chunk-7T4VMXKD.js → chunk-5I7UEXJL.js} +3 -3
  66. package/dist/{chunk-7T4VMXKD.js.map → chunk-5I7UEXJL.js.map} +1 -1
  67. package/dist/{chunk-MGPHBVOK.js → chunk-6ABEAO2K.js} +9 -9
  68. package/dist/{chunk-MGPHBVOK.js.map → chunk-6ABEAO2K.js.map} +1 -1
  69. package/dist/{chunk-SW6KWUNI.mjs → chunk-6RYCAW5B.mjs} +3 -3
  70. package/dist/{chunk-SW6KWUNI.mjs.map → chunk-6RYCAW5B.mjs.map} +1 -1
  71. package/dist/{chunk-MVJQ4ZA2.mjs → chunk-7MQR4KDL.mjs} +4 -4
  72. package/dist/{chunk-MVJQ4ZA2.mjs.map → chunk-7MQR4KDL.mjs.map} +1 -1
  73. package/dist/{chunk-FQ3JQV3M.js → chunk-7NMI7M56.js} +4 -4
  74. package/dist/{chunk-FQ3JQV3M.js.map → chunk-7NMI7M56.js.map} +1 -1
  75. package/dist/{chunk-XPAHKYX7.mjs → chunk-7OCQ4646.mjs} +3 -3
  76. package/dist/{chunk-XPAHKYX7.mjs.map → chunk-7OCQ4646.mjs.map} +1 -1
  77. package/dist/chunk-AEW7EFYU.js +147 -0
  78. package/dist/chunk-AEW7EFYU.js.map +1 -0
  79. package/dist/{chunk-OGPS3DKE.js → chunk-B7FHRTBA.js} +5 -5
  80. package/dist/{chunk-OGPS3DKE.js.map → chunk-B7FHRTBA.js.map} +1 -1
  81. package/dist/{chunk-SXPINIJG.mjs → chunk-BAFGZQWP.mjs} +4 -4
  82. package/dist/{chunk-SXPINIJG.mjs.map → chunk-BAFGZQWP.mjs.map} +1 -1
  83. package/dist/chunk-BIZT7AYK.js +8 -0
  84. package/dist/{chunk-S65JSRWW.js.map → chunk-BIZT7AYK.js.map} +1 -1
  85. package/dist/{chunk-EISVUD75.mjs → chunk-D2D3YKWT.mjs} +3 -3
  86. package/dist/{chunk-EISVUD75.mjs.map → chunk-D2D3YKWT.mjs.map} +1 -1
  87. package/dist/{chunk-FTBABL3T.mjs → chunk-DXFZA34N.mjs} +3 -3
  88. package/dist/{chunk-FTBABL3T.mjs.map → chunk-DXFZA34N.mjs.map} +1 -1
  89. package/dist/{chunk-4UHO6DPJ.mjs → chunk-F4DZH4E5.mjs} +4 -4
  90. package/dist/{chunk-4UHO6DPJ.mjs.map → chunk-F4DZH4E5.mjs.map} +1 -1
  91. package/dist/{chunk-QH3WVTEK.mjs → chunk-FDLFXHUU.mjs} +4 -4
  92. package/dist/{chunk-QH3WVTEK.mjs.map → chunk-FDLFXHUU.mjs.map} +1 -1
  93. package/dist/{chunk-MWXBRCM2.mjs → chunk-GCY6VPBG.mjs} +3 -3
  94. package/dist/{chunk-MWXBRCM2.mjs.map → chunk-GCY6VPBG.mjs.map} +1 -1
  95. package/dist/{chunk-LLKXPJSE.js → chunk-GF7CQMBL.js} +7 -7
  96. package/dist/{chunk-LLKXPJSE.js.map → chunk-GF7CQMBL.js.map} +1 -1
  97. package/dist/{chunk-FDWDXMJL.mjs → chunk-HHX72A2B.mjs} +3 -3
  98. package/dist/{chunk-FDWDXMJL.mjs.map → chunk-HHX72A2B.mjs.map} +1 -1
  99. package/dist/{chunk-UFURXSAI.mjs → chunk-ITV76G3L.mjs} +39 -3
  100. package/dist/chunk-ITV76G3L.mjs.map +1 -0
  101. package/dist/{chunk-N3RWPAR5.js → chunk-JJ6AI6LW.js} +5 -5
  102. package/dist/{chunk-N3RWPAR5.js.map → chunk-JJ6AI6LW.js.map} +1 -1
  103. package/dist/{chunk-AXYKBQVI.mjs → chunk-K447AIIB.mjs} +8 -8
  104. package/dist/{chunk-AXYKBQVI.mjs.map → chunk-K447AIIB.mjs.map} +1 -1
  105. package/dist/{chunk-6QQFEJIP.js → chunk-K6YQ73IX.js} +8 -8
  106. package/dist/{chunk-6QQFEJIP.js.map → chunk-K6YQ73IX.js.map} +1 -1
  107. package/dist/{chunk-FCKL5CF3.mjs → chunk-KC2FCI5V.mjs} +3 -3
  108. package/dist/{chunk-FCKL5CF3.mjs.map → chunk-KC2FCI5V.mjs.map} +1 -1
  109. package/dist/{chunk-YVE65W47.mjs → chunk-KHHMU4UH.mjs} +4 -4
  110. package/dist/{chunk-YVE65W47.mjs.map → chunk-KHHMU4UH.mjs.map} +1 -1
  111. package/dist/{chunk-HEUCDF3O.mjs → chunk-KIGIAA6Q.mjs} +3 -3
  112. package/dist/{chunk-HEUCDF3O.mjs.map → chunk-KIGIAA6Q.mjs.map} +1 -1
  113. package/dist/{chunk-5OHHYGD6.js → chunk-KMNIW4K4.js} +15 -15
  114. package/dist/{chunk-5OHHYGD6.js.map → chunk-KMNIW4K4.js.map} +1 -1
  115. package/dist/{chunk-PZE5L2FK.mjs → chunk-LCRWCOPI.mjs} +4 -4
  116. package/dist/{chunk-PZE5L2FK.mjs.map → chunk-LCRWCOPI.mjs.map} +1 -1
  117. package/dist/{chunk-62ODUWUX.js → chunk-LFBMFACZ.js} +40 -4
  118. package/dist/chunk-LFBMFACZ.js.map +1 -0
  119. package/dist/chunk-MLXUMVBK.mjs +142 -0
  120. package/dist/chunk-MLXUMVBK.mjs.map +1 -0
  121. package/dist/{chunk-3SMG4EXR.mjs → chunk-MOVMDHGE.mjs} +3 -3
  122. package/dist/{chunk-3SMG4EXR.mjs.map → chunk-MOVMDHGE.mjs.map} +1 -1
  123. package/dist/{chunk-KWH6RAVY.js → chunk-NQLE3V3T.js} +11 -11
  124. package/dist/{chunk-KWH6RAVY.js.map → chunk-NQLE3V3T.js.map} +1 -1
  125. package/dist/{chunk-5JNLZRLX.mjs → chunk-O2KN2SC7.mjs} +3 -3
  126. package/dist/{chunk-5JNLZRLX.mjs.map → chunk-O2KN2SC7.mjs.map} +1 -1
  127. package/dist/{chunk-IX5RAZWX.js → chunk-OQBDJRVP.js} +6 -6
  128. package/dist/{chunk-IX5RAZWX.js.map → chunk-OQBDJRVP.js.map} +1 -1
  129. package/dist/{chunk-MPO6TRLS.js → chunk-PEIWCJXS.js} +14 -14
  130. package/dist/{chunk-MPO6TRLS.js.map → chunk-PEIWCJXS.js.map} +1 -1
  131. package/dist/{chunk-VACFVPNF.js → chunk-RE54UKET.js} +14 -14
  132. package/dist/{chunk-VACFVPNF.js.map → chunk-RE54UKET.js.map} +1 -1
  133. package/dist/{chunk-4D2G5ZNP.js → chunk-RMLRZOVE.js} +15 -15
  134. package/dist/{chunk-4D2G5ZNP.js.map → chunk-RMLRZOVE.js.map} +1 -1
  135. package/dist/{chunk-GCZMDY2T.js → chunk-ULGTZ2VU.js} +3 -3
  136. package/dist/{chunk-GCZMDY2T.js.map → chunk-ULGTZ2VU.js.map} +1 -1
  137. package/dist/{chunk-JY3KZDEM.js → chunk-VTEIXKBA.js} +3 -3
  138. package/dist/{chunk-JY3KZDEM.js.map → chunk-VTEIXKBA.js.map} +1 -1
  139. package/dist/{chunk-YGRHEEPX.mjs → chunk-W7QMCG2A.mjs} +7 -7
  140. package/dist/{chunk-YGRHEEPX.mjs.map → chunk-W7QMCG2A.mjs.map} +1 -1
  141. package/dist/{chunk-HCN2US4M.js → chunk-WZ6QNL2D.js} +18 -18
  142. package/dist/{chunk-HCN2US4M.js.map → chunk-WZ6QNL2D.js.map} +1 -1
  143. package/dist/{chunk-YSZB2DRX.mjs → chunk-X4H2RAIQ.mjs} +3 -3
  144. package/dist/{chunk-YSZB2DRX.mjs.map → chunk-X4H2RAIQ.mjs.map} +1 -1
  145. package/dist/{chunk-JIUVBSQZ.js → chunk-X6SAM7CR.js} +3 -3
  146. package/dist/{chunk-JIUVBSQZ.js.map → chunk-X6SAM7CR.js.map} +1 -1
  147. package/dist/{chunk-J4JXAFSW.mjs → chunk-XRONA2QL.mjs} +3 -3
  148. package/dist/{chunk-J4JXAFSW.mjs.map → chunk-XRONA2QL.mjs.map} +1 -1
  149. package/dist/{chunk-5JQLLF2T.js → chunk-XYZZJZGS.js} +12 -12
  150. package/dist/{chunk-5JQLLF2T.js.map → chunk-XYZZJZGS.js.map} +1 -1
  151. package/dist/{chunk-DX6D7HDI.js → chunk-XZI6KUB3.js} +4 -4
  152. package/dist/{chunk-DX6D7HDI.js.map → chunk-XZI6KUB3.js.map} +1 -1
  153. package/dist/{chunk-UV6KQUSL.mjs → chunk-YDIINUWD.mjs} +3 -3
  154. package/dist/{chunk-UV6KQUSL.mjs.map → chunk-YDIINUWD.mjs.map} +1 -1
  155. package/dist/{chunk-QI2H5KK6.mjs → chunk-YUOVAWCL.mjs} +4 -4
  156. package/dist/{chunk-QI2H5KK6.mjs.map → chunk-YUOVAWCL.mjs.map} +1 -1
  157. package/dist/{chunk-UABMMR7U.js → chunk-Z33JXJTJ.js} +10 -3
  158. package/dist/chunk-Z33JXJTJ.js.map +1 -0
  159. package/dist/cli/index.js +3 -3
  160. package/dist/cli/index.mjs +1 -1
  161. package/dist/client/index.js +4 -4
  162. package/dist/client/index.mjs +3 -3
  163. package/dist/commerce/index.js +56 -56
  164. package/dist/commerce/index.mjs +5 -5
  165. package/dist/commerce/server-result.test.d.ts +2 -0
  166. package/dist/commerce/server-result.test.d.ts.map +1 -0
  167. package/dist/commerce/server.d.ts +51 -0
  168. package/dist/commerce/server.d.ts.map +1 -1
  169. package/dist/commerce/server.js +57 -24
  170. package/dist/commerce/server.js.map +1 -1
  171. package/dist/commerce/server.mjs +54 -25
  172. package/dist/commerce/server.mjs.map +1 -1
  173. package/dist/engage/index.js +13 -13
  174. package/dist/engage/index.mjs +7 -7
  175. package/dist/fleet/index.js +8 -8
  176. package/dist/fleet/index.mjs +4 -4
  177. package/dist/forms/ga4-identity.d.ts +31 -0
  178. package/dist/forms/ga4-identity.d.ts.map +1 -0
  179. package/dist/forms/ga4-identity.test.d.ts +2 -0
  180. package/dist/forms/ga4-identity.test.d.ts.map +1 -0
  181. package/dist/forms/index.js +22 -22
  182. package/dist/forms/index.mjs +9 -9
  183. package/dist/forms/server.js +10 -10
  184. package/dist/forms/server.mjs +8 -8
  185. package/dist/forms/static.js +7 -7
  186. package/dist/forms/static.mjs +6 -6
  187. package/dist/forms/submitForm.d.ts.map +1 -1
  188. package/dist/forms/types.d.ts +13 -0
  189. package/dist/forms/types.d.ts.map +1 -1
  190. package/dist/images/index.js +11 -11
  191. package/dist/images/index.mjs +4 -4
  192. package/dist/index.js +63 -63
  193. package/dist/index.mjs +9 -9
  194. package/dist/layout/client.js +8 -8
  195. package/dist/layout/client.mjs +7 -7
  196. package/dist/layout/index.js +10 -10
  197. package/dist/layout/index.mjs +8 -8
  198. package/dist/llms/generateLLMsTxt.d.ts.map +1 -1
  199. package/dist/llms/humanize-industry.d.ts +9 -0
  200. package/dist/llms/humanize-industry.d.ts.map +1 -0
  201. package/dist/llms/humanize-industry.test.d.ts +2 -0
  202. package/dist/llms/humanize-industry.test.d.ts.map +1 -0
  203. package/dist/llms/index.js +12 -12
  204. package/dist/llms/index.mjs +2 -2
  205. package/dist/maps/index.js +5 -5
  206. package/dist/maps/index.mjs +3 -3
  207. package/dist/motion/Parallax.d.ts +42 -0
  208. package/dist/motion/Parallax.d.ts.map +1 -0
  209. package/dist/motion/Reveal.d.ts +59 -0
  210. package/dist/motion/Reveal.d.ts.map +1 -0
  211. package/dist/motion/ScrollScene.d.ts +42 -0
  212. package/dist/motion/ScrollScene.d.ts.map +1 -0
  213. package/dist/motion/engine.d.ts +74 -0
  214. package/dist/motion/engine.d.ts.map +1 -0
  215. package/dist/motion/failsafe.d.ts +20 -0
  216. package/dist/motion/failsafe.d.ts.map +1 -0
  217. package/dist/motion/gsap.d.ts +84 -0
  218. package/dist/motion/gsap.d.ts.map +1 -0
  219. package/dist/motion/gsap.js +103 -0
  220. package/dist/motion/gsap.js.map +1 -0
  221. package/dist/motion/gsap.mjs +99 -0
  222. package/dist/motion/gsap.mjs.map +1 -0
  223. package/dist/motion/index.d.ts +31 -0
  224. package/dist/motion/index.d.ts.map +1 -0
  225. package/dist/motion/index.js +252 -0
  226. package/dist/motion/index.js.map +1 -0
  227. package/dist/motion/index.mjs +230 -0
  228. package/dist/motion/index.mjs.map +1 -0
  229. package/dist/motion/motion.test.d.ts +16 -0
  230. package/dist/motion/motion.test.d.ts.map +1 -0
  231. package/dist/motion/three.d.ts +105 -0
  232. package/dist/motion/three.d.ts.map +1 -0
  233. package/dist/motion/three.js +150 -0
  234. package/dist/motion/three.js.map +1 -0
  235. package/dist/motion/three.mjs +145 -0
  236. package/dist/motion/three.mjs.map +1 -0
  237. package/dist/search/index.js +4 -4
  238. package/dist/search/index.mjs +3 -3
  239. package/dist/seo/client.js +5 -5
  240. package/dist/seo/client.mjs +4 -4
  241. package/dist/seo/index.js +5 -5
  242. package/dist/seo/index.mjs +4 -4
  243. package/dist/server/index.js +3 -3
  244. package/dist/server/index.mjs +2 -2
  245. package/dist/shared/build-entries.d.ts +7 -1
  246. package/dist/shared/build-entries.d.ts.map +1 -1
  247. package/dist/shared/version.d.ts +1 -1
  248. package/dist/signal/index.js +11 -11
  249. package/dist/signal/index.mjs +2 -2
  250. package/dist/sitemap/index.js +2 -2
  251. package/dist/sitemap/index.mjs +1 -1
  252. package/dist/sync/index.js +16 -16
  253. package/dist/sync/index.mjs +4 -4
  254. package/package.json +28 -2
  255. package/skills/site-kit/SKILL.md +6 -0
  256. package/dist/AnalyticsProvider-KCLRFOX6.mjs +0 -10
  257. package/dist/AnalyticsProvider-TXM3DRLI.js +0 -31
  258. package/dist/ChatWidget-LD54Z2PQ.js +0 -20
  259. package/dist/ChatWidget-PMDPSZXG.mjs +0 -11
  260. package/dist/EngageWidget-4CBFRN4Y.mjs +0 -9
  261. package/dist/EngageWidget-BF5NMQ5A.js +0 -18
  262. package/dist/ManagedForm-E4WHMARH.js +0 -23
  263. package/dist/ManagedForm-VU2TKV6J.mjs +0 -14
  264. package/dist/SitemapSync-AJU4DM3G.js +0 -17
  265. package/dist/SitemapSync-T75NAFB3.mjs +0 -8
  266. package/dist/chunk-62ODUWUX.js.map +0 -1
  267. package/dist/chunk-JPTJGLKS.mjs +0 -6
  268. package/dist/chunk-PPCTL4B5.mjs.map +0 -1
  269. package/dist/chunk-S65JSRWW.js +0 -8
  270. package/dist/chunk-UABMMR7U.js.map +0 -1
  271. package/dist/chunk-UFURXSAI.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commerce/server.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["/**\n * @sonordev/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n * \n * All data fetching goes through the Portal API.\n */\n\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n apiUrl: string\n apiKey: string\n projectId: string\n}\n\ninterface SlugItem {\n slug: string\n}\n\nasync function apiFetch<T>(config: ServerConfig, endpoint: string): Promise<T | null> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) return null\n return response.json()\n } catch (error) {\n console.error('API fetch error:', error)\n return null\n }\n}\n\nasync function apiPost<T>(\n config: ServerConfig,\n endpoint: string,\n body: Record<string, unknown>,\n): Promise<T | null> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) return null\n return response.json()\n } catch (error) {\n console.error('API fetch error:', error)\n return null\n }\n}\n\nfunction transformOffering(data: Record<string, unknown>): CommerceOffering {\n return {\n id: data.id as string,\n project_id: data.project_id as string,\n type: data.type as OfferingType,\n status: data.status as 'draft' | 'active' | 'archived' | 'sold_out',\n name: data.name as string,\n slug: data.slug as string,\n description: data.description as string | undefined,\n short_description: data.short_description as string | undefined,\n long_description: data.long_description as string | undefined,\n featured_image_url: data.featured_image_url as string | undefined,\n gallery_images: (data.gallery_image_urls as string[]) || [],\n price_type: (data.price_type as 'fixed' | 'variable' | 'quote' | 'free') || 'fixed',\n price: data.price as number | undefined,\n compare_at_price: data.compare_at_price as number | undefined,\n currency: (data.currency as string) || 'USD',\n price_is_public: (data.price_is_public as boolean) ?? true,\n billing_period: data.billing_period as 'weekly' | 'monthly' | 'quarterly' | 'yearly' | undefined,\n track_inventory: data.track_inventory as boolean | undefined,\n inventory_count: data.inventory_count as number | undefined,\n allow_backorder: data.allow_backorder as boolean | undefined,\n duration_minutes: data.duration_minutes as number | undefined,\n capacity: data.capacity as number | undefined,\n location: data.location as string | undefined,\n is_virtual: data.is_virtual as boolean | undefined,\n virtual_meeting_url: data.virtual_meeting_url as string | undefined,\n requires_booking: data.requires_booking as boolean | undefined,\n booking_lead_time_hours: data.booking_lead_time_hours as number | undefined,\n category: data.category as CommerceOffering['category'],\n category_id: data.category_id as string | undefined,\n tags: (data.tags as string[]) || [],\n seo_title: data.seo_title as string | undefined,\n seo_description: data.seo_description as string | undefined,\n features: (data.features as string[]) || [],\n specifications: (data.specifications as Record<string, string>) || {},\n schedules: (data.schedules as CommerceOffering['schedules']) || [],\n variants: (data.variants as CommerceOffering['variants']) || [],\n created_at: data.created_at as string,\n updated_at: data.updated_at as string,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=product&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=event&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n let typeParam = ''\n if (type) {\n if (Array.isArray(type)) {\n typeParam = `&type=${type.join(',')}`\n } else {\n typeParam = `&type=${type}`\n }\n }\n \n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?status=active&fields=slug${typeParam}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n const data = await apiFetch<{ offering: Record<string, unknown> }>(\n config,\n `/public/commerce/offerings/${slug}`\n )\n \n if (!data?.offering) return null\n \n return transformOffering(data.offering)\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n const params = new URLSearchParams()\n params.set('status', options.status || 'active')\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n params.set('type', options.type.join(','))\n } else {\n params.set('type', options.type)\n }\n }\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const data = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map(transformOffering)\n}\n\n/**\n * Fetch upcoming events (server-side), WITH schedules and category embedded.\n *\n * Uses POST /public/commerce/events — the same endpoint the client fetcher\n * uses — because the GET offerings list does NOT embed commerce_schedules,\n * which made this helper return events with empty `schedules[]` and forced\n * sites to hand-roll their own fetcher for any calendar UI (the Ludlow PTO\n * lesson). Falls back to the legacy offerings query if the events endpoint\n * is unavailable (older self-hosted API).\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n const data = await apiPost<{ events: Record<string, unknown>[] }>(\n config,\n '/public/commerce/events',\n {\n type: 'event',\n category: options.category,\n limit: options.limit,\n includePast: false,\n },\n )\n\n if (data?.events) {\n return data.events.map(transformOffering)\n }\n\n // Legacy fallback: offerings list (no schedules embedded).\n const params = new URLSearchParams()\n params.set('type', 'event')\n params.set('status', 'active')\n params.set('upcoming', 'true')\n\n if (options.category) {\n params.set('category', options.category)\n }\n\n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n\n const legacy = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n\n if (!legacy?.offerings) return []\n\n return legacy.offerings.map(transformOffering)\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n const events = await getUpcomingEvents(config, { limit: 1, category })\n return events[0] || null\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\n/**\n * Create a server config for API calls\n * \n * @param apiUrl - Portal API URL (e.g., 'https://api.sonor.io')\n * @param apiKey - Project API key\n * @param projectId - Project ID\n */\nexport function createServerConfig(\n apiUrl: string,\n apiKey: string,\n projectId: string\n): ServerConfig {\n return { apiUrl, apiKey, projectId }\n}\n"]}
1
+ {"version":3,"sources":["../../src/commerce/server.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["/**\n * @sonordev/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n * \n * All data fetching goes through the Portal API.\n */\n\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n apiUrl: string\n apiKey: string\n projectId: string\n}\n\ninterface SlugItem {\n slug: string\n}\n\n/**\n * Outcome of a server-side fetch.\n *\n * `ok` is the entire point. A helper that returns an empty array on failure lets\n * the calling page state a business fact it does not know: \"no upcoming events\",\n * \"no products available\" — when the truth is only that the API was unreachable.\n * QCR's /public-cruises told customers the business had no cruises during a\n * transient failure while three were on sale (2026-08-27).\n *\n * Branch on `ok` in new code. The legacy helpers returning a bare array or null\n * are kept for compatibility, but they cannot express this difference — an empty\n * result from them is indistinguishable from an outage.\n */\nexport interface ServerResult<T> {\n /** false = the request failed. `ok: true` with empty data means genuinely empty. */\n ok: boolean\n data: T\n}\n\n/**\n * Next throws to signal control flow, not failure — a DynamicServerError during\n * the static pass means \"this route can't be prerendered\", and redirect()/\n * notFound() throw too. Catching those and returning a failure logs a fake fetch\n * error on every build and makes a real API outage look identical to the\n * framework doing its job. Always rethrow.\n */\nfunction isFrameworkSignal(err: unknown): boolean {\n const digest = (err as { digest?: unknown } | null)?.digest\n return (\n typeof digest === 'string' &&\n (digest === 'DYNAMIC_SERVER_USAGE' || digest.startsWith('NEXT_'))\n )\n}\n\nasync function apiFetch<T>(\n config: ServerConfig,\n endpoint: string,\n): Promise<ServerResult<T | null>> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n console.error(`[site-kit/commerce] GET ${endpoint} failed: ${response.status}`)\n return { ok: false, data: null }\n }\n return { ok: true, data: (await response.json()) as T }\n } catch (error) {\n if (isFrameworkSignal(error)) throw error\n console.error(`[site-kit/commerce] GET ${endpoint} failed:`, error)\n return { ok: false, data: null }\n }\n}\n\nasync function apiPost<T>(\n config: ServerConfig,\n endpoint: string,\n body: Record<string, unknown>,\n): Promise<ServerResult<T | null>> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) {\n console.error(`[site-kit/commerce] POST ${endpoint} failed: ${response.status}`)\n return { ok: false, data: null }\n }\n return { ok: true, data: (await response.json()) as T }\n } catch (error) {\n if (isFrameworkSignal(error)) throw error\n console.error(`[site-kit/commerce] POST ${endpoint} failed:`, error)\n return { ok: false, data: null }\n }\n}\n\nfunction transformOffering(data: Record<string, unknown>): CommerceOffering {\n return {\n id: data.id as string,\n project_id: data.project_id as string,\n type: data.type as OfferingType,\n status: data.status as 'draft' | 'active' | 'archived' | 'sold_out',\n name: data.name as string,\n slug: data.slug as string,\n description: data.description as string | undefined,\n short_description: data.short_description as string | undefined,\n long_description: data.long_description as string | undefined,\n featured_image_url: data.featured_image_url as string | undefined,\n gallery_images: (data.gallery_image_urls as string[]) || [],\n price_type: (data.price_type as 'fixed' | 'variable' | 'quote' | 'free') || 'fixed',\n price: data.price as number | undefined,\n compare_at_price: data.compare_at_price as number | undefined,\n currency: (data.currency as string) || 'USD',\n price_is_public: (data.price_is_public as boolean) ?? true,\n billing_period: data.billing_period as 'weekly' | 'monthly' | 'quarterly' | 'yearly' | undefined,\n track_inventory: data.track_inventory as boolean | undefined,\n inventory_count: data.inventory_count as number | undefined,\n allow_backorder: data.allow_backorder as boolean | undefined,\n duration_minutes: data.duration_minutes as number | undefined,\n capacity: data.capacity as number | undefined,\n location: data.location as string | undefined,\n is_virtual: data.is_virtual as boolean | undefined,\n virtual_meeting_url: data.virtual_meeting_url as string | undefined,\n requires_booking: data.requires_booking as boolean | undefined,\n booking_lead_time_hours: data.booking_lead_time_hours as number | undefined,\n category: data.category as CommerceOffering['category'],\n category_id: data.category_id as string | undefined,\n tags: (data.tags as string[]) || [],\n seo_title: data.seo_title as string | undefined,\n seo_description: data.seo_description as string | undefined,\n features: (data.features as string[]) || [],\n specifications: (data.specifications as Record<string, string>) || {},\n schedules: (data.schedules as CommerceOffering['schedules']) || [],\n variants: (data.variants as CommerceOffering['variants']) || [],\n created_at: data.created_at as string,\n updated_at: data.updated_at as string,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const { ok, data } = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=product&status=active&fields=slug`\n )\n\n // A failed path fetch prerenders ZERO product pages and looks like a healthy\n // build. Say so loudly rather than shipping a site with its catalogue missing.\n if (!ok) console.error('[site-kit/commerce] getProductPaths failed — 0 product pages will be prerendered')\n if (!data?.offerings) return []\n\n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const { ok, data } = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=event&status=active&fields=slug`\n )\n\n if (!ok) console.error('[site-kit/commerce] getEventPaths failed — 0 event pages will be prerendered')\n if (!data?.offerings) return []\n\n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n let typeParam = ''\n if (type) {\n if (Array.isArray(type)) {\n typeParam = `&type=${type.join(',')}`\n } else {\n typeParam = `&type=${type}`\n }\n }\n \n const { ok, data } = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?status=active&fields=slug${typeParam}`\n )\n\n if (!ok) console.error('[site-kit/commerce] getOfferingPaths failed — 0 pages will be prerendered')\n if (!data?.offerings) return []\n\n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n return (await getOfferingBySlugResult(config, slug)).data\n}\n\n/**\n * As getOfferingBySlug, but distinguishes \"no such offering\" (ok: true, null)\n * from \"could not reach the API\" (ok: false, null). Use this before rendering a\n * 404 — a notFound() on a transient failure de-indexes a page that exists.\n */\nexport async function getOfferingBySlugResult(\n config: ServerConfig,\n slug: string\n): Promise<ServerResult<CommerceOffering | null>> {\n const { ok, data } = await apiFetch<{ offering: Record<string, unknown> }>(\n config,\n `/public/commerce/offerings/${slug}`\n )\n\n if (!data?.offering) return { ok, data: null }\n\n return { ok: true, data: transformOffering(data.offering) }\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n return (await getOfferingsResult(config, options)).data\n}\n\n/**\n * As getOfferings, but distinguishes an empty catalogue from a failed request.\n * Branch on `ok` before rendering \"nothing available\" copy.\n */\nexport async function getOfferingsResult(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<ServerResult<CommerceOffering[]>> {\n const params = new URLSearchParams()\n params.set('status', options.status || 'active')\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n params.set('type', options.type.join(','))\n } else {\n params.set('type', options.type)\n }\n }\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const { ok, data } = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n\n if (!data?.offerings) return { ok, data: [] }\n\n return { ok: true, data: data.offerings.map(transformOffering) }\n}\n\n/**\n * Fetch upcoming events (server-side), WITH schedules and category embedded.\n *\n * Uses POST /public/commerce/events — the same endpoint the client fetcher\n * uses — because the GET offerings list does NOT embed commerce_schedules,\n * which made this helper return events with empty `schedules[]` and forced\n * sites to hand-roll their own fetcher for any calendar UI (the Ludlow PTO\n * lesson). Falls back to the legacy offerings query if the events endpoint\n * is unavailable (older self-hosted API).\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n return (await getUpcomingEventsResult(config, options)).data\n}\n\n/**\n * As getUpcomingEvents, but tells you whether the list is empty because there is\n * nothing scheduled or because the API could not be reached.\n *\n * ALWAYS prefer this when the UI renders copy like \"no upcoming events\". Doing\n * otherwise is what put \"No public cruises currently on the schedule\" in front\n * of QCR's customers while three cruises were on sale — and, because the page\n * was statically revalidated, cached that claim for the whole revalidate window.\n */\nexport async function getUpcomingEventsResult(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<ServerResult<CommerceOffering[]>> {\n const primary = await apiPost<{ events: Record<string, unknown>[] }>(\n config,\n '/public/commerce/events',\n {\n type: 'event',\n category: options.category,\n limit: options.limit,\n includePast: false,\n },\n )\n\n if (primary.ok && primary.data?.events) {\n return { ok: true, data: primary.data.events.map(transformOffering) }\n }\n\n // Legacy fallback: offerings list (no schedules embedded).\n const params = new URLSearchParams()\n params.set('type', 'event')\n params.set('status', 'active')\n params.set('upcoming', 'true')\n\n if (options.category) {\n params.set('category', options.category)\n }\n\n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n\n const legacy = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n\n if (legacy.ok && legacy.data?.offerings) {\n return { ok: true, data: legacy.data.offerings.map(transformOffering) }\n }\n\n // Nothing usable came back. It is only honestly \"empty\" if at least one call\n // actually reached the API; if both failed the caller must not claim empty.\n return { ok: primary.ok || legacy.ok, data: [] }\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n return (await getNextEventResult(config, category)).data\n}\n\n/**\n * As getNextEvent, but distinguishes \"nothing scheduled\" from \"fetch failed\".\n */\nexport async function getNextEventResult(\n config: ServerConfig,\n category?: string\n): Promise<ServerResult<CommerceOffering | null>> {\n const { ok, data } = await getUpcomingEventsResult(config, { limit: 1, category })\n return { ok, data: data[0] || null }\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\n/**\n * Create a server config for API calls\n * \n * @param apiUrl - Portal API URL (e.g., 'https://api.sonor.io')\n * @param apiKey - Project API key\n * @param projectId - Project ID\n */\nexport function createServerConfig(\n apiUrl: string,\n apiKey: string,\n projectId: string\n): ServerConfig {\n return { apiUrl, apiKey, projectId }\n}\n"]}
@@ -1,6 +1,10 @@
1
1
  import '../chunk-BEXTDHO4.mjs';
2
2
 
3
3
  // src/commerce/server.ts
4
+ function isFrameworkSignal(err) {
5
+ const digest = err?.digest;
6
+ return typeof digest === "string" && (digest === "DYNAMIC_SERVER_USAGE" || digest.startsWith("NEXT_"));
7
+ }
4
8
  async function apiFetch(config, endpoint) {
5
9
  try {
6
10
  const response = await fetch(`${config.apiUrl}${endpoint}`, {
@@ -10,11 +14,15 @@ async function apiFetch(config, endpoint) {
10
14
  "Content-Type": "application/json"
11
15
  }
12
16
  });
13
- if (!response.ok) return null;
14
- return response.json();
17
+ if (!response.ok) {
18
+ console.error(`[site-kit/commerce] GET ${endpoint} failed: ${response.status}`);
19
+ return { ok: false, data: null };
20
+ }
21
+ return { ok: true, data: await response.json() };
15
22
  } catch (error) {
16
- console.error("API fetch error:", error);
17
- return null;
23
+ if (isFrameworkSignal(error)) throw error;
24
+ console.error(`[site-kit/commerce] GET ${endpoint} failed:`, error);
25
+ return { ok: false, data: null };
18
26
  }
19
27
  }
20
28
  async function apiPost(config, endpoint, body) {
@@ -28,11 +36,15 @@ async function apiPost(config, endpoint, body) {
28
36
  },
29
37
  body: JSON.stringify(body)
30
38
  });
31
- if (!response.ok) return null;
32
- return response.json();
39
+ if (!response.ok) {
40
+ console.error(`[site-kit/commerce] POST ${endpoint} failed: ${response.status}`);
41
+ return { ok: false, data: null };
42
+ }
43
+ return { ok: true, data: await response.json() };
33
44
  } catch (error) {
34
- console.error("API fetch error:", error);
35
- return null;
45
+ if (isFrameworkSignal(error)) throw error;
46
+ console.error(`[site-kit/commerce] POST ${endpoint} failed:`, error);
47
+ return { ok: false, data: null };
36
48
  }
37
49
  }
38
50
  function transformOffering(data) {
@@ -78,18 +90,20 @@ function transformOffering(data) {
78
90
  };
79
91
  }
80
92
  async function getProductPaths(config) {
81
- const data = await apiFetch(
93
+ const { ok, data } = await apiFetch(
82
94
  config,
83
95
  `/public/commerce/offerings?type=product&status=active&fields=slug`
84
96
  );
97
+ if (!ok) console.error("[site-kit/commerce] getProductPaths failed \u2014 0 product pages will be prerendered");
85
98
  if (!data?.offerings) return [];
86
99
  return data.offerings.map((item) => ({ params: { slug: item.slug } }));
87
100
  }
88
101
  async function getEventPaths(config) {
89
- const data = await apiFetch(
102
+ const { ok, data } = await apiFetch(
90
103
  config,
91
104
  `/public/commerce/offerings?type=event&status=active&fields=slug`
92
105
  );
106
+ if (!ok) console.error("[site-kit/commerce] getEventPaths failed \u2014 0 event pages will be prerendered");
93
107
  if (!data?.offerings) return [];
94
108
  return data.offerings.map((item) => ({ params: { slug: item.slug } }));
95
109
  }
@@ -102,22 +116,29 @@ async function getOfferingPaths(config, type) {
102
116
  typeParam = `&type=${type}`;
103
117
  }
104
118
  }
105
- const data = await apiFetch(
119
+ const { ok, data } = await apiFetch(
106
120
  config,
107
121
  `/public/commerce/offerings?status=active&fields=slug${typeParam}`
108
122
  );
123
+ if (!ok) console.error("[site-kit/commerce] getOfferingPaths failed \u2014 0 pages will be prerendered");
109
124
  if (!data?.offerings) return [];
110
125
  return data.offerings.map((item) => ({ params: { slug: item.slug } }));
111
126
  }
112
127
  async function getOfferingBySlug(config, slug) {
113
- const data = await apiFetch(
128
+ return (await getOfferingBySlugResult(config, slug)).data;
129
+ }
130
+ async function getOfferingBySlugResult(config, slug) {
131
+ const { ok, data } = await apiFetch(
114
132
  config,
115
133
  `/public/commerce/offerings/${slug}`
116
134
  );
117
- if (!data?.offering) return null;
118
- return transformOffering(data.offering);
135
+ if (!data?.offering) return { ok, data: null };
136
+ return { ok: true, data: transformOffering(data.offering) };
119
137
  }
120
138
  async function getOfferings(config, options = {}) {
139
+ return (await getOfferingsResult(config, options)).data;
140
+ }
141
+ async function getOfferingsResult(config, options = {}) {
121
142
  const params = new URLSearchParams();
122
143
  params.set("status", options.status || "active");
123
144
  if (options.type) {
@@ -133,15 +154,18 @@ async function getOfferings(config, options = {}) {
133
154
  if (options.limit) {
134
155
  params.set("limit", options.limit.toString());
135
156
  }
136
- const data = await apiFetch(
157
+ const { ok, data } = await apiFetch(
137
158
  config,
138
159
  `/public/commerce/offerings?${params.toString()}`
139
160
  );
140
- if (!data?.offerings) return [];
141
- return data.offerings.map(transformOffering);
161
+ if (!data?.offerings) return { ok, data: [] };
162
+ return { ok: true, data: data.offerings.map(transformOffering) };
142
163
  }
143
164
  async function getUpcomingEvents(config, options = {}) {
144
- const data = await apiPost(
165
+ return (await getUpcomingEventsResult(config, options)).data;
166
+ }
167
+ async function getUpcomingEventsResult(config, options = {}) {
168
+ const primary = await apiPost(
145
169
  config,
146
170
  "/public/commerce/events",
147
171
  {
@@ -151,8 +175,8 @@ async function getUpcomingEvents(config, options = {}) {
151
175
  includePast: false
152
176
  }
153
177
  );
154
- if (data?.events) {
155
- return data.events.map(transformOffering);
178
+ if (primary.ok && primary.data?.events) {
179
+ return { ok: true, data: primary.data.events.map(transformOffering) };
156
180
  }
157
181
  const params = new URLSearchParams();
158
182
  params.set("type", "event");
@@ -168,12 +192,17 @@ async function getUpcomingEvents(config, options = {}) {
168
192
  config,
169
193
  `/public/commerce/offerings?${params.toString()}`
170
194
  );
171
- if (!legacy?.offerings) return [];
172
- return legacy.offerings.map(transformOffering);
195
+ if (legacy.ok && legacy.data?.offerings) {
196
+ return { ok: true, data: legacy.data.offerings.map(transformOffering) };
197
+ }
198
+ return { ok: primary.ok || legacy.ok, data: [] };
173
199
  }
174
200
  async function getNextEvent(config, category) {
175
- const events = await getUpcomingEvents(config, { limit: 1, category });
176
- return events[0] || null;
201
+ return (await getNextEventResult(config, category)).data;
202
+ }
203
+ async function getNextEventResult(config, category) {
204
+ const { ok, data } = await getUpcomingEventsResult(config, { limit: 1, category });
205
+ return { ok, data: data[0] || null };
177
206
  }
178
207
  function generateOfferingMetadata(offering, siteUrl) {
179
208
  if (!offering) return null;
@@ -203,6 +232,6 @@ function createServerConfig(apiUrl, apiKey, projectId) {
203
232
  return { apiUrl, apiKey, projectId };
204
233
  }
205
234
 
206
- export { createServerConfig, generateOfferingMetadata, getEventPaths, getNextEvent, getOfferingBySlug, getOfferingPaths, getOfferings, getProductPaths, getUpcomingEvents };
235
+ export { createServerConfig, generateOfferingMetadata, getEventPaths, getNextEvent, getNextEventResult, getOfferingBySlug, getOfferingBySlugResult, getOfferingPaths, getOfferings, getOfferingsResult, getProductPaths, getUpcomingEvents, getUpcomingEventsResult };
207
236
  //# sourceMappingURL=server.mjs.map
208
237
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commerce/server.ts"],"names":[],"mappings":"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","file":"server.mjs","sourcesContent":["/**\n * @sonordev/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n * \n * All data fetching goes through the Portal API.\n */\n\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n apiUrl: string\n apiKey: string\n projectId: string\n}\n\ninterface SlugItem {\n slug: string\n}\n\nasync function apiFetch<T>(config: ServerConfig, endpoint: string): Promise<T | null> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) return null\n return response.json()\n } catch (error) {\n console.error('API fetch error:', error)\n return null\n }\n}\n\nasync function apiPost<T>(\n config: ServerConfig,\n endpoint: string,\n body: Record<string, unknown>,\n): Promise<T | null> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) return null\n return response.json()\n } catch (error) {\n console.error('API fetch error:', error)\n return null\n }\n}\n\nfunction transformOffering(data: Record<string, unknown>): CommerceOffering {\n return {\n id: data.id as string,\n project_id: data.project_id as string,\n type: data.type as OfferingType,\n status: data.status as 'draft' | 'active' | 'archived' | 'sold_out',\n name: data.name as string,\n slug: data.slug as string,\n description: data.description as string | undefined,\n short_description: data.short_description as string | undefined,\n long_description: data.long_description as string | undefined,\n featured_image_url: data.featured_image_url as string | undefined,\n gallery_images: (data.gallery_image_urls as string[]) || [],\n price_type: (data.price_type as 'fixed' | 'variable' | 'quote' | 'free') || 'fixed',\n price: data.price as number | undefined,\n compare_at_price: data.compare_at_price as number | undefined,\n currency: (data.currency as string) || 'USD',\n price_is_public: (data.price_is_public as boolean) ?? true,\n billing_period: data.billing_period as 'weekly' | 'monthly' | 'quarterly' | 'yearly' | undefined,\n track_inventory: data.track_inventory as boolean | undefined,\n inventory_count: data.inventory_count as number | undefined,\n allow_backorder: data.allow_backorder as boolean | undefined,\n duration_minutes: data.duration_minutes as number | undefined,\n capacity: data.capacity as number | undefined,\n location: data.location as string | undefined,\n is_virtual: data.is_virtual as boolean | undefined,\n virtual_meeting_url: data.virtual_meeting_url as string | undefined,\n requires_booking: data.requires_booking as boolean | undefined,\n booking_lead_time_hours: data.booking_lead_time_hours as number | undefined,\n category: data.category as CommerceOffering['category'],\n category_id: data.category_id as string | undefined,\n tags: (data.tags as string[]) || [],\n seo_title: data.seo_title as string | undefined,\n seo_description: data.seo_description as string | undefined,\n features: (data.features as string[]) || [],\n specifications: (data.specifications as Record<string, string>) || {},\n schedules: (data.schedules as CommerceOffering['schedules']) || [],\n variants: (data.variants as CommerceOffering['variants']) || [],\n created_at: data.created_at as string,\n updated_at: data.updated_at as string,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=product&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=event&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n let typeParam = ''\n if (type) {\n if (Array.isArray(type)) {\n typeParam = `&type=${type.join(',')}`\n } else {\n typeParam = `&type=${type}`\n }\n }\n \n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?status=active&fields=slug${typeParam}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n const data = await apiFetch<{ offering: Record<string, unknown> }>(\n config,\n `/public/commerce/offerings/${slug}`\n )\n \n if (!data?.offering) return null\n \n return transformOffering(data.offering)\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n const params = new URLSearchParams()\n params.set('status', options.status || 'active')\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n params.set('type', options.type.join(','))\n } else {\n params.set('type', options.type)\n }\n }\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const data = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map(transformOffering)\n}\n\n/**\n * Fetch upcoming events (server-side), WITH schedules and category embedded.\n *\n * Uses POST /public/commerce/events — the same endpoint the client fetcher\n * uses — because the GET offerings list does NOT embed commerce_schedules,\n * which made this helper return events with empty `schedules[]` and forced\n * sites to hand-roll their own fetcher for any calendar UI (the Ludlow PTO\n * lesson). Falls back to the legacy offerings query if the events endpoint\n * is unavailable (older self-hosted API).\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n const data = await apiPost<{ events: Record<string, unknown>[] }>(\n config,\n '/public/commerce/events',\n {\n type: 'event',\n category: options.category,\n limit: options.limit,\n includePast: false,\n },\n )\n\n if (data?.events) {\n return data.events.map(transformOffering)\n }\n\n // Legacy fallback: offerings list (no schedules embedded).\n const params = new URLSearchParams()\n params.set('type', 'event')\n params.set('status', 'active')\n params.set('upcoming', 'true')\n\n if (options.category) {\n params.set('category', options.category)\n }\n\n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n\n const legacy = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n\n if (!legacy?.offerings) return []\n\n return legacy.offerings.map(transformOffering)\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n const events = await getUpcomingEvents(config, { limit: 1, category })\n return events[0] || null\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\n/**\n * Create a server config for API calls\n * \n * @param apiUrl - Portal API URL (e.g., 'https://api.sonor.io')\n * @param apiKey - Project API key\n * @param projectId - Project ID\n */\nexport function createServerConfig(\n apiUrl: string,\n apiKey: string,\n projectId: string\n): ServerConfig {\n return { apiUrl, apiKey, projectId }\n}\n"]}
1
+ {"version":3,"sources":["../../src/commerce/server.ts"],"names":[],"mappings":"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","file":"server.mjs","sourcesContent":["/**\n * @sonordev/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n * \n * All data fetching goes through the Portal API.\n */\n\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n apiUrl: string\n apiKey: string\n projectId: string\n}\n\ninterface SlugItem {\n slug: string\n}\n\n/**\n * Outcome of a server-side fetch.\n *\n * `ok` is the entire point. A helper that returns an empty array on failure lets\n * the calling page state a business fact it does not know: \"no upcoming events\",\n * \"no products available\" — when the truth is only that the API was unreachable.\n * QCR's /public-cruises told customers the business had no cruises during a\n * transient failure while three were on sale (2026-08-27).\n *\n * Branch on `ok` in new code. The legacy helpers returning a bare array or null\n * are kept for compatibility, but they cannot express this difference — an empty\n * result from them is indistinguishable from an outage.\n */\nexport interface ServerResult<T> {\n /** false = the request failed. `ok: true` with empty data means genuinely empty. */\n ok: boolean\n data: T\n}\n\n/**\n * Next throws to signal control flow, not failure — a DynamicServerError during\n * the static pass means \"this route can't be prerendered\", and redirect()/\n * notFound() throw too. Catching those and returning a failure logs a fake fetch\n * error on every build and makes a real API outage look identical to the\n * framework doing its job. Always rethrow.\n */\nfunction isFrameworkSignal(err: unknown): boolean {\n const digest = (err as { digest?: unknown } | null)?.digest\n return (\n typeof digest === 'string' &&\n (digest === 'DYNAMIC_SERVER_USAGE' || digest.startsWith('NEXT_'))\n )\n}\n\nasync function apiFetch<T>(\n config: ServerConfig,\n endpoint: string,\n): Promise<ServerResult<T | null>> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n console.error(`[site-kit/commerce] GET ${endpoint} failed: ${response.status}`)\n return { ok: false, data: null }\n }\n return { ok: true, data: (await response.json()) as T }\n } catch (error) {\n if (isFrameworkSignal(error)) throw error\n console.error(`[site-kit/commerce] GET ${endpoint} failed:`, error)\n return { ok: false, data: null }\n }\n}\n\nasync function apiPost<T>(\n config: ServerConfig,\n endpoint: string,\n body: Record<string, unknown>,\n): Promise<ServerResult<T | null>> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) {\n console.error(`[site-kit/commerce] POST ${endpoint} failed: ${response.status}`)\n return { ok: false, data: null }\n }\n return { ok: true, data: (await response.json()) as T }\n } catch (error) {\n if (isFrameworkSignal(error)) throw error\n console.error(`[site-kit/commerce] POST ${endpoint} failed:`, error)\n return { ok: false, data: null }\n }\n}\n\nfunction transformOffering(data: Record<string, unknown>): CommerceOffering {\n return {\n id: data.id as string,\n project_id: data.project_id as string,\n type: data.type as OfferingType,\n status: data.status as 'draft' | 'active' | 'archived' | 'sold_out',\n name: data.name as string,\n slug: data.slug as string,\n description: data.description as string | undefined,\n short_description: data.short_description as string | undefined,\n long_description: data.long_description as string | undefined,\n featured_image_url: data.featured_image_url as string | undefined,\n gallery_images: (data.gallery_image_urls as string[]) || [],\n price_type: (data.price_type as 'fixed' | 'variable' | 'quote' | 'free') || 'fixed',\n price: data.price as number | undefined,\n compare_at_price: data.compare_at_price as number | undefined,\n currency: (data.currency as string) || 'USD',\n price_is_public: (data.price_is_public as boolean) ?? true,\n billing_period: data.billing_period as 'weekly' | 'monthly' | 'quarterly' | 'yearly' | undefined,\n track_inventory: data.track_inventory as boolean | undefined,\n inventory_count: data.inventory_count as number | undefined,\n allow_backorder: data.allow_backorder as boolean | undefined,\n duration_minutes: data.duration_minutes as number | undefined,\n capacity: data.capacity as number | undefined,\n location: data.location as string | undefined,\n is_virtual: data.is_virtual as boolean | undefined,\n virtual_meeting_url: data.virtual_meeting_url as string | undefined,\n requires_booking: data.requires_booking as boolean | undefined,\n booking_lead_time_hours: data.booking_lead_time_hours as number | undefined,\n category: data.category as CommerceOffering['category'],\n category_id: data.category_id as string | undefined,\n tags: (data.tags as string[]) || [],\n seo_title: data.seo_title as string | undefined,\n seo_description: data.seo_description as string | undefined,\n features: (data.features as string[]) || [],\n specifications: (data.specifications as Record<string, string>) || {},\n schedules: (data.schedules as CommerceOffering['schedules']) || [],\n variants: (data.variants as CommerceOffering['variants']) || [],\n created_at: data.created_at as string,\n updated_at: data.updated_at as string,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const { ok, data } = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=product&status=active&fields=slug`\n )\n\n // A failed path fetch prerenders ZERO product pages and looks like a healthy\n // build. Say so loudly rather than shipping a site with its catalogue missing.\n if (!ok) console.error('[site-kit/commerce] getProductPaths failed — 0 product pages will be prerendered')\n if (!data?.offerings) return []\n\n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const { ok, data } = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=event&status=active&fields=slug`\n )\n\n if (!ok) console.error('[site-kit/commerce] getEventPaths failed — 0 event pages will be prerendered')\n if (!data?.offerings) return []\n\n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n let typeParam = ''\n if (type) {\n if (Array.isArray(type)) {\n typeParam = `&type=${type.join(',')}`\n } else {\n typeParam = `&type=${type}`\n }\n }\n \n const { ok, data } = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?status=active&fields=slug${typeParam}`\n )\n\n if (!ok) console.error('[site-kit/commerce] getOfferingPaths failed — 0 pages will be prerendered')\n if (!data?.offerings) return []\n\n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n return (await getOfferingBySlugResult(config, slug)).data\n}\n\n/**\n * As getOfferingBySlug, but distinguishes \"no such offering\" (ok: true, null)\n * from \"could not reach the API\" (ok: false, null). Use this before rendering a\n * 404 — a notFound() on a transient failure de-indexes a page that exists.\n */\nexport async function getOfferingBySlugResult(\n config: ServerConfig,\n slug: string\n): Promise<ServerResult<CommerceOffering | null>> {\n const { ok, data } = await apiFetch<{ offering: Record<string, unknown> }>(\n config,\n `/public/commerce/offerings/${slug}`\n )\n\n if (!data?.offering) return { ok, data: null }\n\n return { ok: true, data: transformOffering(data.offering) }\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n return (await getOfferingsResult(config, options)).data\n}\n\n/**\n * As getOfferings, but distinguishes an empty catalogue from a failed request.\n * Branch on `ok` before rendering \"nothing available\" copy.\n */\nexport async function getOfferingsResult(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<ServerResult<CommerceOffering[]>> {\n const params = new URLSearchParams()\n params.set('status', options.status || 'active')\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n params.set('type', options.type.join(','))\n } else {\n params.set('type', options.type)\n }\n }\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const { ok, data } = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n\n if (!data?.offerings) return { ok, data: [] }\n\n return { ok: true, data: data.offerings.map(transformOffering) }\n}\n\n/**\n * Fetch upcoming events (server-side), WITH schedules and category embedded.\n *\n * Uses POST /public/commerce/events — the same endpoint the client fetcher\n * uses — because the GET offerings list does NOT embed commerce_schedules,\n * which made this helper return events with empty `schedules[]` and forced\n * sites to hand-roll their own fetcher for any calendar UI (the Ludlow PTO\n * lesson). Falls back to the legacy offerings query if the events endpoint\n * is unavailable (older self-hosted API).\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n return (await getUpcomingEventsResult(config, options)).data\n}\n\n/**\n * As getUpcomingEvents, but tells you whether the list is empty because there is\n * nothing scheduled or because the API could not be reached.\n *\n * ALWAYS prefer this when the UI renders copy like \"no upcoming events\". Doing\n * otherwise is what put \"No public cruises currently on the schedule\" in front\n * of QCR's customers while three cruises were on sale — and, because the page\n * was statically revalidated, cached that claim for the whole revalidate window.\n */\nexport async function getUpcomingEventsResult(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<ServerResult<CommerceOffering[]>> {\n const primary = await apiPost<{ events: Record<string, unknown>[] }>(\n config,\n '/public/commerce/events',\n {\n type: 'event',\n category: options.category,\n limit: options.limit,\n includePast: false,\n },\n )\n\n if (primary.ok && primary.data?.events) {\n return { ok: true, data: primary.data.events.map(transformOffering) }\n }\n\n // Legacy fallback: offerings list (no schedules embedded).\n const params = new URLSearchParams()\n params.set('type', 'event')\n params.set('status', 'active')\n params.set('upcoming', 'true')\n\n if (options.category) {\n params.set('category', options.category)\n }\n\n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n\n const legacy = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n\n if (legacy.ok && legacy.data?.offerings) {\n return { ok: true, data: legacy.data.offerings.map(transformOffering) }\n }\n\n // Nothing usable came back. It is only honestly \"empty\" if at least one call\n // actually reached the API; if both failed the caller must not claim empty.\n return { ok: primary.ok || legacy.ok, data: [] }\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n return (await getNextEventResult(config, category)).data\n}\n\n/**\n * As getNextEvent, but distinguishes \"nothing scheduled\" from \"fetch failed\".\n */\nexport async function getNextEventResult(\n config: ServerConfig,\n category?: string\n): Promise<ServerResult<CommerceOffering | null>> {\n const { ok, data } = await getUpcomingEventsResult(config, { limit: 1, category })\n return { ok, data: data[0] || null }\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\n/**\n * Create a server config for API calls\n * \n * @param apiUrl - Portal API URL (e.g., 'https://api.sonor.io')\n * @param apiKey - Project API key\n * @param projectId - Project ID\n */\nexport function createServerConfig(\n apiUrl: string,\n apiKey: string,\n projectId: string\n): ServerConfig {\n return { apiUrl, apiKey, projectId }\n}\n"]}
@@ -1,16 +1,16 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkIX5RAZWX_js = require('../chunk-IX5RAZWX.js');
5
- var chunk5OHHYGD6_js = require('../chunk-5OHHYGD6.js');
6
- require('../chunk-5JQLLF2T.js');
7
- require('../chunk-62ODUWUX.js');
4
+ var chunkKMNIW4K4_js = require('../chunk-KMNIW4K4.js');
5
+ var chunkOQBDJRVP_js = require('../chunk-OQBDJRVP.js');
6
+ require('../chunk-XYZZJZGS.js');
7
+ require('../chunk-LFBMFACZ.js');
8
8
  require('../chunk-KHPJ3CEL.js');
9
9
  require('../chunk-RC4WWQXR.js');
10
10
  require('../chunk-VJMPIRSD.js');
11
- require('../chunk-4D2G5ZNP.js');
12
- require('../chunk-FQ3JQV3M.js');
13
- require('../chunk-S65JSRWW.js');
11
+ require('../chunk-RMLRZOVE.js');
12
+ require('../chunk-7NMI7M56.js');
13
+ require('../chunk-BIZT7AYK.js');
14
14
  require('../chunk-SNAQBZPT.js');
15
15
 
16
16
  // src/engage/echo-config.ts
@@ -40,17 +40,17 @@ function getEchoWidgetProps(config = SONOR_PUBLIC_ECHO_DEFAULTS) {
40
40
  };
41
41
  }
42
42
 
43
- Object.defineProperty(exports, "DesignRenderer", {
43
+ Object.defineProperty(exports, "ChatWidget", {
44
44
  enumerable: true,
45
- get: function () { return chunkIX5RAZWX_js.DesignRenderer; }
45
+ get: function () { return chunkKMNIW4K4_js.ChatWidget; }
46
46
  });
47
- Object.defineProperty(exports, "EngageWidget", {
47
+ Object.defineProperty(exports, "DesignRenderer", {
48
48
  enumerable: true,
49
- get: function () { return chunkIX5RAZWX_js.EngageWidget; }
49
+ get: function () { return chunkOQBDJRVP_js.DesignRenderer; }
50
50
  });
51
- Object.defineProperty(exports, "ChatWidget", {
51
+ Object.defineProperty(exports, "EngageWidget", {
52
52
  enumerable: true,
53
- get: function () { return chunk5OHHYGD6_js.ChatWidget; }
53
+ get: function () { return chunkOQBDJRVP_js.EngageWidget; }
54
54
  });
55
55
  exports.SONOR_PUBLIC_ECHO_DEFAULTS = SONOR_PUBLIC_ECHO_DEFAULTS;
56
56
  exports.getEchoWidgetProps = getEchoWidgetProps;
@@ -1,14 +1,14 @@
1
1
  'use client';
2
- export { DesignRenderer, EngageWidget } from '../chunk-QI2H5KK6.mjs';
3
- export { ChatWidget } from '../chunk-SXPINIJG.mjs';
4
- import '../chunk-YVE65W47.mjs';
5
- import '../chunk-UFURXSAI.mjs';
2
+ export { ChatWidget } from '../chunk-BAFGZQWP.mjs';
3
+ export { DesignRenderer, EngageWidget } from '../chunk-YUOVAWCL.mjs';
4
+ import '../chunk-KHHMU4UH.mjs';
5
+ import '../chunk-ITV76G3L.mjs';
6
6
  import '../chunk-TMVKRQGJ.mjs';
7
7
  import '../chunk-ZZQAGCSI.mjs';
8
8
  import '../chunk-6EDVCUAG.mjs';
9
- import '../chunk-4UHO6DPJ.mjs';
10
- import '../chunk-FDWDXMJL.mjs';
11
- import '../chunk-JPTJGLKS.mjs';
9
+ import '../chunk-F4DZH4E5.mjs';
10
+ import '../chunk-HHX72A2B.mjs';
11
+ import '../chunk-3PTKHSF7.mjs';
12
12
  import '../chunk-BEXTDHO4.mjs';
13
13
 
14
14
  // src/engage/echo-config.ts
@@ -1,31 +1,31 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkLLKXPJSE_js = require('../chunk-LLKXPJSE.js');
4
+ var chunkGF7CQMBL_js = require('../chunk-GF7CQMBL.js');
5
5
  var chunkQ2NBD54V_js = require('../chunk-Q2NBD54V.js');
6
6
  require('../chunk-HGNSJXWT.js');
7
- require('../chunk-4D2G5ZNP.js');
8
- require('../chunk-FQ3JQV3M.js');
9
- require('../chunk-S65JSRWW.js');
7
+ require('../chunk-RMLRZOVE.js');
8
+ require('../chunk-7NMI7M56.js');
9
+ require('../chunk-BIZT7AYK.js');
10
10
  require('../chunk-SNAQBZPT.js');
11
11
 
12
12
 
13
13
 
14
14
  Object.defineProperty(exports, "FLEET_HEARTBEAT_PATH", {
15
15
  enumerable: true,
16
- get: function () { return chunkLLKXPJSE_js.FLEET_HEARTBEAT_PATH; }
16
+ get: function () { return chunkGF7CQMBL_js.FLEET_HEARTBEAT_PATH; }
17
17
  });
18
18
  Object.defineProperty(exports, "FleetHeartbeat", {
19
19
  enumerable: true,
20
- get: function () { return chunkLLKXPJSE_js.FleetHeartbeat; }
20
+ get: function () { return chunkGF7CQMBL_js.FleetHeartbeat; }
21
21
  });
22
22
  Object.defineProperty(exports, "detectNextVersion", {
23
23
  enumerable: true,
24
- get: function () { return chunkLLKXPJSE_js.detectNextVersion; }
24
+ get: function () { return chunkGF7CQMBL_js.detectNextVersion; }
25
25
  });
26
26
  Object.defineProperty(exports, "sendFleetHeartbeat", {
27
27
  enumerable: true,
28
- get: function () { return chunkLLKXPJSE_js.sendFleetHeartbeat; }
28
+ get: function () { return chunkGF7CQMBL_js.sendFleetHeartbeat; }
29
29
  });
30
30
  Object.defineProperty(exports, "FLEET_CONTRACT_VERSION", {
31
31
  enumerable: true,
@@ -1,10 +1,10 @@
1
1
  'use client';
2
- export { FLEET_HEARTBEAT_PATH, FleetHeartbeat, detectNextVersion, sendFleetHeartbeat } from '../chunk-QH3WVTEK.mjs';
2
+ export { FLEET_HEARTBEAT_PATH, FleetHeartbeat, detectNextVersion, sendFleetHeartbeat } from '../chunk-FDLFXHUU.mjs';
3
3
  export { FLEET_CONTRACT_VERSION, FLEET_MODULES, FLEET_MODULES_MAX, FLEET_SITE_MAX_LENGTH, FLEET_VERSION_MAX_LENGTH, FLEET_VERSION_PATTERN, buildFleetHeartbeatPayload, isFleetModule, normalizeFleetModules, normalizeFleetSite, sanitizeFleetVersion } from '../chunk-ZPLN537Q.mjs';
4
4
  import '../chunk-ZVBLXXNJ.mjs';
5
- import '../chunk-4UHO6DPJ.mjs';
6
- import '../chunk-FDWDXMJL.mjs';
7
- import '../chunk-JPTJGLKS.mjs';
5
+ import '../chunk-F4DZH4E5.mjs';
6
+ import '../chunk-HHX72A2B.mjs';
7
+ import '../chunk-3PTKHSF7.mjs';
8
8
  import '../chunk-BEXTDHO4.mjs';
9
9
  //# sourceMappingURL=index.mjs.map
10
10
  //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Reads the visitor's GA4 identity out of their own first-party cookies so a
3
+ * lead conversion can be reported SERVER-side.
4
+ *
5
+ * Why the server has to do the reporting: Sonor's form-submit endpoint answers
6
+ * with a byte-identical success payload whether it accepted a submission or
7
+ * quarantined it as spam (deliberately — a bot must never learn it was
8
+ * caught). So the browser cannot tell a real lead from a filtered one, and a
9
+ * site firing its own ad conversion bills both. The accept/reject verdict only
10
+ * exists on the server, so the conversion has to be sent from there — and to
11
+ * send it, the server needs the GA4 identity that only the browser can see.
12
+ *
13
+ * Nothing here is a new identifier: these are cookies Google's own tag already
14
+ * set on this visitor. We read them, we never write them.
15
+ */
16
+ export interface Ga4Identity {
17
+ /** GA4 client id, from `_ga`. Without it a server-sent event has no identity. */
18
+ gaClientId?: string;
19
+ /**
20
+ * GA4 session ids keyed by container id (the measurement id minus `G-`), from
21
+ * the `_ga_<CONTAINER>` cookies.
22
+ *
23
+ * A map rather than one value because a page may carry more than one GA4
24
+ * property, and picking the wrong one would silently attach the lead to the
25
+ * wrong session — the sender knows which measurement id it is configured for,
26
+ * this side does not.
27
+ */
28
+ gaSessions?: Record<string, string>;
29
+ }
30
+ export declare function readGa4Identity(): Ga4Identity;
31
+ //# sourceMappingURL=ga4-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ga4-identity.d.ts","sourceRoot":"","sources":["../../src/forms/ga4-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACpC;AAQD,wBAAgB,eAAe,IAAI,WAAW,CAkC7C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ga4-identity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ga4-identity.test.d.ts","sourceRoot":"","sources":["../../src/forms/ga4-identity.test.ts"],"names":[],"mappings":""}