@burdenoff/website-sdk 2026.1031.3 → 2026.1101.2

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 (274) hide show
  1. package/README.md +42 -8
  2. package/dist/analytics/index.js +19 -69
  3. package/dist/analytics/index.js.map +1 -1
  4. package/dist/analytics/index.mjs +3 -69
  5. package/dist/analytics/index.mjs.map +1 -1
  6. package/dist/avatar-live/index.js +1 -0
  7. package/dist/avatar-live/index.js.map +1 -1
  8. package/dist/avatar-live/index.mjs +1 -0
  9. package/dist/avatar-live/index.mjs.map +1 -1
  10. package/dist/avatar-live-view/index.js +10 -30
  11. package/dist/avatar-live-view/index.js.map +1 -1
  12. package/dist/avatar-live-view/index.mjs +4 -24
  13. package/dist/avatar-live-view/index.mjs.map +1 -1
  14. package/dist/chunk-23H4JUL4.js +41 -0
  15. package/dist/chunk-23H4JUL4.js.map +1 -0
  16. package/dist/chunk-34RX5P75.mjs +25 -0
  17. package/dist/chunk-34RX5P75.mjs.map +1 -0
  18. package/dist/chunk-3LFFY7AZ.js +184 -0
  19. package/dist/chunk-3LFFY7AZ.js.map +1 -0
  20. package/dist/chunk-3X26GE4S.js +2794 -0
  21. package/dist/chunk-3X26GE4S.js.map +1 -0
  22. package/dist/chunk-45GCA4GG.js +85 -0
  23. package/dist/chunk-45GCA4GG.js.map +1 -0
  24. package/dist/chunk-4SAGVLHN.js +876 -0
  25. package/dist/chunk-4SAGVLHN.js.map +1 -0
  26. package/dist/chunk-4U6YAII5.js +218 -0
  27. package/dist/chunk-4U6YAII5.js.map +1 -0
  28. package/dist/chunk-5GMTBOO6.js +21 -0
  29. package/dist/chunk-5GMTBOO6.js.map +1 -0
  30. package/dist/chunk-5JRJ57CL.mjs +329 -0
  31. package/dist/chunk-5JRJ57CL.mjs.map +1 -0
  32. package/dist/chunk-6C2DKIC7.js +4 -0
  33. package/dist/chunk-6C2DKIC7.js.map +1 -0
  34. package/dist/chunk-6IBFBWC5.mjs +17 -0
  35. package/dist/chunk-6IBFBWC5.mjs.map +1 -0
  36. package/dist/chunk-6KY2ZRVI.js +116 -0
  37. package/dist/chunk-6KY2ZRVI.js.map +1 -0
  38. package/dist/chunk-6VJT3SM4.mjs +182 -0
  39. package/dist/chunk-6VJT3SM4.mjs.map +1 -0
  40. package/dist/chunk-6YZUFMK2.mjs +40 -0
  41. package/dist/chunk-6YZUFMK2.mjs.map +1 -0
  42. package/dist/chunk-7A6R7CGG.js +47 -0
  43. package/dist/chunk-7A6R7CGG.js.map +1 -0
  44. package/dist/chunk-7PWL4V2R.js +4 -0
  45. package/dist/chunk-7PWL4V2R.js.map +1 -0
  46. package/dist/chunk-AA33WDYS.js +161 -0
  47. package/dist/chunk-AA33WDYS.js.map +1 -0
  48. package/dist/chunk-AHRGFXV2.js +525 -0
  49. package/dist/chunk-AHRGFXV2.js.map +1 -0
  50. package/dist/chunk-B63XLDZH.mjs +109 -0
  51. package/dist/chunk-B63XLDZH.mjs.map +1 -0
  52. package/dist/chunk-BX2USEWF.mjs +35 -0
  53. package/dist/chunk-BX2USEWF.mjs.map +1 -0
  54. package/dist/chunk-BYSZT35R.js +150 -0
  55. package/dist/chunk-BYSZT35R.js.map +1 -0
  56. package/dist/chunk-C6OJIHNO.js +12 -0
  57. package/dist/chunk-C6OJIHNO.js.map +1 -0
  58. package/dist/chunk-COOELBX7.mjs +63 -0
  59. package/dist/chunk-COOELBX7.mjs.map +1 -0
  60. package/dist/chunk-D2TW7MNC.mjs +2771 -0
  61. package/dist/chunk-D2TW7MNC.mjs.map +1 -0
  62. package/dist/chunk-D5KEZ6V6.mjs +3 -0
  63. package/dist/chunk-D5KEZ6V6.mjs.map +1 -0
  64. package/dist/chunk-E3GUGJMY.js +46 -0
  65. package/dist/chunk-E3GUGJMY.js.map +1 -0
  66. package/dist/chunk-EBZ2HGJ2.mjs +52 -0
  67. package/dist/chunk-EBZ2HGJ2.mjs.map +1 -0
  68. package/dist/chunk-EDLTUOIA.mjs +210 -0
  69. package/dist/chunk-EDLTUOIA.mjs.map +1 -0
  70. package/dist/chunk-EJQSOT4X.js +4 -0
  71. package/dist/chunk-EJQSOT4X.js.map +1 -0
  72. package/dist/chunk-EUPFS6MZ.mjs +2019 -0
  73. package/dist/chunk-EUPFS6MZ.mjs.map +1 -0
  74. package/dist/chunk-F3XWDC3B.js +77 -0
  75. package/dist/chunk-F3XWDC3B.js.map +1 -0
  76. package/dist/chunk-FFADMVIK.mjs +5127 -0
  77. package/dist/chunk-FFADMVIK.mjs.map +1 -0
  78. package/dist/chunk-FJWS7BKT.mjs +3 -0
  79. package/dist/chunk-FJWS7BKT.mjs.map +1 -0
  80. package/dist/chunk-FJZJDUOR.mjs +3 -0
  81. package/dist/chunk-FJZJDUOR.mjs.map +1 -0
  82. package/dist/chunk-GCFLCO2Z.mjs +145 -0
  83. package/dist/chunk-GCFLCO2Z.mjs.map +1 -0
  84. package/dist/chunk-GEXC4LRP.js +61 -0
  85. package/dist/chunk-GEXC4LRP.js.map +1 -0
  86. package/dist/chunk-GTRAXQGC.mjs +3 -0
  87. package/dist/chunk-GTRAXQGC.mjs.map +1 -0
  88. package/dist/chunk-IKOIRUKW.js +270 -0
  89. package/dist/chunk-IKOIRUKW.js.map +1 -0
  90. package/dist/chunk-IXTWOPRN.js +45 -0
  91. package/dist/chunk-IXTWOPRN.js.map +1 -0
  92. package/dist/chunk-JDXOXGOK.js +547 -0
  93. package/dist/chunk-JDXOXGOK.js.map +1 -0
  94. package/dist/chunk-JSLDWYV7.mjs +558 -0
  95. package/dist/chunk-JSLDWYV7.mjs.map +1 -0
  96. package/dist/chunk-JXLSTVBK.js +336 -0
  97. package/dist/chunk-JXLSTVBK.js.map +1 -0
  98. package/dist/chunk-KHYXK7FG.mjs +49 -0
  99. package/dist/chunk-KHYXK7FG.mjs.map +1 -0
  100. package/dist/chunk-KSMBOWQQ.js +2034 -0
  101. package/dist/chunk-KSMBOWQQ.js.map +1 -0
  102. package/dist/chunk-KU2PXHGB.mjs +83 -0
  103. package/dist/chunk-KU2PXHGB.mjs.map +1 -0
  104. package/dist/chunk-KZANIV3S.mjs +37 -0
  105. package/dist/chunk-KZANIV3S.mjs.map +1 -0
  106. package/dist/chunk-L4BP6YOB.js +20 -0
  107. package/dist/chunk-L4BP6YOB.js.map +1 -0
  108. package/dist/chunk-MRKA2OAF.mjs +75 -0
  109. package/dist/chunk-MRKA2OAF.mjs.map +1 -0
  110. package/dist/chunk-N5EC53MH.mjs +80 -0
  111. package/dist/chunk-N5EC53MH.mjs.map +1 -0
  112. package/dist/chunk-NZANQGDM.mjs +34 -0
  113. package/dist/chunk-NZANQGDM.mjs.map +1 -0
  114. package/dist/chunk-O4GS3XPZ.js +10 -0
  115. package/dist/chunk-O4GS3XPZ.js.map +1 -0
  116. package/dist/chunk-O76QDGRM.js +5154 -0
  117. package/dist/chunk-O76QDGRM.js.map +1 -0
  118. package/dist/chunk-OYEUNZJY.js +114 -0
  119. package/dist/chunk-OYEUNZJY.js.map +1 -0
  120. package/dist/chunk-PHXAGQNB.js +74 -0
  121. package/dist/chunk-PHXAGQNB.js.map +1 -0
  122. package/dist/chunk-PIHHPP7J.mjs +16 -0
  123. package/dist/chunk-PIHHPP7J.mjs.map +1 -0
  124. package/dist/chunk-PXRHVVOU.mjs +499 -0
  125. package/dist/chunk-PXRHVVOU.mjs.map +1 -0
  126. package/dist/chunk-QMA6U6AU.js +36 -0
  127. package/dist/chunk-QMA6U6AU.js.map +1 -0
  128. package/dist/chunk-R6J7IULF.js +44 -0
  129. package/dist/chunk-R6J7IULF.js.map +1 -0
  130. package/dist/chunk-R7G6TWIS.mjs +10 -0
  131. package/dist/chunk-R7G6TWIS.mjs.map +1 -0
  132. package/dist/chunk-RUMGFI6L.mjs +544 -0
  133. package/dist/chunk-RUMGFI6L.mjs.map +1 -0
  134. package/dist/chunk-S54JWSJF.js +565 -0
  135. package/dist/chunk-S54JWSJF.js.map +1 -0
  136. package/dist/chunk-SK5UGG6A.js +2041 -0
  137. package/dist/chunk-SK5UGG6A.js.map +1 -0
  138. package/dist/chunk-SKIYDKIS.mjs +70 -0
  139. package/dist/chunk-SKIYDKIS.mjs.map +1 -0
  140. package/dist/chunk-SZNS5IK6.mjs +322 -0
  141. package/dist/chunk-SZNS5IK6.mjs.map +1 -0
  142. package/dist/chunk-T7JIPZAC.js +66 -0
  143. package/dist/chunk-T7JIPZAC.js.map +1 -0
  144. package/dist/chunk-TGYQHO2E.mjs +864 -0
  145. package/dist/chunk-TGYQHO2E.mjs.map +1 -0
  146. package/dist/chunk-TT3MHN42.mjs +8 -0
  147. package/dist/chunk-TT3MHN42.mjs.map +1 -0
  148. package/dist/chunk-UM55U65W.mjs +268 -0
  149. package/dist/chunk-UM55U65W.mjs.map +1 -0
  150. package/dist/chunk-UQ2HALUD.js +72 -0
  151. package/dist/chunk-UQ2HALUD.js.map +1 -0
  152. package/dist/chunk-UXWT7G77.js +82 -0
  153. package/dist/chunk-UXWT7G77.js.map +1 -0
  154. package/dist/chunk-VNS5WDWO.mjs +7 -0
  155. package/dist/chunk-VNS5WDWO.mjs.map +1 -0
  156. package/dist/chunk-VRWZLGR7.js +4 -0
  157. package/dist/chunk-VRWZLGR7.js.map +1 -0
  158. package/dist/chunk-VZLDSNH4.mjs +22 -0
  159. package/dist/chunk-VZLDSNH4.mjs.map +1 -0
  160. package/dist/chunk-W6P3YETJ.js +92 -0
  161. package/dist/chunk-W6P3YETJ.js.map +1 -0
  162. package/dist/chunk-WPKFFQCR.mjs +90 -0
  163. package/dist/chunk-WPKFFQCR.mjs.map +1 -0
  164. package/dist/chunk-WTVTI5TO.mjs +22 -0
  165. package/dist/chunk-WTVTI5TO.mjs.map +1 -0
  166. package/dist/chunk-XJOBZ4RJ.js +44 -0
  167. package/dist/chunk-XJOBZ4RJ.js.map +1 -0
  168. package/dist/chunk-XP2JDNDU.js +325 -0
  169. package/dist/chunk-XP2JDNDU.js.map +1 -0
  170. package/dist/chunk-Y4V5CEWD.mjs +112 -0
  171. package/dist/chunk-Y4V5CEWD.mjs.map +1 -0
  172. package/dist/chunk-YERN2UWM.js +116 -0
  173. package/dist/chunk-YERN2UWM.js.map +1 -0
  174. package/dist/chunk-ZKJQWFAA.mjs +114 -0
  175. package/dist/chunk-ZKJQWFAA.mjs.map +1 -0
  176. package/dist/chunk-ZOON3S3Y.mjs +138 -0
  177. package/dist/chunk-ZOON3S3Y.mjs.map +1 -0
  178. package/dist/chunk-ZP6QRAYC.mjs +2024 -0
  179. package/dist/chunk-ZP6QRAYC.mjs.map +1 -0
  180. package/dist/chunk-ZSTFX7FV.js +9 -0
  181. package/dist/chunk-ZSTFX7FV.js.map +1 -0
  182. package/dist/client/index.js +23 -331
  183. package/dist/client/index.js.map +1 -1
  184. package/dist/client/index.mjs +3 -330
  185. package/dist/client/index.mjs.map +1 -1
  186. package/dist/comparison/index.js +28 -111
  187. package/dist/comparison/index.js.map +1 -1
  188. package/dist/comparison/index.mjs +2 -107
  189. package/dist/comparison/index.mjs.map +1 -1
  190. package/dist/components/contact.js +21 -931
  191. package/dist/components/contact.js.map +1 -1
  192. package/dist/components/contact.mjs +12 -909
  193. package/dist/components/contact.mjs.map +1 -1
  194. package/dist/components/electron-download.js +12 -124
  195. package/dist/components/electron-download.js.map +1 -1
  196. package/dist/components/electron-download.mjs +4 -106
  197. package/dist/components/electron-download.mjs.map +1 -1
  198. package/dist/components/explore-cta.js +8 -112
  199. package/dist/components/explore-cta.js.map +1 -1
  200. package/dist/components/explore-cta.mjs +3 -114
  201. package/dist/components/explore-cta.mjs.map +1 -1
  202. package/dist/components/explore.js +62 -7833
  203. package/dist/components/explore.js.map +1 -1
  204. package/dist/components/explore.mjs +13 -7800
  205. package/dist/components/explore.mjs.map +1 -1
  206. package/dist/components/launch-countdown.js +8 -83
  207. package/dist/components/launch-countdown.js.map +1 -1
  208. package/dist/components/launch-countdown.mjs +3 -85
  209. package/dist/components/launch-countdown.mjs.map +1 -1
  210. package/dist/components/newsletter.js +20 -993
  211. package/dist/components/newsletter.js.map +1 -1
  212. package/dist/components/newsletter.mjs +11 -971
  213. package/dist/components/newsletter.mjs.map +1 -1
  214. package/dist/components/partners.js +24 -1302
  215. package/dist/components/partners.js.map +1 -1
  216. package/dist/components/partners.mjs +15 -1276
  217. package/dist/components/partners.mjs.map +1 -1
  218. package/dist/components/pricing.js +49 -1249
  219. package/dist/components/pricing.js.map +1 -1
  220. package/dist/components/pricing.mjs +8 -1226
  221. package/dist/components/pricing.mjs.map +1 -1
  222. package/dist/components/problems-solved.js +8 -150
  223. package/dist/components/problems-solved.js.map +1 -1
  224. package/dist/components/problems-solved.mjs +4 -133
  225. package/dist/components/problems-solved.mjs.map +1 -1
  226. package/dist/components/resource-links.js +8 -304
  227. package/dist/components/resource-links.js.map +1 -1
  228. package/dist/components/resource-links.mjs +5 -308
  229. package/dist/components/resource-links.mjs.map +1 -1
  230. package/dist/components/social-links.js +8 -343
  231. package/dist/components/social-links.js.map +1 -1
  232. package/dist/components/social-links.mjs +5 -347
  233. package/dist/components/social-links.mjs.map +1 -1
  234. package/dist/components/unsubscribe.js +10 -627
  235. package/dist/components/unsubscribe.js.map +1 -1
  236. package/dist/components/unsubscribe.mjs +6 -611
  237. package/dist/components/unsubscribe.mjs.map +1 -1
  238. package/dist/components/waitlist.js +21 -1001
  239. package/dist/components/waitlist.js.map +1 -1
  240. package/dist/components/waitlist.mjs +12 -982
  241. package/dist/components/waitlist.mjs.map +1 -1
  242. package/dist/components/website-switcher.js +12 -175
  243. package/dist/components/website-switcher.js.map +1 -1
  244. package/dist/components/website-switcher.mjs +4 -157
  245. package/dist/components/website-switcher.mjs.map +1 -1
  246. package/dist/content/index.js +118 -3616
  247. package/dist/content/index.js.map +1 -1
  248. package/dist/content/index.mjs +12 -3567
  249. package/dist/content/index.mjs.map +1 -1
  250. package/dist/hooks/index.js +37 -2321
  251. package/dist/hooks/index.js.map +1 -1
  252. package/dist/hooks/index.mjs +6 -2318
  253. package/dist/hooks/index.mjs.map +1 -1
  254. package/dist/index.js +4145 -20599
  255. package/dist/index.js.map +1 -1
  256. package/dist/index.mjs +3766 -20567
  257. package/dist/index.mjs.map +1 -1
  258. package/dist/product/index.js +20 -393
  259. package/dist/product/index.js.map +1 -1
  260. package/dist/product/index.mjs +5 -394
  261. package/dist/product/index.mjs.map +1 -1
  262. package/dist/seo/index.js +8 -76
  263. package/dist/seo/index.js.map +1 -1
  264. package/dist/seo/index.mjs +3 -78
  265. package/dist/seo/index.mjs.map +1 -1
  266. package/dist/store/index.js +51 -2650
  267. package/dist/store/index.js.map +1 -1
  268. package/dist/store/index.mjs +13 -2619
  269. package/dist/store/index.mjs.map +1 -1
  270. package/dist/utils/index.js +69 -134
  271. package/dist/utils/index.js.map +1 -1
  272. package/dist/utils/index.mjs +5 -122
  273. package/dist/utils/index.mjs.map +1 -1
  274. package/package.json +2 -1
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ // src/utils/product-slug.ts
4
+ var PRODUCT_SLUG_RENAMES = Object.freeze(
5
+ [Object.freeze({ legacy: "botlit", current: "botmanor" })]
6
+ );
7
+ var PRODUCT_SLUG_ALIASES = Object.freeze(
8
+ Object.fromEntries(PRODUCT_SLUG_RENAMES.map((r) => [r.legacy, r.current]))
9
+ );
10
+ var PRODUCT_SLUG_EMIT = Object.freeze({ productSlug: "current" });
11
+ function findRename(slug) {
12
+ const wanted = slug.toLowerCase();
13
+ return PRODUCT_SLUG_RENAMES.find(
14
+ (r) => r.legacy === wanted || r.current === wanted
15
+ );
16
+ }
17
+ function normalizeProductSlug(slug) {
18
+ if (slug == null) return slug;
19
+ return findRename(slug)?.current ?? slug;
20
+ }
21
+ function legacyProductSlug(slug) {
22
+ return findRename(slug)?.legacy ?? slug;
23
+ }
24
+ function productSlugVariants(slug) {
25
+ return [
26
+ .../* @__PURE__ */ new Set([slug, normalizeProductSlug(slug), legacyProductSlug(slug)])
27
+ ];
28
+ }
29
+ function isSameProductSlug(a, b) {
30
+ if (a == null || b == null) return a === b;
31
+ return a === b || normalizeProductSlug(a) === normalizeProductSlug(b);
32
+ }
33
+ function emitProductSlug(slug) {
34
+ return PRODUCT_SLUG_EMIT.productSlug === "current" ? normalizeProductSlug(slug) : legacyProductSlug(slug);
35
+ }
36
+
37
+ exports.PRODUCT_SLUG_ALIASES = PRODUCT_SLUG_ALIASES;
38
+ exports.PRODUCT_SLUG_EMIT = PRODUCT_SLUG_EMIT;
39
+ exports.PRODUCT_SLUG_RENAMES = PRODUCT_SLUG_RENAMES;
40
+ exports.emitProductSlug = emitProductSlug;
41
+ exports.isSameProductSlug = isSameProductSlug;
42
+ exports.legacyProductSlug = legacyProductSlug;
43
+ exports.normalizeProductSlug = normalizeProductSlug;
44
+ exports.productSlugVariants = productSlugVariants;
45
+ //# sourceMappingURL=chunk-E3GUGJMY.js.map
46
+ //# sourceMappingURL=chunk-E3GUGJMY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/product-slug.ts"],"names":[],"mappings":";;;AAoBO,IAAM,uBAAqD,MAAA,CAAO,MAAA;AAAA,EACvE,CAAC,OAAO,MAAA,CAAO,EAAE,QAAQ,QAAA,EAAU,OAAA,EAAS,UAAA,EAAY,CAAC;AAC3D;AAGO,IAAM,uBACX,MAAA,CAAO,MAAA;AAAA,EACL,MAAA,CAAO,WAAA,CAAY,oBAAA,CAAqB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,MAAA,EAAQ,CAAA,CAAE,OAAO,CAAC,CAAC;AAC3E;AASK,IAAM,oBAER,MAAA,CAAO,MAAA,CAAO,EAAE,WAAA,EAAa,WAAW;AAE7C,SAAS,WAAW,IAAA,EAA6C;AAC/D,EAAA,MAAM,MAAA,GAAS,KAAK,WAAA,EAAY;AAChC,EAAA,OAAO,oBAAA,CAAqB,IAAA;AAAA,IAC1B,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,MAAA,IAAU,EAAE,OAAA,KAAY;AAAA,GAC9C;AACF;AAOO,SAAS,qBACd,IAAA,EAC2B;AAC3B,EAAA,IAAI,IAAA,IAAQ,MAAM,OAAO,IAAA;AACzB,EAAA,OAAO,UAAA,CAAW,IAAI,CAAA,EAAG,OAAA,IAAW,IAAA;AACtC;AAGO,SAAS,kBAAkB,IAAA,EAAsB;AACtD,EAAA,OAAO,UAAA,CAAW,IAAI,CAAA,EAAG,MAAA,IAAU,IAAA;AACrC;AAGO,SAAS,oBAAoB,IAAA,EAAwB;AAE1D,EAAA,OAAO;AAAA,IACL,mBAAG,IAAI,GAAA,CAAI,CAAC,IAAA,EAAM,oBAAA,CAAqB,IAAI,CAAA,EAAG,iBAAA,CAAkB,IAAI,CAAC,CAAC;AAAA,GACxE;AACF;AAGO,SAAS,iBAAA,CACd,GACA,CAAA,EACS;AACT,EAAA,IAAI,CAAA,IAAK,IAAA,IAAQ,CAAA,IAAK,IAAA,SAAa,CAAA,KAAM,CAAA;AACzC,EAAA,OAAO,MAAM,CAAA,IAAK,oBAAA,CAAqB,CAAC,CAAA,KAAM,qBAAqB,CAAC,CAAA;AACtE;AAGO,SAAS,gBAAgB,IAAA,EAAsB;AACpD,EAAA,OAAO,kBAAkB,WAAA,KAAgB,SAAA,GACrC,qBAAqB,IAAI,CAAA,GACzB,kBAAkB,IAAI,CAAA;AAC5B","file":"chunk-E3GUGJMY.js","sourcesContent":["/**\n * Product slug aliases for products whose machine slug is being renamed\n * (today: `botlit` → `botmanor`, see botmanor-migration PLAN.md Stage 0 / WP-E).\n *\n * - Readers accept both slugs: compare with {@link isSameProductSlug}, look up\n * with {@link productSlugVariants}.\n * - Writers emit {@link emitProductSlug}, which follows {@link PRODUCT_SLUG_EMIT}\n * (`\"current\"` since PLAN.md Stage 5a, so writers emit `botmanor`).\n *\n * Mirrors `@burdenoff/be-sdk/product-alias` (product-slug concern only) so the\n * browser bundle does not pull in the backend SDK.\n */\n\n/** One product whose slug is being renamed. Both values are lowercase. */\nexport interface ProductSlugRename {\n readonly legacy: string;\n readonly current: string;\n}\n\n/** Every product slug rename in flight. */\nexport const PRODUCT_SLUG_RENAMES: readonly ProductSlugRename[] = Object.freeze(\n [Object.freeze({ legacy: \"botlit\", current: \"botmanor\" })],\n);\n\n/** Legacy slug → current slug, e.g. `{ botlit: \"botmanor\" }`. */\nexport const PRODUCT_SLUG_ALIASES: Readonly<Record<string, string>> =\n Object.freeze(\n Object.fromEntries(PRODUCT_SLUG_RENAMES.map((r) => [r.legacy, r.current])),\n );\n\n/** Which spelling a writer emits. */\nexport type ProductSlugGeneration = \"legacy\" | \"current\";\n\n/**\n * Which slug writers emit. Flipped to `\"current\"` at PLAN.md Stage 5a: stored\n * product slugs are migrated to `botmanor`, and every reader accepts both.\n */\nexport const PRODUCT_SLUG_EMIT: Readonly<{\n productSlug: ProductSlugGeneration;\n}> = Object.freeze({ productSlug: \"current\" });\n\nfunction findRename(slug: string): ProductSlugRename | undefined {\n const wanted = slug.toLowerCase();\n return PRODUCT_SLUG_RENAMES.find(\n (r) => r.legacy === wanted || r.current === wanted,\n );\n}\n\n/** `botlit` (any case) → `botmanor`; every other slug is returned unchanged. */\nexport function normalizeProductSlug(slug: string): string;\nexport function normalizeProductSlug(\n slug: string | null | undefined,\n): string | null | undefined;\nexport function normalizeProductSlug(\n slug: string | null | undefined,\n): string | null | undefined {\n if (slug == null) return slug;\n return findRename(slug)?.current ?? slug;\n}\n\n/** Old spelling of a renamed slug (`botmanor` → `botlit`); every other slug unchanged. */\nexport function legacyProductSlug(slug: string): string {\n return findRename(slug)?.legacy ?? slug;\n}\n\n/** Every slug a reader must accept for `slug`, the given one first. */\nexport function productSlugVariants(slug: string): string[] {\n // Canonical lowercase keys come after the given spelling, so \"BotLit\" yields both keys.\n return [\n ...new Set([slug, normalizeProductSlug(slug), legacyProductSlug(slug)]),\n ];\n}\n\n/** True when `a` and `b` are the same product under the rename. */\nexport function isSameProductSlug(\n a: string | null | undefined,\n b: string | null | undefined,\n): boolean {\n if (a == null || b == null) return a === b;\n return a === b || normalizeProductSlug(a) === normalizeProductSlug(b);\n}\n\n/** The slug writers should use today, from either spelling. */\nexport function emitProductSlug(slug: string): string {\n return PRODUCT_SLUG_EMIT.productSlug === \"current\"\n ? normalizeProductSlug(slug)\n : legacyProductSlug(slug);\n}\n"]}
@@ -0,0 +1,52 @@
1
+ import ReactMarkdown from 'react-markdown';
2
+ import rehypeSanitize from 'rehype-sanitize';
3
+ import remarkGfm from 'remark-gfm';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ function MarkdownLink({
7
+ href,
8
+ children,
9
+ // react-markdown passes the hast node to every override; it is not a DOM attribute.
10
+ node: _node,
11
+ ...props
12
+ }) {
13
+ const isExternal = typeof href === "string" && (href.startsWith("http://") || href.startsWith("https://"));
14
+ return /* @__PURE__ */ jsx(
15
+ "a",
16
+ {
17
+ href,
18
+ ...props,
19
+ ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : { rel: "noopener noreferrer" },
20
+ children
21
+ }
22
+ );
23
+ }
24
+ var defaultComponents = {
25
+ a: MarkdownLink
26
+ };
27
+ function Markdown({
28
+ children,
29
+ className,
30
+ inline,
31
+ components,
32
+ rehypePlugins
33
+ }) {
34
+ const content = /* @__PURE__ */ jsx(
35
+ ReactMarkdown,
36
+ {
37
+ remarkPlugins: [remarkGfm],
38
+ rehypePlugins: [rehypeSanitize, ...rehypePlugins ?? []],
39
+ components: { ...defaultComponents, ...components },
40
+ ...inline ? { disallowedElements: ["p"], unwrapDisallowed: true } : {},
41
+ children
42
+ }
43
+ );
44
+ if (inline) {
45
+ return /* @__PURE__ */ jsx("span", { className, children: content });
46
+ }
47
+ return /* @__PURE__ */ jsx("div", { className, children: content });
48
+ }
49
+
50
+ export { Markdown, MarkdownLink };
51
+ //# sourceMappingURL=chunk-EBZ2HGJ2.mjs.map
52
+ //# sourceMappingURL=chunk-EBZ2HGJ2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/content/Markdown.tsx"],"names":[],"mappings":";;;;;AA8BO,SAAS,YAAA,CAAa;AAAA,EAC3B,IAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAEA,IAAA,EAAM,KAAA;AAAA,EACN,GAAG;AACL,CAAA,EAAqC;AACnC,EAAA,MAAM,UAAA,GACJ,OAAO,IAAA,KAAS,QAAA,KACf,IAAA,CAAK,WAAW,SAAS,CAAA,IAAK,IAAA,CAAK,UAAA,CAAW,UAAU,CAAA,CAAA;AAC3D,EAAA,uBACE,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACC,GAAG,KAAA;AAAA,MACH,GAAI,UAAA,GACD,EAAE,MAAA,EAAQ,QAAA,EAAU,KAAK,qBAAA,EAAsB,GAC/C,EAAE,GAAA,EAAK,qBAAA,EAAsB;AAAA,MAEhC;AAAA;AAAA,GACH;AAEJ;AAEA,IAAM,iBAAA,GAAgC;AAAA,EACpC,CAAA,EAAG;AACL,CAAA;AAUO,SAAS,QAAA,CAAS;AAAA,EACvB,QAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAA6B;AAC3B,EAAA,MAAM,OAAA,mBACJ,GAAA;AAAA,IAAC,aAAA;AAAA,IAAA;AAAA,MACC,aAAA,EAAe,CAAC,SAAS,CAAA;AAAA,MACzB,eAAe,CAAC,cAAA,EAAgB,GAAI,aAAA,IAAiB,EAAG,CAAA;AAAA,MACxD,UAAA,EAAY,EAAE,GAAG,iBAAA,EAAmB,GAAG,UAAA,EAAW;AAAA,MACjD,GAAI,MAAA,GAAS,EAAE,kBAAA,EAAoB,CAAC,GAAG,CAAA,EAAG,gBAAA,EAAkB,IAAA,EAAK,GAAI,EAAC;AAAA,MAEtE;AAAA;AAAA,GACH;AAGF,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,uBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAuB,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EAC9C;AAEA,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAuB,QAAA,EAAA,OAAA,EAAQ,CAAA;AAC7C","file":"chunk-EBZ2HGJ2.mjs","sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\n\nimport ReactMarkdown from \"react-markdown\";\nimport rehypeSanitize from \"rehype-sanitize\";\nimport remarkGfm from \"remark-gfm\";\n\nimport type { Components, ExtraProps, Options } from \"react-markdown\";\n\nexport interface MarkdownProps {\n /** Markdown source to render. */\n children: string;\n /** Additional classes for the wrapper element. */\n className?: string;\n /** Render without a wrapping block element, suitable for inline content. */\n inline?: boolean;\n /** Optional react-markdown component overrides. */\n components?: Components;\n /**\n * Extra rehype plugins. They run AFTER `rehype-sanitize`, on the already-safe tree, so they\n * are for annotating nodes an override then reads — never for adding markup, because\n * nothing sanitises what they insert.\n */\n rehypePlugins?: Options[\"rehypePlugins\"];\n}\n\n/**\n * The default markdown link: external links open in a new tab, every link gets safe `rel`\n * attributes. Exported so a caller overriding `a` (to add context around links, say) can\n * still render the same element.\n */\nexport function MarkdownLink({\n href,\n children,\n // react-markdown passes the hast node to every override; it is not a DOM attribute.\n node: _node,\n ...props\n}: ComponentProps<\"a\"> & ExtraProps) {\n const isExternal =\n typeof href === \"string\" &&\n (href.startsWith(\"http://\") || href.startsWith(\"https://\"));\n return (\n <a\n href={href}\n {...props}\n {...(isExternal\n ? { target: \"_blank\", rel: \"noopener noreferrer\" }\n : { rel: \"noopener noreferrer\" })}\n >\n {children}\n </a>\n );\n}\n\nconst defaultComponents: Components = {\n a: MarkdownLink,\n};\n\n/**\n * Shared markdown renderer for website content.\n *\n * - Uses `react-markdown` for standards-compliant parsing.\n * - Enables GitHub Flavored Markdown (tables, task lists, strikethrough, autolinks).\n * - Sanitizes HTML via `rehype-sanitize` so raw markup in markdown is stripped.\n * - External links open in a new tab with safe rel attributes.\n */\nexport function Markdown({\n children,\n className,\n inline,\n components,\n rehypePlugins,\n}: MarkdownProps): ReactNode {\n const content = (\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n rehypePlugins={[rehypeSanitize, ...(rehypePlugins ?? [])]}\n components={{ ...defaultComponents, ...components }}\n {...(inline ? { disallowedElements: [\"p\"], unwrapDisallowed: true } : {})}\n >\n {children}\n </ReactMarkdown>\n );\n\n if (inline) {\n return <span className={className}>{content}</span>;\n }\n\n return <div className={className}>{content}</div>;\n}\n"]}
@@ -0,0 +1,210 @@
1
+ import { Markdown } from './chunk-EBZ2HGJ2.mjs';
2
+ import { useProduct } from './chunk-GCFLCO2Z.mjs';
3
+ import { useWebSDK, useWebSDKConfig } from './chunk-5JRJ57CL.mjs';
4
+ import { useState, useCallback, useEffect } from 'react';
5
+ import DOMPurify from 'isomorphic-dompurify';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ var PUBLIC_CONTENT_PAGE_QUERY = `
9
+ query PublicContentPage($slug: String!, $productId: String) {
10
+ publicContentPage(slug: $slug, productId: $productId) {
11
+ id
12
+ title
13
+ slug
14
+ content
15
+ contentFormat
16
+ seoTitle
17
+ seoDescription
18
+ seoKeywords
19
+ lastUpdated
20
+ version
21
+ excerpt
22
+ thumbnail
23
+ author
24
+ publishedAt
25
+ readingTime
26
+ featured
27
+ category
28
+ }
29
+ }
30
+ `;
31
+ var PUBLIC_RESOLVED_CONTENT_PAGE_QUERY = `
32
+ query PublicResolvedContentPage($slug: String!, $productId: String!) {
33
+ publicResolvedContentPage(slug: $slug, productId: $productId) {
34
+ id
35
+ title
36
+ slug
37
+ content
38
+ contentFormat
39
+ seoTitle
40
+ seoDescription
41
+ seoKeywords
42
+ lastUpdated
43
+ version
44
+ excerpt
45
+ thumbnail
46
+ author
47
+ publishedAt
48
+ readingTime
49
+ featured
50
+ category
51
+ }
52
+ }
53
+ `;
54
+ var PUBLIC_CONTENT_PAGES_QUERY = `
55
+ query PublicContentPages($productId: String!, $limit: Int, $offset: Int) {
56
+ publicContentPages(productId: $productId, limit: $limit, offset: $offset) {
57
+ items {
58
+ id
59
+ title
60
+ slug
61
+ lastUpdated
62
+ tags
63
+ seoDescription
64
+ excerpt
65
+ thumbnail
66
+ author
67
+ publishedAt
68
+ readingTime
69
+ featured
70
+ category
71
+ }
72
+ total
73
+ hasMore
74
+ }
75
+ }
76
+ `;
77
+ function resolveContentPageGate(resolvedProductId, hasProvider, productLoading) {
78
+ if (resolvedProductId) return "fetch";
79
+ return hasProvider && productLoading ? "wait" : "unavailable";
80
+ }
81
+ function useContentPage(slug, options) {
82
+ const client = useWebSDK();
83
+ const config = useWebSDKConfig();
84
+ const {
85
+ product,
86
+ loading: productLoading,
87
+ error: productError,
88
+ hasProvider
89
+ } = useProduct();
90
+ const resolvedProductId = product?.id || config.productId;
91
+ const gate = resolveContentPageGate(
92
+ resolvedProductId,
93
+ hasProvider,
94
+ productLoading
95
+ );
96
+ const enabled = options?.enabled !== false;
97
+ const [data, setData] = useState(null);
98
+ const [loading, setLoading] = useState(enabled);
99
+ const [error, setError] = useState(null);
100
+ const fetchPage = useCallback(async () => {
101
+ if (!enabled) {
102
+ setLoading(false);
103
+ return;
104
+ }
105
+ if (gate === "wait") return;
106
+ if (gate === "unavailable") {
107
+ setData(null);
108
+ setError(
109
+ productError ?? "Product unavailable \u2014 cannot load content page"
110
+ );
111
+ setLoading(false);
112
+ return;
113
+ }
114
+ setLoading(true);
115
+ setError(null);
116
+ try {
117
+ const query = options?.resolve ? PUBLIC_RESOLVED_CONTENT_PAGE_QUERY : PUBLIC_CONTENT_PAGE_QUERY;
118
+ const queryName = options?.resolve ? "publicResolvedContentPage" : "publicContentPage";
119
+ const result = await client.query(
120
+ query,
121
+ {
122
+ slug,
123
+ productId: resolvedProductId
124
+ }
125
+ );
126
+ if (result.errors?.length) {
127
+ setError(result.errors[0]?.message ?? "Unknown error");
128
+ setData(null);
129
+ } else {
130
+ setData(result.data?.[queryName] ?? null);
131
+ }
132
+ } catch (err) {
133
+ setError(err instanceof Error ? err.message : "Failed to fetch content");
134
+ setData(null);
135
+ } finally {
136
+ setLoading(false);
137
+ }
138
+ }, [
139
+ client,
140
+ enabled,
141
+ gate,
142
+ productError,
143
+ resolvedProductId,
144
+ slug,
145
+ options?.resolve
146
+ ]);
147
+ useEffect(() => {
148
+ fetchPage();
149
+ }, [fetchPage]);
150
+ return { data, loading, error, refetch: fetchPage };
151
+ }
152
+ function useContentPages(options) {
153
+ const client = useWebSDK();
154
+ const config = useWebSDKConfig();
155
+ const [data, setData] = useState(null);
156
+ const [loading, setLoading] = useState(true);
157
+ const [error, setError] = useState(null);
158
+ const fetchPages = useCallback(async () => {
159
+ setLoading(true);
160
+ setError(null);
161
+ try {
162
+ const result = await client.query(PUBLIC_CONTENT_PAGES_QUERY, {
163
+ productId: config.productId,
164
+ limit: options?.limit ?? 50,
165
+ offset: options?.offset ?? 0
166
+ });
167
+ if (result.errors?.length) {
168
+ setError(result.errors[0]?.message ?? "Unknown error");
169
+ setData(null);
170
+ } else {
171
+ setData(result.data?.publicContentPages ?? null);
172
+ }
173
+ } catch (err) {
174
+ setError(
175
+ err instanceof Error ? err.message : "Failed to fetch content pages"
176
+ );
177
+ setData(null);
178
+ } finally {
179
+ setLoading(false);
180
+ }
181
+ }, [client, config.productId, options?.limit, options?.offset]);
182
+ useEffect(() => {
183
+ fetchPages();
184
+ }, [fetchPages]);
185
+ return { data, loading, error, refetch: fetchPages };
186
+ }
187
+ function ContentRenderer({
188
+ content,
189
+ format = "markdown",
190
+ className
191
+ }) {
192
+ if (format === "markdown") {
193
+ return /* @__PURE__ */ jsx(Markdown, { className, children: content });
194
+ }
195
+ if (format === "html") {
196
+ const sanitized = DOMPurify.sanitize(content);
197
+ return /* @__PURE__ */ jsx(
198
+ "div",
199
+ {
200
+ className,
201
+ dangerouslySetInnerHTML: { __html: sanitized }
202
+ }
203
+ );
204
+ }
205
+ return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx("pre", { style: { whiteSpace: "pre-wrap", fontFamily: "inherit" }, children: content }) });
206
+ }
207
+
208
+ export { ContentRenderer, useContentPage, useContentPages };
209
+ //# sourceMappingURL=chunk-EDLTUOIA.mjs.map
210
+ //# sourceMappingURL=chunk-EDLTUOIA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/content/content-provider.tsx"],"names":[],"mappings":"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","file":"chunk-EDLTUOIA.mjs","sourcesContent":["/**\n * Content Provider\n *\n * React hooks for fetching public content pages from the global tenant service.\n * Content pages include privacy policies, terms of service, blogs, changelogs, etc.\n */\n\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\n\nimport DOMPurify from \"isomorphic-dompurify\";\n\nimport { Markdown } from \"./Markdown\";\nimport { useWebSDK, useWebSDKConfig } from \"../client/provider\";\nimport { useProduct } from \"../product/product-provider\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A customer's written approval of a case study (BOFF-9971). Public callers\n * receive only the approval date; who approved it and where the approval is\n * filed stay with the people who manage content pages.\n */\nexport interface CustomerSignOffData {\n signedAt: string;\n signedBy?: string | null;\n documentRef?: string | null;\n}\n\nexport interface ContentPageData {\n id: string;\n title: string;\n slug: string;\n content: string;\n contentFormat: string;\n seoTitle?: string | null;\n seoDescription?: string | null;\n seoKeywords?: string | null;\n lastUpdated: string;\n version: number;\n tags?: string[];\n excerpt?: string | null;\n thumbnail?: string | null;\n author?: string | null;\n publishedAt?: string | null;\n readingTime?: number | null;\n featured?: boolean;\n category?: string | null;\n customerSignOff?: CustomerSignOffData | null;\n}\n\nexport interface ContentPageListItem {\n id: string;\n title: string;\n slug: string;\n lastUpdated: string;\n tags?: string[];\n excerpt?: string | null;\n thumbnail?: string | null;\n author?: string | null;\n publishedAt?: string | null;\n readingTime?: number | null;\n featured?: boolean;\n category?: string | null;\n seoDescription?: string | null;\n customerSignOff?: CustomerSignOffData | null;\n}\n\nexport interface ContentPageListData {\n items: ContentPageListItem[];\n total: number;\n hasMore: boolean;\n}\n\nexport interface UseContentPageOptions {\n /** Whether to use template variable replacement (resolvedContentPage) */\n resolve?: boolean;\n /**\n * Set to `false` to skip the request entirely — e.g. when the page was\n * already fetched at build time. The hook then settles immediately with\n * `data: null`, `loading: false`. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\n// ============================================================================\n// GraphQL Queries\n// ============================================================================\n\nconst PUBLIC_CONTENT_PAGE_QUERY = `\n query PublicContentPage($slug: String!, $productId: String) {\n publicContentPage(slug: $slug, productId: $productId) {\n id\n title\n slug\n content\n contentFormat\n seoTitle\n seoDescription\n seoKeywords\n lastUpdated\n version\n excerpt\n thumbnail\n author\n publishedAt\n readingTime\n featured\n category\n }\n }\n`;\n\nconst PUBLIC_RESOLVED_CONTENT_PAGE_QUERY = `\n query PublicResolvedContentPage($slug: String!, $productId: String!) {\n publicResolvedContentPage(slug: $slug, productId: $productId) {\n id\n title\n slug\n content\n contentFormat\n seoTitle\n seoDescription\n seoKeywords\n lastUpdated\n version\n excerpt\n thumbnail\n author\n publishedAt\n readingTime\n featured\n category\n }\n }\n`;\n\nconst PUBLIC_CONTENT_PAGES_QUERY = `\n query PublicContentPages($productId: String!, $limit: Int, $offset: Int) {\n publicContentPages(productId: $productId, limit: $limit, offset: $offset) {\n items {\n id\n title\n slug\n lastUpdated\n tags\n seoDescription\n excerpt\n thumbnail\n author\n publishedAt\n readingTime\n featured\n category\n }\n total\n hasMore\n }\n }\n`;\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Decides what `useContentPage` should do about the product-id dependency.\n *\n * The product id comes from `useProduct()` (a `publicProduct(slug)` lookup)\n * or falls back to `config.productId`. While that lookup is in flight there\n * is nothing to fetch — but once it has settled (or no ProductProvider is\n * mounted and no config id exists) waiting is indistinguishable from hanging:\n * the hook must settle with an error so consumers render their fallback\n * instead of a permanent loading skeleton (BOFF-6190).\n */\nexport type ContentPageGate = \"wait\" | \"fetch\" | \"unavailable\";\n\nexport function resolveContentPageGate(\n resolvedProductId: string | undefined | null,\n hasProvider: boolean,\n productLoading: boolean,\n): ContentPageGate {\n if (resolvedProductId) return \"fetch\";\n // Only an in-flight provider lookup is a real reason to keep waiting.\n // Without a provider the default context reports loading forever.\n return hasProvider && productLoading ? \"wait\" : \"unavailable\";\n}\n\n/**\n * Hook to fetch a single public content page by slug.\n *\n * @example\n * ```tsx\n * const { data, loading, error } = useContentPage('privacy-policy');\n * ```\n */\nexport function useContentPage(\n slug: string,\n options?: UseContentPageOptions,\n): {\n data: ContentPageData | null;\n loading: boolean;\n error: string | null;\n refetch: () => void;\n} {\n const client = useWebSDK();\n const config = useWebSDKConfig();\n const {\n product,\n loading: productLoading,\n error: productError,\n hasProvider,\n } = useProduct();\n const resolvedProductId = product?.id || config.productId;\n const gate = resolveContentPageGate(\n resolvedProductId,\n hasProvider,\n productLoading,\n );\n const enabled = options?.enabled !== false;\n const [data, setData] = useState<ContentPageData | null>(null);\n const [loading, setLoading] = useState(enabled);\n const [error, setError] = useState<string | null>(null);\n\n const fetchPage = useCallback(async () => {\n if (!enabled) {\n setLoading(false);\n return;\n }\n if (gate === \"wait\") return; // Product lookup still in flight\n\n if (gate === \"unavailable\") {\n // The product lookup settled without an id (or there is no provider\n // and no config.productId): the fetch can never start. Settle with an\n // error so consumers render their fallback, not a permanent skeleton.\n setData(null);\n setError(\n productError ?? \"Product unavailable — cannot load content page\",\n );\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const query = options?.resolve\n ? PUBLIC_RESOLVED_CONTENT_PAGE_QUERY\n : PUBLIC_CONTENT_PAGE_QUERY;\n\n const queryName = options?.resolve\n ? \"publicResolvedContentPage\"\n : \"publicContentPage\";\n\n const result = await client.query<Record<string, ContentPageData | null>>(\n query,\n {\n slug,\n productId: resolvedProductId,\n },\n );\n\n if (result.errors?.length) {\n setError(result.errors[0]?.message ?? \"Unknown error\");\n setData(null);\n } else {\n setData(result.data?.[queryName] ?? null);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to fetch content\");\n setData(null);\n } finally {\n setLoading(false);\n }\n }, [\n client,\n enabled,\n gate,\n productError,\n resolvedProductId,\n slug,\n options?.resolve,\n ]);\n\n useEffect(() => {\n fetchPage();\n }, [fetchPage]);\n\n return { data, loading, error, refetch: fetchPage };\n}\n\n/**\n * Hook to fetch a list of public content pages for the current product.\n *\n * @example\n * ```tsx\n * const { data, loading } = useContentPages({ limit: 10 });\n * ```\n */\nexport function useContentPages(options?: {\n limit?: number;\n offset?: number;\n}): {\n data: ContentPageListData | null;\n loading: boolean;\n error: string | null;\n refetch: () => void;\n} {\n const client = useWebSDK();\n const config = useWebSDKConfig();\n const [data, setData] = useState<ContentPageListData | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const fetchPages = useCallback(async () => {\n setLoading(true);\n setError(null);\n\n try {\n const result = await client.query<{\n publicContentPages: ContentPageListData;\n }>(PUBLIC_CONTENT_PAGES_QUERY, {\n productId: config.productId,\n limit: options?.limit ?? 50,\n offset: options?.offset ?? 0,\n });\n\n if (result.errors?.length) {\n setError(result.errors[0]?.message ?? \"Unknown error\");\n setData(null);\n } else {\n setData(result.data?.publicContentPages ?? null);\n }\n } catch (err) {\n setError(\n err instanceof Error ? err.message : \"Failed to fetch content pages\",\n );\n setData(null);\n } finally {\n setLoading(false);\n }\n }, [client, config.productId, options?.limit, options?.offset]);\n\n useEffect(() => {\n fetchPages();\n }, [fetchPages]);\n\n return { data, loading, error, refetch: fetchPages };\n}\n\n/**\n * Content renderer component.\n *\n * - `markdown` (default): renders with the shared {@link Markdown} component\n * (react-markdown + remark-gfm + rehype-sanitize).\n * - `html`: sanitized with DOMPurify before rendering.\n * - anything else: plain-text fallback\n *\n * @example\n * ```tsx\n * <ContentRenderer content={page.content} format={page.contentFormat} />\n * ```\n */\nexport function ContentRenderer({\n content,\n format = \"markdown\",\n className,\n}: {\n content: string;\n format?: string;\n className?: string;\n}) {\n if (format === \"markdown\") {\n return <Markdown className={className}>{content}</Markdown>;\n }\n\n if (format === \"html\") {\n const sanitized = DOMPurify.sanitize(content);\n return (\n <div\n className={className}\n dangerouslySetInnerHTML={{ __html: sanitized }}\n />\n );\n }\n\n // Plain text fallback\n return (\n <div className={className}>\n <pre style={{ whiteSpace: \"pre-wrap\", fontFamily: \"inherit\" }}>\n {content}\n </pre>\n </div>\n );\n}\n"]}
@@ -0,0 +1,4 @@
1
+ 'use strict';
2
+
3
+ //# sourceMappingURL=chunk-EJQSOT4X.js.map
4
+ //# sourceMappingURL=chunk-EJQSOT4X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-EJQSOT4X.js"}