@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
@@ -1,141 +1,76 @@
1
1
  'use strict';
2
2
 
3
- var clsx = require('clsx');
4
- var tailwindMerge = require('tailwind-merge');
3
+ var chunk5GMTBOO6_js = require('../chunk-5GMTBOO6.js');
4
+ var chunkPHXAGQNB_js = require('../chunk-PHXAGQNB.js');
5
+ var chunkC6OJIHNO_js = require('../chunk-C6OJIHNO.js');
6
+ var chunkE3GUGJMY_js = require('../chunk-E3GUGJMY.js');
7
+ require('../chunk-ZSTFX7FV.js');
5
8
 
6
- function cn(...inputs) {
7
- return tailwindMerge.twMerge(clsx.clsx(inputs));
8
- }
9
9
 
10
- // src/utils/recaptcha-v3.ts
11
- var SCRIPT_ID = "boff-recaptcha-v3";
12
- var SCRIPT_SRC = "https://www.google.com/recaptcha/api.js?render=";
13
- var EXPLORE_RECAPTCHA_ACTION = "explore_chat";
14
- var loaders = /* @__PURE__ */ new Map();
15
- function isBrowser() {
16
- return typeof window !== "undefined" && typeof document !== "undefined";
17
- }
18
- function loadRecaptchaV3(siteKey) {
19
- if (!siteKey) {
20
- return Promise.reject(new Error("reCAPTCHA site key is required"));
21
- }
22
- if (!isBrowser()) {
23
- return Promise.reject(
24
- new Error("reCAPTCHA v3 can only be loaded in a browser")
25
- );
26
- }
27
- const existing = loaders.get(siteKey);
28
- if (existing) return existing;
29
- const promise = new Promise((resolve, reject) => {
30
- const ready = () => {
31
- const api = window.grecaptcha;
32
- if (!api) {
33
- reject(new Error("reCAPTCHA loaded but grecaptcha is unavailable"));
34
- return;
35
- }
36
- api.ready(() => resolve(api));
37
- };
38
- if (window.grecaptcha) {
39
- ready();
40
- return;
41
- }
42
- const scriptId = `${SCRIPT_ID}-${siteKey}`;
43
- const found = document.getElementById(scriptId);
44
- if (found) {
45
- found.addEventListener("load", ready, { once: true });
46
- found.addEventListener(
47
- "error",
48
- () => reject(new Error("Failed to load reCAPTCHA v3")),
49
- { once: true }
50
- );
51
- return;
52
- }
53
- const script = document.createElement("script");
54
- script.id = scriptId;
55
- script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;
56
- script.async = true;
57
- script.defer = true;
58
- script.addEventListener("load", ready, { once: true });
59
- script.addEventListener(
60
- "error",
61
- () => {
62
- loaders.delete(siteKey);
63
- reject(new Error("Failed to load reCAPTCHA v3"));
64
- },
65
- { once: true }
66
- );
67
- document.head.appendChild(script);
68
- });
69
- loaders.set(siteKey, promise);
70
- return promise;
71
- }
72
- async function getRecaptchaV3Token(siteKey, action = EXPLORE_RECAPTCHA_ACTION) {
73
- const api = await loadRecaptchaV3(siteKey);
74
- return api.execute(siteKey, { action });
75
- }
76
10
 
77
- // src/utils/site-chrome.ts
78
- var FOOTERLESS_ROUTES = ["/explore"];
79
- function normalizeRoutePath(pathname) {
80
- const trimmed = pathname.toLowerCase().replace(/\/+$/, "");
81
- return trimmed === "" ? "/" : trimmed;
82
- }
83
- function isFooterlessPath(pathname) {
84
- return FOOTERLESS_ROUTES.includes(normalizeRoutePath(pathname));
85
- }
86
- function shouldRenderSiteFooter(pathname) {
87
- return !isFooterlessPath(pathname);
88
- }
89
-
90
- // src/utils/product-slug.ts
91
- var PRODUCT_SLUG_RENAMES = Object.freeze(
92
- [Object.freeze({ legacy: "botlit", current: "botmanor" })]
93
- );
94
- var PRODUCT_SLUG_ALIASES = Object.freeze(
95
- Object.fromEntries(PRODUCT_SLUG_RENAMES.map((r) => [r.legacy, r.current]))
96
- );
97
- var PRODUCT_SLUG_EMIT = Object.freeze({ productSlug: "current" });
98
- function findRename(slug) {
99
- const wanted = slug.toLowerCase();
100
- return PRODUCT_SLUG_RENAMES.find(
101
- (r) => r.legacy === wanted || r.current === wanted
102
- );
103
- }
104
- function normalizeProductSlug(slug) {
105
- if (slug == null) return slug;
106
- return findRename(slug)?.current ?? slug;
107
- }
108
- function legacyProductSlug(slug) {
109
- return findRename(slug)?.legacy ?? slug;
110
- }
111
- function productSlugVariants(slug) {
112
- return [
113
- .../* @__PURE__ */ new Set([slug, normalizeProductSlug(slug), legacyProductSlug(slug)])
114
- ];
115
- }
116
- function isSameProductSlug(a, b) {
117
- if (a == null || b == null) return a === b;
118
- return a === b || normalizeProductSlug(a) === normalizeProductSlug(b);
119
- }
120
- function emitProductSlug(slug) {
121
- return PRODUCT_SLUG_EMIT.productSlug === "current" ? normalizeProductSlug(slug) : legacyProductSlug(slug);
122
- }
123
-
124
- exports.EXPLORE_RECAPTCHA_ACTION = EXPLORE_RECAPTCHA_ACTION;
125
- exports.FOOTERLESS_ROUTES = FOOTERLESS_ROUTES;
126
- exports.PRODUCT_SLUG_ALIASES = PRODUCT_SLUG_ALIASES;
127
- exports.PRODUCT_SLUG_EMIT = PRODUCT_SLUG_EMIT;
128
- exports.PRODUCT_SLUG_RENAMES = PRODUCT_SLUG_RENAMES;
129
- exports.cn = cn;
130
- exports.emitProductSlug = emitProductSlug;
131
- exports.getRecaptchaV3Token = getRecaptchaV3Token;
132
- exports.isFooterlessPath = isFooterlessPath;
133
- exports.isSameProductSlug = isSameProductSlug;
134
- exports.legacyProductSlug = legacyProductSlug;
135
- exports.loadRecaptchaV3 = loadRecaptchaV3;
136
- exports.normalizeProductSlug = normalizeProductSlug;
137
- exports.normalizeRoutePath = normalizeRoutePath;
138
- exports.productSlugVariants = productSlugVariants;
139
- exports.shouldRenderSiteFooter = shouldRenderSiteFooter;
11
+ Object.defineProperty(exports, "FOOTERLESS_ROUTES", {
12
+ enumerable: true,
13
+ get: function () { return chunk5GMTBOO6_js.FOOTERLESS_ROUTES; }
14
+ });
15
+ Object.defineProperty(exports, "isFooterlessPath", {
16
+ enumerable: true,
17
+ get: function () { return chunk5GMTBOO6_js.isFooterlessPath; }
18
+ });
19
+ Object.defineProperty(exports, "normalizeRoutePath", {
20
+ enumerable: true,
21
+ get: function () { return chunk5GMTBOO6_js.normalizeRoutePath; }
22
+ });
23
+ Object.defineProperty(exports, "shouldRenderSiteFooter", {
24
+ enumerable: true,
25
+ get: function () { return chunk5GMTBOO6_js.shouldRenderSiteFooter; }
26
+ });
27
+ Object.defineProperty(exports, "EXPLORE_RECAPTCHA_ACTION", {
28
+ enumerable: true,
29
+ get: function () { return chunkPHXAGQNB_js.EXPLORE_RECAPTCHA_ACTION; }
30
+ });
31
+ Object.defineProperty(exports, "getRecaptchaV3Token", {
32
+ enumerable: true,
33
+ get: function () { return chunkPHXAGQNB_js.getRecaptchaV3Token; }
34
+ });
35
+ Object.defineProperty(exports, "loadRecaptchaV3", {
36
+ enumerable: true,
37
+ get: function () { return chunkPHXAGQNB_js.loadRecaptchaV3; }
38
+ });
39
+ Object.defineProperty(exports, "cn", {
40
+ enumerable: true,
41
+ get: function () { return chunkC6OJIHNO_js.cn; }
42
+ });
43
+ Object.defineProperty(exports, "PRODUCT_SLUG_ALIASES", {
44
+ enumerable: true,
45
+ get: function () { return chunkE3GUGJMY_js.PRODUCT_SLUG_ALIASES; }
46
+ });
47
+ Object.defineProperty(exports, "PRODUCT_SLUG_EMIT", {
48
+ enumerable: true,
49
+ get: function () { return chunkE3GUGJMY_js.PRODUCT_SLUG_EMIT; }
50
+ });
51
+ Object.defineProperty(exports, "PRODUCT_SLUG_RENAMES", {
52
+ enumerable: true,
53
+ get: function () { return chunkE3GUGJMY_js.PRODUCT_SLUG_RENAMES; }
54
+ });
55
+ Object.defineProperty(exports, "emitProductSlug", {
56
+ enumerable: true,
57
+ get: function () { return chunkE3GUGJMY_js.emitProductSlug; }
58
+ });
59
+ Object.defineProperty(exports, "isSameProductSlug", {
60
+ enumerable: true,
61
+ get: function () { return chunkE3GUGJMY_js.isSameProductSlug; }
62
+ });
63
+ Object.defineProperty(exports, "legacyProductSlug", {
64
+ enumerable: true,
65
+ get: function () { return chunkE3GUGJMY_js.legacyProductSlug; }
66
+ });
67
+ Object.defineProperty(exports, "normalizeProductSlug", {
68
+ enumerable: true,
69
+ get: function () { return chunkE3GUGJMY_js.normalizeProductSlug; }
70
+ });
71
+ Object.defineProperty(exports, "productSlugVariants", {
72
+ enumerable: true,
73
+ get: function () { return chunkE3GUGJMY_js.productSlugVariants; }
74
+ });
140
75
  //# sourceMappingURL=index.js.map
141
76
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/cn.ts","../../src/utils/recaptcha-v3.ts","../../src/utils/site-chrome.ts","../../src/utils/product-slug.ts"],"names":["twMerge","clsx"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * reCAPTCHA v3 (invisible, score-based) loader and token minter.\n *\n * Deliberately dependency-free: the SDK already ships the `react-google-recaptcha`\n * peer for the **v2 checkbox** used by `ContactPage`, and the two widgets cannot\n * share a script tag — v3 needs `?render=<siteKey>` on the URL, v2 must not have\n * it. This module injects its own v3 script and leaves the v2 integration alone.\n *\n * The Explore chat turns v3 on purely from the backend catalog\n * (`exploreCatalog.captchaRequired && recaptchaSiteKey`), so nothing is loaded\n * and no third-party request is made on sites where captcha is off.\n */\n\n/** The slice of the `grecaptcha` global this module uses. */\nexport interface RecaptchaV3 {\n /** Runs the callback once the API is fully initialised. */\n ready(callback: () => void): void;\n /** Mints a single-use token for `action`. */\n execute(siteKey: string, options: { action: string }): Promise<string>;\n}\n\ndeclare global {\n interface Window {\n grecaptcha?: RecaptchaV3;\n }\n}\n\nconst SCRIPT_ID = \"boff-recaptcha-v3\";\nconst SCRIPT_SRC = \"https://www.google.com/recaptcha/api.js?render=\";\n\n/** Default action name reported to reCAPTCHA for Explore chat submissions. */\nexport const EXPLORE_RECAPTCHA_ACTION = \"explore_chat\";\n\n/**\n * One in-flight/settled promise per site key. Guarantees the script tag is\n * injected at most once even when several components mount at the same time,\n * and lets later callers await the same load instead of racing it.\n */\nconst loaders = new Map<string, Promise<RecaptchaV3>>();\n\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/**\n * Load the reCAPTCHA v3 script for `siteKey` and resolve once `grecaptcha` is\n * ready to mint tokens.\n *\n * - Injects the script at most once per site key (subsequent calls reuse the\n * same promise).\n * - Adopts an already-present script tag (e.g. injected by the host site)\n * rather than adding a second one.\n * - Rejects rather than hanging when the script fails to load, so the caller\n * can decide whether to submit without a token or surface an error.\n */\nexport function loadRecaptchaV3(siteKey: string): Promise<RecaptchaV3> {\n if (!siteKey) {\n return Promise.reject(new Error(\"reCAPTCHA site key is required\"));\n }\n if (!isBrowser()) {\n return Promise.reject(\n new Error(\"reCAPTCHA v3 can only be loaded in a browser\"),\n );\n }\n\n const existing = loaders.get(siteKey);\n if (existing) return existing;\n\n const promise = new Promise<RecaptchaV3>((resolve, reject) => {\n const ready = () => {\n const api = window.grecaptcha;\n if (!api) {\n reject(new Error(\"reCAPTCHA loaded but grecaptcha is unavailable\"));\n return;\n }\n // `ready` queues until the API has finished initialising internally;\n // calling `execute` before that throws.\n api.ready(() => resolve(api));\n };\n\n // Already loaded by this module, another SDK instance, or the host site.\n if (window.grecaptcha) {\n ready();\n return;\n }\n\n const scriptId = `${SCRIPT_ID}-${siteKey}`;\n const found = document.getElementById(scriptId);\n if (found) {\n found.addEventListener(\"load\", ready, { once: true });\n found.addEventListener(\n \"error\",\n () => reject(new Error(\"Failed to load reCAPTCHA v3\")),\n { once: true },\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = scriptId;\n script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;\n script.async = true;\n script.defer = true;\n script.addEventListener(\"load\", ready, { once: true });\n script.addEventListener(\n \"error\",\n () => {\n // Drop the memo so a later attempt can retry a transient CDN failure\n // instead of being stuck with a permanently rejected promise.\n loaders.delete(siteKey);\n reject(new Error(\"Failed to load reCAPTCHA v3\"));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n\n loaders.set(siteKey, promise);\n return promise;\n}\n\n/**\n * Mint a single-use reCAPTCHA v3 token, loading the script on first use.\n *\n * Tokens are valid for ~2 minutes and are consumed by one verification, so\n * this must be called per submission — never cached.\n */\nexport async function getRecaptchaV3Token(\n siteKey: string,\n action: string = EXPLORE_RECAPTCHA_ACTION,\n): Promise<string> {\n const api = await loadRecaptchaV3(siteKey);\n return api.execute(siteKey, { action });\n}\n","/**\n * Which routes a host site should render WITHOUT its marketing footer.\n *\n * ## Why this lives in the SDK\n *\n * It was written 39 times. The footer belongs to each website, so the obvious\n * place for the rule is each website — and eight agents asked to add it produced\n * five different helpers (`footerless-routes.ts`, `footer-visibility.ts`,\n * `footer-routes.ts`, `explore-route.ts`, plus six copies inlined straight into\n * a layout). All five behave the same today. The next person to change the rule\n * has to find all five, and will not.\n *\n * The rule is really a property of the SDK's own surfaces: `/explore` is\n * footerless because `ExplorePage` sizes itself to one viewport, which is a fact\n * about this package, not about any site. So it is declared here, once, and the\n * sites ask.\n *\n * ## Why `/explore` and nothing else\n *\n * `ExplorePage` renders a full-viewport chat pane (`100dvh` minus the site\n * chrome above it), so anything after it is below the fold by construction. On a\n * phone these footers are 1100-1330px — roughly 70% of the document — and that\n * bulk is what allowed a restored scroll offset to open the page on nothing but\n * footer, with zero pixels of the chat on screen.\n *\n * The SDK's OTHER pages are the opposite case and must keep their footer:\n * `/concepts`, `/concept/:slug`, `/answers` and `/answer/:slug` are ordinary\n * indexed content pages whose footer carries the site's internal links.\n * Stripping it would cost hundreds of pages their internal linking, and nobody\n * would notice for weeks.\n */\n\n/** Routes that render without the site footer. Exact paths, not prefixes. */\nexport const FOOTERLESS_ROUTES: readonly string[] = [\"/explore\"];\n\n/**\n * Normalise a router pathname for exact comparison.\n *\n * React Router matches case-insensitively (`caseSensitive` defaults to false)\n * and tolerates a trailing slash, so `/Explore/` reaches the same route element\n * as `/explore` and has to be treated the same way here. Half the fleet's\n * hand-written versions compared case-sensitively and would have rendered a\n * footer under the chat pane on `/Explore`.\n */\nexport function normalizeRoutePath(pathname: string): string {\n const trimmed = pathname.toLowerCase().replace(/\\/+$/, \"\");\n return trimmed === \"\" ? \"/\" : trimmed;\n}\n\n/**\n * True when this pathname is one of the SDK's full-screen surfaces.\n *\n * Deliberately an exact-set test. `startsWith(\"/explore\")` would also swallow a\n * future `/explore-beta`, and `includes(\"explore\")` would swallow far more —\n * including `/concept/explore-your-data`, which is a real shape of concept slug.\n */\nexport function isFooterlessPath(pathname: string): boolean {\n return FOOTERLESS_ROUTES.includes(normalizeRoutePath(pathname));\n}\n\n/** Inverse of {@link isFooterlessPath}, for layouts that read better positively. */\nexport function shouldRenderSiteFooter(pathname: string): boolean {\n return !isFooterlessPath(pathname);\n}\n","/**\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"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -1,124 +1,7 @@
1
- import { clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
3
-
4
- function cn(...inputs) {
5
- return twMerge(clsx(inputs));
6
- }
7
-
8
- // src/utils/recaptcha-v3.ts
9
- var SCRIPT_ID = "boff-recaptcha-v3";
10
- var SCRIPT_SRC = "https://www.google.com/recaptcha/api.js?render=";
11
- var EXPLORE_RECAPTCHA_ACTION = "explore_chat";
12
- var loaders = /* @__PURE__ */ new Map();
13
- function isBrowser() {
14
- return typeof window !== "undefined" && typeof document !== "undefined";
15
- }
16
- function loadRecaptchaV3(siteKey) {
17
- if (!siteKey) {
18
- return Promise.reject(new Error("reCAPTCHA site key is required"));
19
- }
20
- if (!isBrowser()) {
21
- return Promise.reject(
22
- new Error("reCAPTCHA v3 can only be loaded in a browser")
23
- );
24
- }
25
- const existing = loaders.get(siteKey);
26
- if (existing) return existing;
27
- const promise = new Promise((resolve, reject) => {
28
- const ready = () => {
29
- const api = window.grecaptcha;
30
- if (!api) {
31
- reject(new Error("reCAPTCHA loaded but grecaptcha is unavailable"));
32
- return;
33
- }
34
- api.ready(() => resolve(api));
35
- };
36
- if (window.grecaptcha) {
37
- ready();
38
- return;
39
- }
40
- const scriptId = `${SCRIPT_ID}-${siteKey}`;
41
- const found = document.getElementById(scriptId);
42
- if (found) {
43
- found.addEventListener("load", ready, { once: true });
44
- found.addEventListener(
45
- "error",
46
- () => reject(new Error("Failed to load reCAPTCHA v3")),
47
- { once: true }
48
- );
49
- return;
50
- }
51
- const script = document.createElement("script");
52
- script.id = scriptId;
53
- script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;
54
- script.async = true;
55
- script.defer = true;
56
- script.addEventListener("load", ready, { once: true });
57
- script.addEventListener(
58
- "error",
59
- () => {
60
- loaders.delete(siteKey);
61
- reject(new Error("Failed to load reCAPTCHA v3"));
62
- },
63
- { once: true }
64
- );
65
- document.head.appendChild(script);
66
- });
67
- loaders.set(siteKey, promise);
68
- return promise;
69
- }
70
- async function getRecaptchaV3Token(siteKey, action = EXPLORE_RECAPTCHA_ACTION) {
71
- const api = await loadRecaptchaV3(siteKey);
72
- return api.execute(siteKey, { action });
73
- }
74
-
75
- // src/utils/site-chrome.ts
76
- var FOOTERLESS_ROUTES = ["/explore"];
77
- function normalizeRoutePath(pathname) {
78
- const trimmed = pathname.toLowerCase().replace(/\/+$/, "");
79
- return trimmed === "" ? "/" : trimmed;
80
- }
81
- function isFooterlessPath(pathname) {
82
- return FOOTERLESS_ROUTES.includes(normalizeRoutePath(pathname));
83
- }
84
- function shouldRenderSiteFooter(pathname) {
85
- return !isFooterlessPath(pathname);
86
- }
87
-
88
- // src/utils/product-slug.ts
89
- var PRODUCT_SLUG_RENAMES = Object.freeze(
90
- [Object.freeze({ legacy: "botlit", current: "botmanor" })]
91
- );
92
- var PRODUCT_SLUG_ALIASES = Object.freeze(
93
- Object.fromEntries(PRODUCT_SLUG_RENAMES.map((r) => [r.legacy, r.current]))
94
- );
95
- var PRODUCT_SLUG_EMIT = Object.freeze({ productSlug: "current" });
96
- function findRename(slug) {
97
- const wanted = slug.toLowerCase();
98
- return PRODUCT_SLUG_RENAMES.find(
99
- (r) => r.legacy === wanted || r.current === wanted
100
- );
101
- }
102
- function normalizeProductSlug(slug) {
103
- if (slug == null) return slug;
104
- return findRename(slug)?.current ?? slug;
105
- }
106
- function legacyProductSlug(slug) {
107
- return findRename(slug)?.legacy ?? slug;
108
- }
109
- function productSlugVariants(slug) {
110
- return [
111
- .../* @__PURE__ */ new Set([slug, normalizeProductSlug(slug), legacyProductSlug(slug)])
112
- ];
113
- }
114
- function isSameProductSlug(a, b) {
115
- if (a == null || b == null) return a === b;
116
- return a === b || normalizeProductSlug(a) === normalizeProductSlug(b);
117
- }
118
- function emitProductSlug(slug) {
119
- return PRODUCT_SLUG_EMIT.productSlug === "current" ? normalizeProductSlug(slug) : legacyProductSlug(slug);
120
- }
121
-
122
- export { EXPLORE_RECAPTCHA_ACTION, FOOTERLESS_ROUTES, PRODUCT_SLUG_ALIASES, PRODUCT_SLUG_EMIT, PRODUCT_SLUG_RENAMES, cn, emitProductSlug, getRecaptchaV3Token, isFooterlessPath, isSameProductSlug, legacyProductSlug, loadRecaptchaV3, normalizeProductSlug, normalizeRoutePath, productSlugVariants, shouldRenderSiteFooter };
1
+ export { FOOTERLESS_ROUTES, isFooterlessPath, normalizeRoutePath, shouldRenderSiteFooter } from '../chunk-PIHHPP7J.mjs';
2
+ export { EXPLORE_RECAPTCHA_ACTION, getRecaptchaV3Token, loadRecaptchaV3 } from '../chunk-SKIYDKIS.mjs';
3
+ export { cn } from '../chunk-R7G6TWIS.mjs';
4
+ export { PRODUCT_SLUG_ALIASES, PRODUCT_SLUG_EMIT, PRODUCT_SLUG_RENAMES, emitProductSlug, isSameProductSlug, legacyProductSlug, normalizeProductSlug, productSlugVariants } from '../chunk-KZANIV3S.mjs';
5
+ import '../chunk-VNS5WDWO.mjs';
123
6
  //# sourceMappingURL=index.mjs.map
124
7
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/cn.ts","../../src/utils/recaptcha-v3.ts","../../src/utils/site-chrome.ts","../../src/utils/product-slug.ts"],"names":[],"mappings":";;;AAmBO,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;;;ACMA,IAAM,SAAA,GAAY,mBAAA;AAClB,IAAM,UAAA,GAAa,iDAAA;AAGZ,IAAM,wBAAA,GAA2B;AAOxC,IAAM,OAAA,uBAAc,GAAA,EAAkC;AAEtD,SAAS,SAAA,GAAqB;AAC5B,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,QAAA,KAAa,WAAA;AAC9D;AAaO,SAAS,gBAAgB,OAAA,EAAuC;AACrE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAI,KAAA,CAAM,gCAAgC,CAAC,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,CAAC,WAAU,EAAG;AAChB,IAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,MACb,IAAI,MAAM,8CAA8C;AAAA,KAC1D;AAAA,EACF;AAEA,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA;AACpC,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAqB,CAAC,SAAS,MAAA,KAAW;AAC5D,IAAA,MAAM,QAAQ,MAAM;AAClB,MAAA,MAAM,MAAM,MAAA,CAAO,UAAA;AACnB,MAAA,IAAI,CAAC,GAAA,EAAK;AACR,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,gDAAgD,CAAC,CAAA;AAClE,QAAA;AAAA,MACF;AAGA,MAAA,GAAA,CAAI,KAAA,CAAM,MAAM,OAAA,CAAQ,GAAG,CAAC,CAAA;AAAA,IAC9B,CAAA;AAGA,IAAA,IAAI,OAAO,UAAA,EAAY;AACrB,MAAA,KAAA,EAAM;AACN,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA;AACxC,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,cAAA,CAAe,QAAQ,CAAA;AAC9C,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,KAAA,CAAM,iBAAiB,MAAA,EAAQ,KAAA,EAAO,EAAE,IAAA,EAAM,MAAM,CAAA;AACpD,MAAA,KAAA,CAAM,gBAAA;AAAA,QACJ,OAAA;AAAA,QACA,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA;AAAA,QACrD,EAAE,MAAM,IAAA;AAAK,OACf;AACA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,IAAA,MAAA,CAAO,EAAA,GAAK,QAAA;AACZ,IAAA,MAAA,CAAO,MAAM,CAAA,EAAG,UAAU,CAAA,EAAG,kBAAA,CAAmB,OAAO,CAAC,CAAA,CAAA;AACxD,IAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,IAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,IAAA,MAAA,CAAO,iBAAiB,MAAA,EAAQ,KAAA,EAAO,EAAE,IAAA,EAAM,MAAM,CAAA;AACrD,IAAA,MAAA,CAAO,gBAAA;AAAA,MACL,OAAA;AAAA,MACA,MAAM;AAGJ,QAAA,OAAA,CAAQ,OAAO,OAAO,CAAA;AACtB,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,6BAA6B,CAAC,CAAA;AAAA,MACjD,CAAA;AAAA,MACA,EAAE,MAAM,IAAA;AAAK,KACf;AACA,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,MAAM,CAAA;AAAA,EAClC,CAAC,CAAA;AAED,EAAA,OAAA,CAAQ,GAAA,CAAI,SAAS,OAAO,CAAA;AAC5B,EAAA,OAAO,OAAA;AACT;AAQA,eAAsB,mBAAA,CACpB,OAAA,EACA,MAAA,GAAiB,wBAAA,EACA;AACjB,EAAA,MAAM,GAAA,GAAM,MAAM,eAAA,CAAgB,OAAO,CAAA;AACzC,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,OAAA,EAAS,EAAE,QAAQ,CAAA;AACxC;;;ACpGO,IAAM,iBAAA,GAAuC,CAAC,UAAU;AAWxD,SAAS,mBAAmB,QAAA,EAA0B;AAC3D,EAAA,MAAM,UAAU,QAAA,CAAS,WAAA,EAAY,CAAE,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACzD,EAAA,OAAO,OAAA,KAAY,KAAK,GAAA,GAAM,OAAA;AAChC;AASO,SAAS,iBAAiB,QAAA,EAA2B;AAC1D,EAAA,OAAO,iBAAA,CAAkB,QAAA,CAAS,kBAAA,CAAmB,QAAQ,CAAC,CAAA;AAChE;AAGO,SAAS,uBAAuB,QAAA,EAA2B;AAChE,EAAA,OAAO,CAAC,iBAAiB,QAAQ,CAAA;AACnC;;;AC3CO,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":"index.mjs","sourcesContent":["/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * reCAPTCHA v3 (invisible, score-based) loader and token minter.\n *\n * Deliberately dependency-free: the SDK already ships the `react-google-recaptcha`\n * peer for the **v2 checkbox** used by `ContactPage`, and the two widgets cannot\n * share a script tag — v3 needs `?render=<siteKey>` on the URL, v2 must not have\n * it. This module injects its own v3 script and leaves the v2 integration alone.\n *\n * The Explore chat turns v3 on purely from the backend catalog\n * (`exploreCatalog.captchaRequired && recaptchaSiteKey`), so nothing is loaded\n * and no third-party request is made on sites where captcha is off.\n */\n\n/** The slice of the `grecaptcha` global this module uses. */\nexport interface RecaptchaV3 {\n /** Runs the callback once the API is fully initialised. */\n ready(callback: () => void): void;\n /** Mints a single-use token for `action`. */\n execute(siteKey: string, options: { action: string }): Promise<string>;\n}\n\ndeclare global {\n interface Window {\n grecaptcha?: RecaptchaV3;\n }\n}\n\nconst SCRIPT_ID = \"boff-recaptcha-v3\";\nconst SCRIPT_SRC = \"https://www.google.com/recaptcha/api.js?render=\";\n\n/** Default action name reported to reCAPTCHA for Explore chat submissions. */\nexport const EXPLORE_RECAPTCHA_ACTION = \"explore_chat\";\n\n/**\n * One in-flight/settled promise per site key. Guarantees the script tag is\n * injected at most once even when several components mount at the same time,\n * and lets later callers await the same load instead of racing it.\n */\nconst loaders = new Map<string, Promise<RecaptchaV3>>();\n\nfunction isBrowser(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\n/**\n * Load the reCAPTCHA v3 script for `siteKey` and resolve once `grecaptcha` is\n * ready to mint tokens.\n *\n * - Injects the script at most once per site key (subsequent calls reuse the\n * same promise).\n * - Adopts an already-present script tag (e.g. injected by the host site)\n * rather than adding a second one.\n * - Rejects rather than hanging when the script fails to load, so the caller\n * can decide whether to submit without a token or surface an error.\n */\nexport function loadRecaptchaV3(siteKey: string): Promise<RecaptchaV3> {\n if (!siteKey) {\n return Promise.reject(new Error(\"reCAPTCHA site key is required\"));\n }\n if (!isBrowser()) {\n return Promise.reject(\n new Error(\"reCAPTCHA v3 can only be loaded in a browser\"),\n );\n }\n\n const existing = loaders.get(siteKey);\n if (existing) return existing;\n\n const promise = new Promise<RecaptchaV3>((resolve, reject) => {\n const ready = () => {\n const api = window.grecaptcha;\n if (!api) {\n reject(new Error(\"reCAPTCHA loaded but grecaptcha is unavailable\"));\n return;\n }\n // `ready` queues until the API has finished initialising internally;\n // calling `execute` before that throws.\n api.ready(() => resolve(api));\n };\n\n // Already loaded by this module, another SDK instance, or the host site.\n if (window.grecaptcha) {\n ready();\n return;\n }\n\n const scriptId = `${SCRIPT_ID}-${siteKey}`;\n const found = document.getElementById(scriptId);\n if (found) {\n found.addEventListener(\"load\", ready, { once: true });\n found.addEventListener(\n \"error\",\n () => reject(new Error(\"Failed to load reCAPTCHA v3\")),\n { once: true },\n );\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = scriptId;\n script.src = `${SCRIPT_SRC}${encodeURIComponent(siteKey)}`;\n script.async = true;\n script.defer = true;\n script.addEventListener(\"load\", ready, { once: true });\n script.addEventListener(\n \"error\",\n () => {\n // Drop the memo so a later attempt can retry a transient CDN failure\n // instead of being stuck with a permanently rejected promise.\n loaders.delete(siteKey);\n reject(new Error(\"Failed to load reCAPTCHA v3\"));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n\n loaders.set(siteKey, promise);\n return promise;\n}\n\n/**\n * Mint a single-use reCAPTCHA v3 token, loading the script on first use.\n *\n * Tokens are valid for ~2 minutes and are consumed by one verification, so\n * this must be called per submission — never cached.\n */\nexport async function getRecaptchaV3Token(\n siteKey: string,\n action: string = EXPLORE_RECAPTCHA_ACTION,\n): Promise<string> {\n const api = await loadRecaptchaV3(siteKey);\n return api.execute(siteKey, { action });\n}\n","/**\n * Which routes a host site should render WITHOUT its marketing footer.\n *\n * ## Why this lives in the SDK\n *\n * It was written 39 times. The footer belongs to each website, so the obvious\n * place for the rule is each website — and eight agents asked to add it produced\n * five different helpers (`footerless-routes.ts`, `footer-visibility.ts`,\n * `footer-routes.ts`, `explore-route.ts`, plus six copies inlined straight into\n * a layout). All five behave the same today. The next person to change the rule\n * has to find all five, and will not.\n *\n * The rule is really a property of the SDK's own surfaces: `/explore` is\n * footerless because `ExplorePage` sizes itself to one viewport, which is a fact\n * about this package, not about any site. So it is declared here, once, and the\n * sites ask.\n *\n * ## Why `/explore` and nothing else\n *\n * `ExplorePage` renders a full-viewport chat pane (`100dvh` minus the site\n * chrome above it), so anything after it is below the fold by construction. On a\n * phone these footers are 1100-1330px — roughly 70% of the document — and that\n * bulk is what allowed a restored scroll offset to open the page on nothing but\n * footer, with zero pixels of the chat on screen.\n *\n * The SDK's OTHER pages are the opposite case and must keep their footer:\n * `/concepts`, `/concept/:slug`, `/answers` and `/answer/:slug` are ordinary\n * indexed content pages whose footer carries the site's internal links.\n * Stripping it would cost hundreds of pages their internal linking, and nobody\n * would notice for weeks.\n */\n\n/** Routes that render without the site footer. Exact paths, not prefixes. */\nexport const FOOTERLESS_ROUTES: readonly string[] = [\"/explore\"];\n\n/**\n * Normalise a router pathname for exact comparison.\n *\n * React Router matches case-insensitively (`caseSensitive` defaults to false)\n * and tolerates a trailing slash, so `/Explore/` reaches the same route element\n * as `/explore` and has to be treated the same way here. Half the fleet's\n * hand-written versions compared case-sensitively and would have rendered a\n * footer under the chat pane on `/Explore`.\n */\nexport function normalizeRoutePath(pathname: string): string {\n const trimmed = pathname.toLowerCase().replace(/\\/+$/, \"\");\n return trimmed === \"\" ? \"/\" : trimmed;\n}\n\n/**\n * True when this pathname is one of the SDK's full-screen surfaces.\n *\n * Deliberately an exact-set test. `startsWith(\"/explore\")` would also swallow a\n * future `/explore-beta`, and `includes(\"explore\")` would swallow far more —\n * including `/concept/explore-your-data`, which is a real shape of concept slug.\n */\nexport function isFooterlessPath(pathname: string): boolean {\n return FOOTERLESS_ROUTES.includes(normalizeRoutePath(pathname));\n}\n\n/** Inverse of {@link isFooterlessPath}, for layouts that read better positively. */\nexport function shouldRenderSiteFooter(pathname: string): boolean {\n return !isFooterlessPath(pathname);\n}\n","/**\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"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/website-sdk",
3
- "version": "2026.1031.3",
3
+ "version": "2026.1101.2",
4
4
  "description": "Shared SDK for Burdenoff product websites - reusable React components, utilities, and configurations",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -72,6 +72,7 @@
72
72
  "README.md",
73
73
  "LICENSE"
74
74
  ],
75
+ "sideEffects": false,
75
76
  "scripts": {
76
77
  "build": "tsup && node scripts/validate-avatar-live.mjs",
77
78
  "dev": "tsup --watch",