@envive-ai/react-hooks 0.1.0 → 0.1.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 (302) hide show
  1. package/dist/adapters/amplitude/index.cjs +14 -0
  2. package/dist/adapters/amplitude/index.d.cts +4 -0
  3. package/dist/adapters/amplitude/index.d.ts +4 -0
  4. package/dist/adapters/amplitude/index.js +12 -0
  5. package/dist/api-B2euFL-5.cjs +268 -0
  6. package/dist/api-CxGedDxj.cjs +5057 -0
  7. package/dist/api-NJEaveju.js +4113 -0
  8. package/dist/api-XRr_lAG6.js +189 -0
  9. package/dist/application/config/index.cjs +34 -0
  10. package/dist/application/config/index.d.cts +14 -0
  11. package/dist/application/config/index.d.ts +14 -0
  12. package/dist/application/config/index.js +32 -0
  13. package/dist/application/models/graphql/index.cjs +13 -0
  14. package/dist/application/models/graphql/index.d.cts +2 -0
  15. package/dist/application/models/graphql/index.d.ts +2 -0
  16. package/dist/application/models/graphql/index.js +12 -0
  17. package/dist/application/models/guards/api/index.cjs +15 -0
  18. package/dist/application/models/guards/api/index.d.cts +3 -0
  19. package/dist/application/models/guards/api/index.d.ts +3 -0
  20. package/dist/application/models/guards/api/index.js +4 -0
  21. package/dist/application/models/index.cjs +72 -0
  22. package/dist/application/models/index.d.cts +10 -0
  23. package/dist/application/models/index.d.ts +10 -0
  24. package/dist/application/models/index.js +12 -0
  25. package/dist/application/models/utilityTypes/index.cjs +1 -0
  26. package/dist/application/models/utilityTypes/index.d.cts +2 -0
  27. package/dist/application/models/utilityTypes/index.d.ts +2 -0
  28. package/dist/application/models/utilityTypes/index.js +3 -0
  29. package/dist/application/models/variantInfo/index.cjs +1 -0
  30. package/dist/application/models/variantInfo/index.d.cts +2 -0
  31. package/dist/application/models/variantInfo/index.d.ts +2 -0
  32. package/dist/application/models/variantInfo/index.js +3 -0
  33. package/dist/application/service/customerService/index.cjs +4 -0
  34. package/dist/application/service/customerService/index.d.cts +3 -0
  35. package/dist/application/service/customerService/index.d.ts +3 -0
  36. package/dist/application/service/customerService/index.js +4 -0
  37. package/dist/application/service/index.cjs +761 -0
  38. package/dist/application/service/index.d.cts +407 -0
  39. package/dist/application/service/index.d.ts +407 -0
  40. package/dist/application/service/index.js +727 -0
  41. package/dist/application/utils/index.cjs +38 -0
  42. package/dist/application/utils/index.d.cts +254 -0
  43. package/dist/application/utils/index.d.ts +254 -0
  44. package/dist/application/utils/index.js +12 -0
  45. package/dist/atomStore-B3tsg6mF.cjs +0 -0
  46. package/dist/atomStore-BFtpknLM.js +31 -0
  47. package/dist/atomStore-CeJm9Llb.cjs +57 -0
  48. package/dist/atomStore-FSZd_20F.js +1 -0
  49. package/dist/atoms/app/index.cjs +17 -0
  50. package/dist/atoms/app/index.d.cts +33 -0
  51. package/dist/atoms/app/index.d.ts +33 -0
  52. package/dist/atoms/app/index.js +12 -0
  53. package/dist/atoms/atomStore/index.cjs +7 -0
  54. package/dist/atoms/atomStore/index.d.cts +23 -0
  55. package/dist/atoms/atomStore/index.d.ts +23 -0
  56. package/dist/atoms/atomStore/index.js +4 -0
  57. package/dist/atoms/chat/index.cjs +41 -0
  58. package/dist/atoms/chat/index.d.cts +159 -0
  59. package/dist/atoms/chat/index.d.ts +159 -0
  60. package/dist/atoms/chat/index.js +12 -0
  61. package/dist/atoms/globalSearch/index.cjs +6 -0
  62. package/dist/atoms/globalSearch/index.d.cts +23 -0
  63. package/dist/atoms/globalSearch/index.d.ts +23 -0
  64. package/dist/atoms/globalSearch/index.js +3 -0
  65. package/dist/atoms/org/index.cjs +41 -0
  66. package/dist/atoms/org/index.d.cts +93 -0
  67. package/dist/atoms/org/index.d.ts +93 -0
  68. package/dist/atoms/org/index.js +13 -0
  69. package/dist/atoms/search/index.cjs +44 -0
  70. package/dist/atoms/search/index.d.cts +11 -0
  71. package/dist/atoms/search/index.d.ts +11 -0
  72. package/dist/atoms/search/index.js +14 -0
  73. package/dist/{bandolier-Ble8jEa8.js → bandolier-C7PAIw02.js} +16 -7
  74. package/dist/{bandolier-Bm2xAt_j.cjs → bandolier-oMkFDJMF.cjs} +55 -46
  75. package/dist/{carpe-Da7b-LCW.cjs → carpe-C0ccKuR9.cjs} +34 -25
  76. package/dist/{carpe-W13mhRRP.js → carpe-DFc78_lJ.js} +16 -7
  77. package/dist/chat-CCgyDehy.cjs +151 -0
  78. package/dist/chat-Dk6KPb1K.js +25 -0
  79. package/dist/components-CScS7Ii-.cjs +28 -0
  80. package/dist/components-DAQxVIn9.js +10 -0
  81. package/dist/config/locators/components/chat/index.cjs +23 -0
  82. package/dist/config/locators/components/chat/index.d.cts +2 -0
  83. package/dist/config/locators/components/chat/index.d.ts +2 -0
  84. package/dist/config/locators/components/chat/index.js +3 -0
  85. package/dist/config/locators/components/chat/variants/index.cjs +28 -0
  86. package/dist/config/locators/components/chat/variants/index.d.cts +15 -0
  87. package/dist/config/locators/components/chat/variants/index.d.ts +15 -0
  88. package/dist/config/locators/components/chat/variants/index.js +16 -0
  89. package/dist/config/locators/components/index.cjs +5 -0
  90. package/dist/config/locators/components/index.d.cts +2 -0
  91. package/dist/config/locators/components/index.d.ts +2 -0
  92. package/dist/config/locators/components/index.js +3 -0
  93. package/dist/config/locators/components/search/index.cjs +12 -0
  94. package/dist/config/locators/components/search/index.d.cts +7 -0
  95. package/dist/config/locators/components/search/index.d.ts +7 -0
  96. package/dist/config/locators/components/search/index.js +8 -0
  97. package/dist/config/locators/index.cjs +47 -0
  98. package/dist/config/locators/index.d.cts +24 -0
  99. package/dist/config/locators/index.d.ts +24 -0
  100. package/dist/config/locators/index.js +6 -0
  101. package/dist/contexts/index.cjs +19 -3
  102. package/dist/contexts/index.d.cts +16 -22
  103. package/dist/contexts/index.d.ts +19 -26
  104. package/dist/contexts/index.js +15 -4
  105. package/dist/contexts-DO75-Kmx.js +7152 -0
  106. package/dist/contexts-iAzSvZjb.cjs +7331 -0
  107. package/dist/{coterie-DOWcJAYv.js → coterie-BGT8hqFR.js} +18 -7
  108. package/dist/{coterie-3y0D9ko4.cjs → coterie-Cp9FAJTQ.cjs} +25 -14
  109. package/dist/customerService-CUyZzowx.js +22 -0
  110. package/dist/customerService-DqPw_XKf.cjs +35 -0
  111. package/dist/custservice-types-D8Npo-5Z.js +22 -0
  112. package/dist/custservice-types-E9_OSaZ7.cjs +34 -0
  113. package/dist/{default-D_KPZdPJ.cjs → default-BAXPatxf.cjs} +1 -1
  114. package/dist/default-BR3225LZ.js +4 -0
  115. package/dist/default-DR6YjE9B.cjs +4 -0
  116. package/dist/{default-C2fEZKXk.js → default-wf_IORgo.js} +1 -1
  117. package/dist/divIds-BWvq-i6I.js +22 -0
  118. package/dist/{divIds-DnZNd7rA.cjs → divIds-CFyAjjp3.cjs} +6 -99
  119. package/dist/{dreamlandBaby-DCIsuU9R.cjs → dreamlandBaby-BzuMvUFS.cjs} +27 -18
  120. package/dist/{dreamlandBaby-DvSaZGrz.js → dreamlandBaby-DZvM81LQ.js} +16 -7
  121. package/dist/embedded-BlXJUbik.cjs +130 -0
  122. package/dist/embedded-C1jvFj3v.js +22 -0
  123. package/dist/events/index.cjs +4 -0
  124. package/dist/events/index.d.cts +45 -0
  125. package/dist/events/index.d.ts +45 -0
  126. package/dist/events/index.js +3 -0
  127. package/dist/events-ClCDFK7t.js +77 -0
  128. package/dist/events-Da7gpmGv.cjs +89 -0
  129. package/dist/featureFlagService-CroFRxvD.d.cts +17 -0
  130. package/dist/featureFlagService-NkJ2fuEj.d.ts +17 -0
  131. package/dist/featureGates-BMWXU0dS.d.ts +90 -0
  132. package/dist/featureGates-N_gyHCTn.d.cts +90 -0
  133. package/dist/{fiveCbd-CkOlVby_.cjs → fiveCbd-DE-tDY3d.cjs} +31 -22
  134. package/dist/{fiveCbd-B1SESMCO.js → fiveCbd-HNBPqPtX.js} +16 -7
  135. package/dist/{forLoveAndLemons-DmwYZIk0.js → forLoveAndLemons-BKmJJ9pq.js} +13 -5
  136. package/dist/{forLoveAndLemons-CfYPMnKS.cjs → forLoveAndLemons-BeVEBOiu.cjs} +17 -9
  137. package/dist/frontendConfig-KeNqU1wa.d.cts +790 -0
  138. package/dist/frontendConfig-cPvCTWm6.d.ts +790 -0
  139. package/dist/globalSearch-BC0rOX3E.js +13 -0
  140. package/dist/globalSearch-hxbXekus.cjs +38 -0
  141. package/dist/{greenpan-BtOi45lf.js → greenpan-BX1viAZB.js} +16 -7
  142. package/dist/{greenpan-Bsl3ir59.cjs → greenpan-chd3aa5I.cjs} +29 -20
  143. package/dist/{grooveLife-6_dtYsRk.js → grooveLife-CHot3rZw.js} +17 -8
  144. package/dist/{grooveLife-Cmm1PSCL.cjs → grooveLife-DEob7rK0.cjs} +28 -19
  145. package/dist/{homegrownCannabis-CO0uY_mp.cjs → homegrownCannabis-CoIjcehi.cjs} +27 -16
  146. package/dist/{homegrownCannabis-C-kw-74X.js → homegrownCannabis-CwkS1qDA.js} +17 -6
  147. package/dist/hooks/index.cjs +26 -3
  148. package/dist/hooks/index.d.cts +220 -299
  149. package/dist/hooks/index.d.ts +220 -299
  150. package/dist/hooks/index.js +15 -4
  151. package/dist/index-BdNKc2ix.d.cts +8 -0
  152. package/dist/index-BkhvV8RZ.d.cts +202 -0
  153. package/dist/index-BrXuc_Ck.d.cts +24 -0
  154. package/dist/{chatElementDisplayLocation-CX8fuNao.d.cts → index-C4zjAR1c.d.cts} +18 -30
  155. package/dist/index-CGB6CAmr.d.ts +6 -0
  156. package/dist/index-CIco0cCQ.d.ts +183 -0
  157. package/dist/index-COG1kOZG.d.ts +749 -0
  158. package/dist/index-CVxe7FpL.d.cts +6 -0
  159. package/dist/index-Cn1SeI5y.d.cts +183 -0
  160. package/dist/index-Cqg6ltII.d.ts +38 -0
  161. package/dist/index-CzMrMKx-.d.ts +202 -0
  162. package/dist/index-DE_7Q8qK.d.ts +94 -0
  163. package/dist/index-Da0UzyI9.d.ts +24 -0
  164. package/dist/index-DbWWcYax.d.cts +749 -0
  165. package/dist/index-DtoVXd6O.d.cts +97 -0
  166. package/dist/index-JClBRnSX.d.cts +94 -0
  167. package/dist/index-ghzD_356.d.ts +8 -0
  168. package/dist/index-hdbCEjYy.d.cts +38 -0
  169. package/dist/index-luJrHgPN.d.ts +97 -0
  170. package/dist/{chatElementDisplayLocation-CwptS9tx.d.ts → index-tfRj22E1.d.ts} +18 -30
  171. package/dist/interceptors/index.cjs +14 -0
  172. package/dist/interceptors/index.d.cts +25 -0
  173. package/dist/interceptors/index.d.ts +25 -0
  174. package/dist/interceptors/index.js +13 -0
  175. package/dist/{jackArcher-CLVmwwpI.js → jackArcher-BA-pkB4A.js} +16 -7
  176. package/dist/{jackArcher-DdYTIzAV.cjs → jackArcher-bewC0q1T.cjs} +33 -24
  177. package/dist/{jordanCraig-_u3-w4Hp.cjs → jordanCraig-B5k9nlAw.cjs} +76 -67
  178. package/dist/{jordanCraig-Am-Oor-O.js → jordanCraig-BsQ1mYbt.js} +16 -7
  179. package/dist/{kindredBravely-eWp-ud_E.js → kindredBravely-BxYkCpGY.js} +15 -6
  180. package/dist/{kindredBravely-CWovIDSc.cjs → kindredBravely-DsN0fo3s.cjs} +26 -17
  181. package/dist/{kutFromTheKloth-Q589bAOC.cjs → kutFromTheKloth-BQTCu3ct.cjs} +27 -18
  182. package/dist/{kutFromTheKloth-BMV4BuGQ.js → kutFromTheKloth-bukOQM3P.js} +16 -7
  183. package/dist/{larryAndSerges-BMUlTgI-.js → larryAndSerges-D1ecaT5a.js} +14 -5
  184. package/dist/{larryAndSerges-CEau764j.cjs → larryAndSerges-bj7fgy9b.cjs} +21 -12
  185. package/dist/{leapsAndRebounds-DHAtRTJD.cjs → leapsAndRebounds-BfneG_0c.cjs} +29 -20
  186. package/dist/{leapsAndRebounds-DGMzPO7T.js → leapsAndRebounds-DhNpZETg.js} +16 -7
  187. package/dist/locators-C2DX_nX6.js +1 -0
  188. package/dist/locators-CUpyd9Wt.cjs +0 -0
  189. package/dist/{longevityrx-jH2JLhNH.js → longevityrx-CnoGcw0w.js} +16 -7
  190. package/dist/{longevityrx-CZW8Hxzi.cjs → longevityrx-D0goIuX0.cjs} +24 -15
  191. package/dist/{lookOptic-CA6RwLbG.cjs → lookOptic-C4afLPZP.cjs} +24 -15
  192. package/dist/{lookOptic-BGXP5P_V.js → lookOptic-uJWIKpER.js} +16 -7
  193. package/dist/{mantraBrand-DByNqpnL.cjs → mantraBrand-8JUlYtCE.cjs} +45 -36
  194. package/dist/{mantraBrand-Cm9_PBCT.js → mantraBrand-DuwKHM26.js} +17 -8
  195. package/dist/{medterra-B0wxj_PV.js → medterra-BQec8rzn.js} +16 -7
  196. package/dist/{medterra-DnPN2ksU.cjs → medterra-DH067P-V.cjs} +36 -27
  197. package/dist/{modells-Bmz8Ag5M.js → modells-DAgLE2xo.js} +16 -7
  198. package/dist/{modells-CoYgkLSp.cjs → modells-DUFnLmAz.cjs} +30 -21
  199. package/dist/nodeSelector-DpKXszfU.d.ts +30 -0
  200. package/dist/nodeSelector-vKB44CDB.d.cts +30 -0
  201. package/dist/org-C11APG3v.js +63 -0
  202. package/dist/org-CnHL2I9B.cjs +106 -0
  203. package/dist/{pressedFloral-DjBiSoUl.cjs → pressedFloral-DVZVfOSQ.cjs} +35 -26
  204. package/dist/{pressedFloral-DSKs_oVG.js → pressedFloral-MdbuoRyA.js} +16 -7
  205. package/dist/search-CvHb1M3S.js +542 -0
  206. package/dist/search-bSYdOBhY.cjs +743 -0
  207. package/dist/search-filter-types-BsJjrxk0.d.ts +101 -0
  208. package/dist/search-filter-types-CqaGK3nM.d.cts +101 -0
  209. package/dist/{skinPerfection-B_3xzVNS.cjs → skinPerfection-BcEWICQN.cjs} +24 -15
  210. package/dist/{skinPerfection-IDrBuAPt.js → skinPerfection-bGiYxq1i.js} +16 -7
  211. package/dist/{snapSupplements-BStTsdOZ.cjs → snapSupplements-BXSXTjqF.cjs} +24 -15
  212. package/dist/{snapSupplements-BJk5T5ba.js → snapSupplements-D7hHhdC9.js} +16 -7
  213. package/dist/{spanx-BYg0LE7R.js → spanx-5-0yX3iK.js} +18 -9
  214. package/dist/{spanx-LwU1zSzq.cjs → spanx-lUzP6Lva.cjs} +30 -21
  215. package/dist/{spanxStaging-CfSmuKYB.js → spanxStaging-HglCMJag.js} +18 -9
  216. package/dist/{spanxStaging-OZLV9qix.cjs → spanxStaging-hreMR0MS.cjs} +34 -25
  217. package/dist/suggestionBarV2-types-B0RbMStE.js +9 -0
  218. package/dist/suggestionBarV2-types-DG3Ekk44.cjs +15 -0
  219. package/dist/{supergoop-CIlrHND_.js → supergoop-C9DDT3lY.js} +17 -7
  220. package/dist/{supergoop-BqPXDnKk.cjs → supergoop-CkjtuRck.cjs} +28 -18
  221. package/dist/test-types-C9b_OdfO.d.ts +39 -0
  222. package/dist/test-types-CpKCxk8U.d.cts +39 -0
  223. package/dist/types/index.cjs +6 -0
  224. package/dist/types/index.d.cts +3 -0
  225. package/dist/types/index.d.ts +3 -0
  226. package/dist/types/index.js +4 -0
  227. package/dist/types-BE4faOO_.d.cts +32 -0
  228. package/dist/{types-C4T5UOIW.cjs → types-BUjohkXp.cjs} +58 -58
  229. package/dist/{types-CYNvLeSA.js → types-BVsTRyxL.js} +58 -58
  230. package/dist/types-TD8g7LnH.d.ts +32 -0
  231. package/dist/{uniqueVintage-B30mOqbH.cjs → uniqueVintage-DIMGtYAU.cjs} +46 -37
  232. package/dist/{uniqueVintage-CFueJOhO.js → uniqueVintage-DPWA5Ed6.js} +16 -7
  233. package/dist/useMessageInterceptor-B-P_rw73.cjs +72 -0
  234. package/dist/useMessageInterceptor-C2RZM-fo.js +57 -0
  235. package/dist/utilityTypes-BVikejDo.js +1 -0
  236. package/dist/utilityTypes-C4h2wgAK.cjs +0 -0
  237. package/dist/variant-BGjOVpY3.d.cts +12 -0
  238. package/dist/variant-XITncuI3.d.ts +12 -0
  239. package/dist/variantInfo-CNRTY0gH.cjs +0 -0
  240. package/dist/variantInfo-CzhR5W6h.js +1 -0
  241. package/dist/{venaCbd-T0CqVD4k.js → venaCbd-B-znfAsl.js} +16 -7
  242. package/dist/{venaCbd-DHGZy49P.cjs → venaCbd-BOwOtpOz.cjs} +29 -20
  243. package/dist/{westonJonBoucher-BdMzs_Yg.cjs → westonJonBoucher-CraTzRVt.cjs} +29 -20
  244. package/dist/{westonJonBoucher-b4TCQ4ev.js → westonJonBoucher-DCRagGu3.js} +16 -7
  245. package/dist/{wineEnthusiast-BqR0i_54.js → wineEnthusiast-Bv7umajk.js} +16 -7
  246. package/dist/{wineEnthusiast-BLGlOjgr.cjs → wineEnthusiast-sVuATrq6.cjs} +28 -19
  247. package/dist/{wolfMattress-CyyO-LoC.js → wolfMattress-BUH-Rhov.js} +17 -6
  248. package/dist/{wolfMattress-DNGZOivg.cjs → wolfMattress-DpVHIEnJ.cjs} +29 -18
  249. package/dist/{wolfTactical-BmXYlFjr.cjs → wolfTactical-BcvF_sy-.cjs} +28 -19
  250. package/dist/{wolfTactical-3Mm2fvVF.js → wolfTactical-Q14A1fpw.js} +16 -7
  251. package/package.json +101 -3
  252. package/src/adapters/amplitude/amplitudeAdapter.ts +1 -1
  253. package/src/adapters/spiffy/commerce/api.ts +1 -1
  254. package/src/adapters/spiffy/commerce/graphql.ts +61 -37
  255. package/src/application/config/index.ts +1 -0
  256. package/src/application/models/index.ts +102 -17
  257. package/src/application/models/supportedOrgs.ts +89 -65
  258. package/src/application/service/index.ts +32 -0
  259. package/src/application/service/pageVariantService.ts +201 -114
  260. package/src/application/service/searchService.ts +1 -1
  261. package/src/application/service/windowFrontendConfigService.ts +40 -18
  262. package/src/application/utils/index.ts +22 -3
  263. package/src/atoms/app/variant.ts +48 -29
  264. package/src/atoms/atomStore/index.ts +1 -0
  265. package/src/atoms/chat/messageQueue.ts +34 -17
  266. package/src/atoms/chat/performanceMetrics.ts +51 -38
  267. package/src/atoms/chat/renderedWidgetRefs.ts +14 -15
  268. package/src/atoms/globalSearch/index.ts +1 -0
  269. package/src/atoms/org/org.ts +1 -3
  270. package/src/atoms/org/orgUIConfig.ts +31 -24
  271. package/src/contexts/chatContext.tsx +124 -72
  272. package/src/events/registerAnalyticsListeners.ts +13 -9
  273. package/src/hooks/useFileUpload.ts +9 -7
  274. package/src/hooks/useSearch.tsx +4 -7
  275. package/src/initialize.ts +2 -2
  276. package/src/interceptors/index.ts +3 -0
  277. package/src/main.tsx +11 -26
  278. package/src/types/index.ts +4 -0
  279. package/dist/GridInsertionService-CEYo9pGj.js +0 -22
  280. package/dist/GridInsertionService-CS_bnPh0.cjs +0 -28
  281. package/dist/contexts-BRjfVq_k.js +0 -5064
  282. package/dist/contexts-BYArqZtK.cjs +0 -5164
  283. package/dist/custservice-types-CFIFwZ-r.js +0 -10
  284. package/dist/custservice-types-CkfxZiHY.cjs +0 -16
  285. package/dist/default-CBUq6Q6G.cjs +0 -4
  286. package/dist/default-CGIFZK6m.js +0 -4
  287. package/dist/divIds-Bss-btao.js +0 -49
  288. package/dist/models-DHdb7QWn.js +0 -51
  289. package/dist/models-ixxUsGL_.cjs +0 -69
  290. package/dist/suggestionBarV2-types-BllzwsBD.js +0 -34
  291. package/dist/suggestionBarV2-types-CaovchMP.cjs +0 -46
  292. package/src/atoms/index.ts +0 -5
  293. package/src/index.ts +0 -31
  294. package/src/main.ts +0 -85
  295. /package/dist/{cdnService-zQfKk3Eb.js → cdnService-DvDSpfVJ.js} +0 -0
  296. /package/dist/{cdnService-CZ-aXcY6.cjs → cdnService-dJU3sHpF.cjs} +0 -0
  297. /package/dist/{entrypoints-YLQsbBRD.js → entrypoints-CmmOszXO.js} +0 -0
  298. /package/dist/{entrypoints-D_JUvkgy.cjs → entrypoints-fowCLUT2.cjs} +0 -0
  299. /package/dist/{socialProofClasses-CrQBWdSA.cjs → socialProofClasses-BYLiEXpU.cjs} +0 -0
  300. /package/dist/{socialProofClasses-Bhv2Vulz.js → socialProofClasses-CkJufEGb.js} +0 -0
  301. /package/src/atoms/{atomStore.ts → atomStore/atomStore.ts} +0 -0
  302. /package/src/atoms/{globalSearch.ts → globalSearch/globalSearch.ts} +0 -0
@@ -0,0 +1,4113 @@
1
+ import { logger_default } from "./logger-pdEEY8T2.js";
2
+ import { hasPropertyOfType, isApiPDPAttributes, isApiProductResponseAttributes, isApiProductSearchResponseAttributes, isApiQueryTypedAttributes, isApiResponse, isApiReviewResponseAttributes, isApiSearchAttributes, isApiSuggestionClickedAttributes, isApiTextResponseAttributes, isApiUserEvent, isSuggestion } from "./api-XRr_lAG6.js";
3
+ import { ColorNames, CustomerServiceIntegrationMode, OrgShortName, PageVariantTestType, getOrgInfo } from "./types-BVsTRyxL.js";
4
+ import { useEnviveConfig } from "./enviveConfigContext-CUGLpPGU.js";
5
+ import { getAtomStore, sessionStorageUtil } from "./atomStore-BFtpknLM.js";
6
+ import { findCustomerServiceImpl } from "./customerService-CUyZzowx.js";
7
+ import { EventsDispatcher, SpiffyEvent } from "./events-ClCDFK7t.js";
8
+ import { Configuration, ContextEnvEnum, ContextSourceEnum, CustomerServiceApi, DefaultApi, FormType, FulfillmentDisplayStatus, InferenceApi, OrganizationStatusEnum, PLPAttributeCategory, PageVisitCategory, ResponseCategory, ResponseError, SupportedEventProductCategory, UserEventCategory, V1OrgConfigGetSourceEnum } from "@spiffy-ai/commerce-api-client";
9
+ import { atom } from "jotai";
10
+ import { createInstance } from "@amplitude/analytics-browser";
11
+ import { atomWithStorage, createJSONStorage } from "jotai/utils";
12
+ import UAParser from "ua-parser-js";
13
+ import { v4 } from "uuid";
14
+ import { UserEventCategory as UserEventCategory$1 } from "@spiffy-ai/commerce-api-client/dist/models/UserEventCategory";
15
+ import { createPortal } from "react-dom";
16
+
17
+ //#region src/application/models/validators/validateSuggestion.ts
18
+ const validateSuggestion = (data) => {
19
+ if (!isSuggestion(data)) return;
20
+ return {
21
+ id: data.id,
22
+ category: data.category,
23
+ content: data.content,
24
+ createdAt: data.created_at,
25
+ isAnswer: data.is_answer
26
+ };
27
+ };
28
+
29
+ //#endregion
30
+ //#region src/application/models/guards/api/isApiPLPEventAttributes.ts
31
+ const isApiPLPIdAttribute = (data) => {
32
+ if (data == null || typeof data !== "object") return false;
33
+ if (!("id" in data) || typeof data.id !== "string") return false;
34
+ return true;
35
+ };
36
+ const isApiPLPEventAttributes = (data) => {
37
+ if (data == null || typeof data !== "object") return false;
38
+ if (!("category" in data) || typeof data.category !== "string" || !Object.values(PLPAttributeCategory).includes(data.category)) return false;
39
+ if (!("attributes" in data) || typeof data.attributes !== "object" || !isApiPLPIdAttribute(data.attributes)) return false;
40
+ return true;
41
+ };
42
+
43
+ //#endregion
44
+ //#region src/application/models/guards/api/isApiFormSubmittedResponseAttributes.ts
45
+ const isApiFormSubmittedResponseAttributes = (data) => {
46
+ if (data == null || typeof data !== "object") {
47
+ logger_default.logError("isApiFormSubmittedResponseAttributes", "data is null or not an object", data);
48
+ return false;
49
+ }
50
+ if (!hasPropertyOfType(data, "filled_schema", "object")) {
51
+ logger_default.logError("isApiFormSubmittedResponseAttributes", "filled_schema is not an object", data);
52
+ return false;
53
+ }
54
+ if (!hasPropertyOfType(data, "form_response_id", "string")) {
55
+ logger_default.logError("isApiFormSubmittedResponseAttributes", "form_response_id is not a string", data);
56
+ return false;
57
+ }
58
+ if (!("form_type" in data) || !Object.values(FormType).includes(data.form_type)) {
59
+ logger_default.logError("isApiFormSubmittedResponseAttributes", "form_type is not a valid form type enum", data);
60
+ return false;
61
+ }
62
+ return true;
63
+ };
64
+
65
+ //#endregion
66
+ //#region src/application/models/validators/validateUserEvent.ts
67
+ const validateUserEvent = (data) => {
68
+ if (!isApiUserEvent(data)) return;
69
+ if (data.category === UserEventCategory.PdpVisit && isApiPDPAttributes(data.attributes)) return {
70
+ eventId: data.event_id,
71
+ createdAt: data.created_at,
72
+ category: UserEventCategory.PdpVisit,
73
+ attributes: {
74
+ productId: data.attributes.product_id,
75
+ parentProductId: data.attributes.parent_product_id,
76
+ url: data.attributes.url
77
+ }
78
+ };
79
+ if (data.category === UserEventCategory.QueryTyped && isApiQueryTypedAttributes(data.attributes)) return {
80
+ eventId: data.event_id,
81
+ createdAt: data.created_at,
82
+ category: UserEventCategory.QueryTyped,
83
+ attributes: { query: data.attributes.query }
84
+ };
85
+ if (data.category === UserEventCategory.Search && isApiSearchAttributes(data.attributes)) return {
86
+ eventId: data.event_id,
87
+ createdAt: data.created_at,
88
+ category: UserEventCategory.Search,
89
+ attributes: {
90
+ searchTerm: data.attributes.search_term,
91
+ selectedFilters: data.attributes.selected_filters
92
+ }
93
+ };
94
+ if (data.category === UserEventCategory.SuggestionClicked && isApiSuggestionClickedAttributes(data.attributes)) return {
95
+ eventId: data.event_id,
96
+ createdAt: data.created_at,
97
+ category: UserEventCategory.SuggestionClicked,
98
+ attributes: { suggestionId: data.attributes.suggestion_id }
99
+ };
100
+ if (data.category === UserEventCategory.PlpVisit && isApiPLPEventAttributes(data.attributes)) {
101
+ if (isApiPLPIdAttribute(data.attributes)) return {
102
+ eventId: data.event_id,
103
+ createdAt: data.created_at,
104
+ category: UserEventCategory.PlpVisit,
105
+ attributes: {
106
+ category: data.attributes.category,
107
+ attributes: { id: data.attributes.id }
108
+ }
109
+ };
110
+ }
111
+ if (data.category === UserEventCategory.FormSubmitted && isApiFormSubmittedResponseAttributes(data.attributes)) return {
112
+ eventId: data.event_id,
113
+ createdAt: data.created_at,
114
+ category: UserEventCategory.FormSubmitted,
115
+ attributes: {
116
+ filledSchema: { ...data.attributes.filled_schema },
117
+ formResponseId: data.attributes.form_response_id,
118
+ formType: data.attributes.form_type
119
+ }
120
+ };
121
+ return {
122
+ eventId: data.event_id,
123
+ createdAt: data.created_at,
124
+ category: UserEventCategory.AppLoaded
125
+ };
126
+ };
127
+
128
+ //#endregion
129
+ //#region src/application/models/featureGates.ts
130
+ let FeatureGates = /* @__PURE__ */ function(FeatureGates$1) {
131
+ FeatureGates$1["IsClientSessionEnabled"] = "is_client_session_enabled";
132
+ FeatureGates$1["IsNewFeatureEnabled"] = "is_new_feature_enabled";
133
+ FeatureGates$1["IsFineTunedModel8b"] = "is_fine_tuned_model_8b";
134
+ FeatureGates$1["IsIntegratedCXEnabled"] = "is_integrated_cx_enabled";
135
+ FeatureGates$1["IsNonShapewearEnabled"] = "is_non_shapewear_enabled";
136
+ FeatureGates$1["IsImageBannerEnabled"] = "is_image_banner_enabled";
137
+ FeatureGates$1["IsOrderLookupEnabled"] = "is_order_lookup_enabled";
138
+ FeatureGates$1["IsSummarizeReviewsEnabled"] = "is_summarize_reviews_enabled";
139
+ FeatureGates$1["IsGlobalSearchEnabled"] = "is_global_search_enabled";
140
+ FeatureGates$1["IsImagePromptEnabled"] = "is_image_prompt_enabled";
141
+ FeatureGates$1["IsWatermarkEnabled"] = "is_watermark_enabled";
142
+ FeatureGates$1["IsInferenceRegion0"] = "is_inference_region_0";
143
+ FeatureGates$1["IsGraphQLUIConfigsEnabled"] = "is_graphql_ui_configs_enabled";
144
+ FeatureGates$1["IsGraphQLPageConfigsEnabled"] = "is_graphql_page_configs_enabled";
145
+ FeatureGates$1["IsGraphQLComponentConfigsEnabled"] = "is_graphql_component_configs_enabled";
146
+ FeatureGates$1["IsChatVariantEnabled"] = "is_chat_variant_enabled";
147
+ FeatureGates$1["IsChatVariantAEnabled"] = "is_chat_variant_a_enabled";
148
+ FeatureGates$1["IsChatVariantBEnabled"] = "is_chat_variant_b_enabled";
149
+ FeatureGates$1["IsUserQueryAlwaysEnabled"] = "is_user_query_always_enabled";
150
+ return FeatureGates$1;
151
+ }({});
152
+
153
+ //#endregion
154
+ //#region src/application/models/chatElementDisplayLocation.ts
155
+ let ChatElementDisplayLocation = /* @__PURE__ */ function(ChatElementDisplayLocation$1) {
156
+ ChatElementDisplayLocation$1["IN_CHAT"] = "in_chat";
157
+ ChatElementDisplayLocation$1["CHAT_PREVIEW"] = "chat_preview";
158
+ ChatElementDisplayLocation$1["FLOATING_BUTTON"] = "floating_button";
159
+ ChatElementDisplayLocation$1["HELP_ME_CHOOSE"] = "help_me_choose";
160
+ ChatElementDisplayLocation$1["PLP_IMAGE_BANNER"] = "plp_image_banner";
161
+ ChatElementDisplayLocation$1["TOP_REVIEWS_SNIPPET"] = "top_reviews_snippet";
162
+ ChatElementDisplayLocation$1["BOTTOM_REVIEWS_SNIPPET"] = "bottom_reviews_snippet";
163
+ ChatElementDisplayLocation$1["BLOCK_BACK_BUTTON"] = "block_back_button";
164
+ ChatElementDisplayLocation$1["SWITCH_TO_AGENT"] = "switch_to_agent";
165
+ ChatElementDisplayLocation$1["CONVERSATIONAL_SEARCH"] = "conversational_search";
166
+ ChatElementDisplayLocation$1["GLOBAL_SEARCH_ENTRYPOINT"] = "global_search_entrypoint";
167
+ ChatElementDisplayLocation$1["SEARCH_NAV_ENTRYPOINT"] = "search_nav_entrypoint";
168
+ ChatElementDisplayLocation$1["SEARCH_PROMPT"] = "search_prompt";
169
+ ChatElementDisplayLocation$1["SEARCH_PROMPT_BUTTON"] = "search_prompt_button";
170
+ ChatElementDisplayLocation$1["PRODUCT_GRID"] = "product_grid";
171
+ ChatElementDisplayLocation$1["UNSPECIFIED"] = "unspecified";
172
+ ChatElementDisplayLocation$1["FILTER_MODAL"] = "filter_modal";
173
+ ChatElementDisplayLocation$1["PROMPT_CARD"] = "prompt_card";
174
+ ChatElementDisplayLocation$1["WINDOW_API_CALL"] = "window_api_call";
175
+ return ChatElementDisplayLocation$1;
176
+ }({});
177
+
178
+ //#endregion
179
+ //#region src/application/models/domMutationContinuation.ts
180
+ var DomMutationObserverContinuation = /* @__PURE__ */ function(DomMutationObserverContinuation$1) {
181
+ DomMutationObserverContinuation$1["CONTINUE"] = "CONTINUE";
182
+ DomMutationObserverContinuation$1["EXECUTING"] = "EXECUTING";
183
+ DomMutationObserverContinuation$1["STOP"] = "STOP";
184
+ return DomMutationObserverContinuation$1;
185
+ }(DomMutationObserverContinuation || {});
186
+
187
+ //#endregion
188
+ //#region src/application/models/domObservationStrategy.ts
189
+ var DomObservationStrategy = /* @__PURE__ */ function(DomObservationStrategy$1) {
190
+ DomObservationStrategy$1["MutationObserver"] = "MutationObserver";
191
+ DomObservationStrategy$1["Polling"] = "Polling";
192
+ DomObservationStrategy$1["None"] = "None";
193
+ return DomObservationStrategy$1;
194
+ }(DomObservationStrategy || {});
195
+
196
+ //#endregion
197
+ //#region src/application/models/events.ts
198
+ let SpiffyEventName = /* @__PURE__ */ function(SpiffyEventName$1) {
199
+ SpiffyEventName$1["WidgetOpen"] = "spiffy:widgetopen";
200
+ SpiffyEventName$1["WidgetClose"] = "spiffy:widgetclose";
201
+ return SpiffyEventName$1;
202
+ }({});
203
+
204
+ //#endregion
205
+ //#region src/application/models/googleAnalyticsEvents.ts
206
+ var GoogleAnalyticsEvents = /* @__PURE__ */ function(GoogleAnalyticsEvents$1) {
207
+ GoogleAnalyticsEvents$1["ADD_TO_CART_v1"] = "add_to_cart";
208
+ GoogleAnalyticsEvents$1["ADD_TO_CART_v2"] = "addToCart";
209
+ return GoogleAnalyticsEvents$1;
210
+ }(GoogleAnalyticsEvents || {});
211
+
212
+ //#endregion
213
+ //#region src/application/models/message.ts
214
+ let MessageRole = /* @__PURE__ */ function(MessageRole$1) {
215
+ MessageRole$1["User"] = "user";
216
+ MessageRole$1["Assistant"] = "assistant";
217
+ return MessageRole$1;
218
+ }({});
219
+ let MessageType = /* @__PURE__ */ function(MessageType$1) {
220
+ MessageType$1["Text"] = "text";
221
+ MessageType$1["SuggestionClicked"] = "suggestion_clicked";
222
+ MessageType$1["Product"] = "product";
223
+ MessageType$1["ProductSearch"] = "product_search";
224
+ MessageType$1["Review"] = "review";
225
+ MessageType$1["QueryTyped"] = "query_typed";
226
+ MessageType$1["Separator"] = "separator";
227
+ MessageType$1["Page"] = "page";
228
+ MessageType$1["Search"] = "search";
229
+ MessageType$1["Attachment"] = "attachment";
230
+ MessageType$1["CXAgentResponse"] = "cx_agent_response";
231
+ MessageType$1["Form"] = "form";
232
+ MessageType$1["Order"] = "order";
233
+ MessageType$1["ProductSearchFilter"] = "product_search_filter";
234
+ return MessageType$1;
235
+ }({});
236
+
237
+ //#endregion
238
+ //#region src/application/models/productExperiment.ts
239
+ let ProductExperiment = /* @__PURE__ */ function(ProductExperiment$1) {
240
+ ProductExperiment$1["Default"] = "default";
241
+ return ProductExperiment$1;
242
+ }({});
243
+
244
+ //#endregion
245
+ //#region src/application/models/spiffyWidgets.ts
246
+ /**
247
+ * Enum of all widget names. These are widgets that are rendered and integrated into
248
+ * a merchant's website.
249
+ */
250
+ let SpiffyWidgets = /* @__PURE__ */ function(SpiffyWidgets$1) {
251
+ SpiffyWidgets$1["ImageBanner"] = "image_banner";
252
+ SpiffyWidgets$1["ImagePromptCard"] = "image_prompt_card";
253
+ SpiffyWidgets$1["SingleImagePrompt"] = "single_image_prompt";
254
+ SpiffyWidgets$1["EmbeddedWidget"] = "embedded_widget";
255
+ SpiffyWidgets$1["FloatingButton"] = "floating_button";
256
+ SpiffyWidgets$1["SuggestionBar"] = "suggestion_bar";
257
+ SpiffyWidgets$1["SearchPrompt"] = "search_prompt";
258
+ SpiffyWidgets$1["GlobalSearch"] = "global_search";
259
+ SpiffyWidgets$1["SearchResults"] = "search_results";
260
+ SpiffyWidgets$1["GlobalSearchEntryPoint"] = "global_search_entry_point";
261
+ return SpiffyWidgets$1;
262
+ }({});
263
+
264
+ //#endregion
265
+ //#region src/application/models/graphql/queries/getMerchantOrgIdQuery.ts
266
+ const getMerchantOrgIdQuery = `
267
+ query {
268
+ me {
269
+ org {
270
+ id
271
+ }
272
+ }
273
+ }
274
+ `;
275
+
276
+ //#endregion
277
+ //#region src/application/models/guards/graphQL/isGraphQLColorsConfig.ts
278
+ const REQUIRED_COLOR_FIELDS = [
279
+ "accent_primary",
280
+ "accent_secondary",
281
+ "background_dark",
282
+ "background_light",
283
+ "background_primary",
284
+ "background_saturated",
285
+ "background_secondary",
286
+ "background_secondary_dark",
287
+ "background_tertiary",
288
+ "border_dark",
289
+ "border_light",
290
+ "border_medium",
291
+ "border_outline",
292
+ "text_accent",
293
+ "text_light",
294
+ "text_link",
295
+ "text_primary",
296
+ "text_secondary"
297
+ ];
298
+ const isGraphQLColorsConfig = (data) => {
299
+ if (typeof data !== "object" || data === null) {
300
+ logger_default.logError("Invalid graphql response for colors config", void 0, { data });
301
+ return false;
302
+ }
303
+ const missingFields = REQUIRED_COLOR_FIELDS.filter((field) => !(field in data) || typeof data[field] !== "string");
304
+ if (missingFields.length === REQUIRED_COLOR_FIELDS.length) {
305
+ logger_default.logError("All color fields are missing or null", void 0);
306
+ return false;
307
+ }
308
+ if (missingFields.length > 0) {
309
+ logger_default.logError("Missing or invalid color fields", void 0, {
310
+ data,
311
+ missingFields
312
+ });
313
+ return false;
314
+ }
315
+ return true;
316
+ };
317
+
318
+ //#endregion
319
+ //#region src/application/models/validators/validateGraphQLColorsConfig.ts
320
+ const validateGraphQLColorsConfig = (data) => {
321
+ if (!isGraphQLColorsConfig(data)) return;
322
+ return {
323
+ [ColorNames.TextPrimary]: data.text_primary,
324
+ [ColorNames.TextSecondary]: data.text_secondary,
325
+ [ColorNames.TextAccent]: data.text_accent,
326
+ [ColorNames.TextLink]: data.text_link,
327
+ [ColorNames.TextLight]: data.text_light,
328
+ [ColorNames.BackgroundPrimary]: data.background_primary,
329
+ [ColorNames.BackgroundSecondary]: data.background_secondary,
330
+ [ColorNames.BackgroundSecondaryDark]: data.background_secondary_dark,
331
+ [ColorNames.BackgroundTertiary]: data.background_tertiary,
332
+ [ColorNames.BackgroundDark]: data.background_dark,
333
+ [ColorNames.BorderLight]: data.border_light,
334
+ [ColorNames.BorderMedium]: data.border_medium,
335
+ [ColorNames.BorderDark]: data.border_dark,
336
+ [ColorNames.BorderOutline]: data.border_outline,
337
+ [ColorNames.AccentPrimary]: data.accent_primary,
338
+ [ColorNames.AccentSecondary]: data.accent_secondary,
339
+ [ColorNames.BackgroundLight]: data.background_light,
340
+ [ColorNames.BackgroundSaturated]: data.background_saturated
341
+ };
342
+ };
343
+
344
+ //#endregion
345
+ //#region src/application/models/utils/snakeToCamelTransformer.ts
346
+ /**
347
+ * Generic utility to transform snake_case object keys to camelCase at runtime.
348
+ * This is the runtime equivalent of the CamelCasedPropertiesDeep type utility.
349
+ */
350
+ const PRESERVED_ACRONYMS = [
351
+ "PLP",
352
+ "PDP",
353
+ "SVG"
354
+ ];
355
+ /**
356
+ * Converts a snake_case string to camelCase
357
+ * Handles specific acronyms like PLP and PDP correctly
358
+ */
359
+ const toCamelCase = (str) => {
360
+ let processedStr = str;
361
+ for (const acronym of PRESERVED_ACRONYMS) {
362
+ const regex = new RegExp(`_${acronym}_?`, "gi");
363
+ if (processedStr.match(regex)) processedStr = processedStr.replace(regex, (v) => v.endsWith("_") ? `${acronym}_` : `${acronym}`);
364
+ }
365
+ return processedStr.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
366
+ };
367
+ /**
368
+ * Converts a camelCase string to snake_case
369
+ * Handles consecutive capital letters correctly (e.g., "PDP" -> "pdp", not "p_d_p")
370
+ * Preserves specific acronyms like PLP and PDP as lowercase in snake_case
371
+ */
372
+ const toSnakeCase = (str) => str.replace(/([A-Z])(?=[a-z])/g, "_$1").replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().replace(/^_/, "");
373
+ /**
374
+ * Recursively transforms all object keys from snake_case to camelCase
375
+ */
376
+ const transformSnakeToCamel = (obj) => {
377
+ if (obj === null || obj === void 0) return obj;
378
+ if (Array.isArray(obj)) return obj.map((val) => transformSnakeToCamel(val));
379
+ if (typeof obj === "object") {
380
+ const result = {};
381
+ for (const [key, value] of Object.entries(obj)) {
382
+ const camelKey = toCamelCase(key);
383
+ result[camelKey] = transformSnakeToCamel(value);
384
+ }
385
+ return result;
386
+ }
387
+ return obj;
388
+ };
389
+ /**
390
+ * Recursively transforms all object keys from camelCase to snake_case
391
+ */
392
+ const transformCamelToSnake = (obj) => {
393
+ if (obj === null || obj === void 0) return obj;
394
+ if (Array.isArray(obj)) return obj.map(transformCamelToSnake);
395
+ if (typeof obj === "object") {
396
+ const result = {};
397
+ for (const [key, value] of Object.entries(obj)) {
398
+ const snakeKey = toSnakeCase(key);
399
+ result[snakeKey] = transformCamelToSnake(value);
400
+ }
401
+ return result;
402
+ }
403
+ return obj;
404
+ };
405
+
406
+ //#endregion
407
+ //#region src/application/service/domMutations/domInsertionService.ts
408
+ var DOMInsertionType = /* @__PURE__ */ function(DOMInsertionType$1) {
409
+ DOMInsertionType$1["AFTER"] = "after";
410
+ DOMInsertionType$1["BEFORE"] = "before";
411
+ DOMInsertionType$1["ADJACENT_AFTER_BEGIN"] = "adjacent-after-begin";
412
+ DOMInsertionType$1["ADJACENT_BEFORE_BEGIN"] = "adjacent-before-begin";
413
+ DOMInsertionType$1["ADJACENT_AFTER_END"] = "adjacent-after-end";
414
+ DOMInsertionType$1["ADJACENT_BEFORE_END"] = "adjacent-before-end";
415
+ DOMInsertionType$1["APPEND_CHILD"] = "append-child";
416
+ DOMInsertionType$1["NONE"] = "none";
417
+ return DOMInsertionType$1;
418
+ }(DOMInsertionType || {});
419
+ const DOMInsertionTypeToInsertPosition = (type) => {
420
+ switch (type) {
421
+ case DOMInsertionType.ADJACENT_AFTER_BEGIN: return "afterbegin";
422
+ case DOMInsertionType.BEFORE:
423
+ case DOMInsertionType.ADJACENT_BEFORE_BEGIN: return "beforebegin";
424
+ case DOMInsertionType.ADJACENT_BEFORE_END: return "beforeend";
425
+ case DOMInsertionType.AFTER:
426
+ case DOMInsertionType.ADJACENT_AFTER_END:
427
+ default: return "afterend";
428
+ }
429
+ };
430
+ var DOMInsertionService = class {
431
+ static insert(targetElement, nodeToInsert, insertionType) {
432
+ switch (insertionType) {
433
+ case DOMInsertionType.AFTER:
434
+ targetElement.after(nodeToInsert);
435
+ break;
436
+ case DOMInsertionType.BEFORE:
437
+ targetElement.before(nodeToInsert);
438
+ break;
439
+ case DOMInsertionType.ADJACENT_AFTER_BEGIN:
440
+ targetElement.insertAdjacentElement("afterbegin", nodeToInsert);
441
+ break;
442
+ case DOMInsertionType.ADJACENT_BEFORE_BEGIN:
443
+ targetElement.insertAdjacentElement("beforebegin", nodeToInsert);
444
+ break;
445
+ case DOMInsertionType.ADJACENT_AFTER_END:
446
+ targetElement.insertAdjacentElement("afterend", nodeToInsert);
447
+ break;
448
+ case DOMInsertionType.ADJACENT_BEFORE_END:
449
+ targetElement.insertAdjacentElement("beforeend", nodeToInsert);
450
+ break;
451
+ case DOMInsertionType.APPEND_CHILD:
452
+ targetElement.appendChild(nodeToInsert);
453
+ break;
454
+ case DOMInsertionType.NONE: break;
455
+ default: throw new Error(`Invalid insertion type: ${insertionType}`);
456
+ }
457
+ }
458
+ /**
459
+ * Get the insertion point for the widget.
460
+ * @param selector - The selector to find the insertion point.
461
+ * @param selectionIndex - For multiple matches, pick the nth element. Can be negative to insert from the end (-1 is the last element). (optional, default first)
462
+ * @returns The insertion point element or null if not found.
463
+ */
464
+ static getInsertionPoint(selector, selectionIndex) {
465
+ let elem = null;
466
+ if (selectionIndex === void 0 || selectionIndex === 0) {
467
+ elem = document.querySelector(selector);
468
+ if (elem?.parentElement) return elem;
469
+ } else {
470
+ const elems = document.querySelectorAll(selector);
471
+ const minLength = selectionIndex > 0 ? selectionIndex + 1 : -selectionIndex;
472
+ const index = selectionIndex > 0 ? selectionIndex : elems.length + selectionIndex;
473
+ if (elems.length >= minLength && elems[index].parentElement) return elems[index];
474
+ }
475
+ return null;
476
+ }
477
+ };
478
+
479
+ //#endregion
480
+ //#region src/application/service/domMutations/GridInsertionService.ts
481
+ var GridInsertionType = /* @__PURE__ */ function(GridInsertionType$1) {
482
+ GridInsertionType$1["FIXED_1"] = "fixed-1";
483
+ GridInsertionType$1["FIXED_2"] = "fixed-2";
484
+ GridInsertionType$1["FIXED_3"] = "fixed-3";
485
+ GridInsertionType$1["FIXED_4"] = "fixed-4";
486
+ GridInsertionType$1["FIXED_5"] = "fixed-5";
487
+ GridInsertionType$1["FIXED_6"] = "fixed-6";
488
+ GridInsertionType$1["FIXED_7"] = "fixed-7";
489
+ GridInsertionType$1["FIXED_8"] = "fixed-8";
490
+ GridInsertionType$1["FIXED_9"] = "fixed-9";
491
+ GridInsertionType$1["FIXED_12"] = "fixed-12";
492
+ GridInsertionType$1["FIXED_13"] = "fixed-13";
493
+ GridInsertionType$1["ROW_1"] = "row-1";
494
+ GridInsertionType$1["ROW_2"] = "row-2";
495
+ GridInsertionType$1["ROW_3"] = "row-3";
496
+ GridInsertionType$1["ROW_4"] = "row-4";
497
+ return GridInsertionType$1;
498
+ }(GridInsertionType || {});
499
+ var GridInsertionService = class GridInsertionService {
500
+ static insert(gridInsertionType, targetElement, nodeToInsert, insertionType) {
501
+ switch (gridInsertionType) {
502
+ case GridInsertionType.FIXED_1:
503
+ GridInsertionService.fixedInsert(targetElement, 1, nodeToInsert, insertionType);
504
+ break;
505
+ case GridInsertionType.FIXED_2:
506
+ GridInsertionService.fixedInsert(targetElement, 2, nodeToInsert, insertionType);
507
+ break;
508
+ case GridInsertionType.FIXED_3:
509
+ GridInsertionService.fixedInsert(targetElement, 3, nodeToInsert, insertionType);
510
+ break;
511
+ case GridInsertionType.FIXED_4:
512
+ GridInsertionService.fixedInsert(targetElement, 4, nodeToInsert, insertionType);
513
+ break;
514
+ case GridInsertionType.FIXED_5:
515
+ GridInsertionService.fixedInsert(targetElement, 5, nodeToInsert, insertionType);
516
+ break;
517
+ case GridInsertionType.FIXED_6:
518
+ GridInsertionService.fixedInsert(targetElement, 6, nodeToInsert, insertionType);
519
+ break;
520
+ case GridInsertionType.FIXED_7:
521
+ GridInsertionService.fixedInsert(targetElement, 7, nodeToInsert, insertionType);
522
+ break;
523
+ case GridInsertionType.FIXED_8:
524
+ GridInsertionService.fixedInsert(targetElement, 8, nodeToInsert, insertionType);
525
+ break;
526
+ case GridInsertionType.FIXED_9:
527
+ GridInsertionService.fixedInsert(targetElement, 9, nodeToInsert, insertionType);
528
+ break;
529
+ case GridInsertionType.FIXED_12:
530
+ GridInsertionService.fixedInsert(targetElement, 12, nodeToInsert, insertionType);
531
+ break;
532
+ case GridInsertionType.FIXED_13:
533
+ GridInsertionService.fixedInsert(targetElement, 13, nodeToInsert, insertionType);
534
+ break;
535
+ case GridInsertionType.ROW_1:
536
+ GridInsertionService.rowInsert(targetElement, nodeToInsert, 1);
537
+ break;
538
+ case GridInsertionType.ROW_2:
539
+ GridInsertionService.rowInsert(targetElement, nodeToInsert, 2);
540
+ break;
541
+ case GridInsertionType.ROW_3:
542
+ GridInsertionService.rowInsert(targetElement, nodeToInsert, 3);
543
+ break;
544
+ case GridInsertionType.ROW_4:
545
+ GridInsertionService.rowInsert(targetElement, nodeToInsert, 4);
546
+ break;
547
+ default: logger_default.logError(`Skipping grid insertion: invalid grid insertion type "${gridInsertionType}". \
548
+ Valid types are: ${Object.keys(GridInsertionType).join(", ")}`, void 0);
549
+ }
550
+ }
551
+ /**
552
+ * Inserts a node into a grid row at the specified index starting from index 1. If the index
553
+ * is higher than the total number of rows, the node will be inserted at the end of the grid.
554
+ * This function does not make any assumptions about the column span of the inserted node - that
555
+ * should be handled by the orgConfig instead.
556
+ *
557
+ * @param targetElement - The target element to insert the node into.
558
+ * @param nodeToInsert - The node to insert into the grid.
559
+ * @param rowIndex - The index of the row to insert the node into.
560
+ */
561
+ static rowInsert(targetElement, nodeToInsert, rowIndex) {
562
+ const node = nodeToInsert;
563
+ node.style.gridRow = rowIndex.toString();
564
+ node.style.gridColumn = "1/-1";
565
+ DOMInsertionService.insert(targetElement, node, DOMInsertionType.APPEND_CHILD);
566
+ }
567
+ static fixedInsert(targetElement, insertionGridIndex, nodeToInsert, insertionType) {
568
+ const childCount = targetElement.children.length;
569
+ const actualIndex = Math.min(insertionGridIndex - 1, childCount - 1);
570
+ const targetChild = targetElement.children[actualIndex];
571
+ if (!targetChild) {
572
+ logger_default.logWarn("Skipping grid insertion: grid has no elements", void 0);
573
+ return;
574
+ }
575
+ DOMInsertionService.insert(targetChild, nodeToInsert, insertionType);
576
+ }
577
+ };
578
+
579
+ //#endregion
580
+ //#region src/application/models/validators/validateGraphQLFrontendConfig.ts
581
+ const validateAndTransformPageVariants = (config) => {
582
+ const { variantChecks, widgetMounting,...rest } = transformSnakeToCamel(config);
583
+ const variantTests = Array.isArray(variantChecks) ? variantChecks.map(({ checkType,...restCheck }) => ({
584
+ ...restCheck,
585
+ testType: checkType
586
+ })) : [];
587
+ const normalizedWidgetMounting = Array.isArray(widgetMounting) ? widgetMounting.map(({ mountingPointWidgets,...restMounting }) => ({
588
+ ...restMounting,
589
+ ...Array.isArray(mountingPointWidgets) ? { mountingPointWidgets: mountingPointWidgets.map(({ checks,...restWidget }) => ({
590
+ ...restWidget,
591
+ tests: Array.isArray(checks) ? checks.map(({ checkType,...restCheck }) => ({
592
+ ...restCheck,
593
+ testType: checkType
594
+ })) : []
595
+ })) } : {}
596
+ })) : [];
597
+ const normalizedConfig = {
598
+ ...rest,
599
+ ...variantTests ? { variantTests } : {},
600
+ ...normalizedWidgetMounting ? { widgetMounting: normalizedWidgetMounting } : {}
601
+ };
602
+ const variantId = normalizedConfig.variantId;
603
+ const variantType = normalizedConfig.variantType;
604
+ if (typeof variantId !== "string" || !variantId) throw new Error(`Missing or invalid variantId for pageVariant`);
605
+ if (typeof variantType !== "string" || !variantType) throw new Error(`Missing or invalid variantType for pageVariant '${variantId}'`);
606
+ if (!Array.isArray(variantTests)) throw new Error(`Missing or invalid variantTests for pageVariant '${variantId}'. Must be an array`);
607
+ for (const test of variantTests) {
608
+ if (!test.testType || typeof test.testType !== "string") throw new Error(`Invalid variantTest.testType for pageVariant '${variantId}'`);
609
+ if (!Object.values(PageVariantTestType).includes(test.testType)) throw new Error(`Invalid testType '${test.testType}' for pageVariant '${variantId}'. Valid types: ${Object.values(PageVariantTestType).join(", ")}`);
610
+ }
611
+ if (!Array.isArray(normalizedWidgetMounting)) throw new Error(`Missing or invalid widgetMounting for pageVariant '${variantId}'. Must be an array`);
612
+ for (const mounting of normalizedWidgetMounting) {
613
+ if (typeof mounting.mountingConfigId !== "string" || !mounting.mountingConfigId) throw new Error(`Invalid mountingConfigId in widgetMounting for pageVariant '${variantId}'`);
614
+ if (mounting.widgetConfigId && typeof mounting.widgetConfigId !== "string") throw new Error(`Invalid widgetConfigId in widgetMounting for pageVariant '${variantId}'`);
615
+ if (mounting.mountingPointWidgets) for (const widget of mounting.mountingPointWidgets) {
616
+ if (typeof widget.widgetConfigId !== "string" || !widget.widgetConfigId) throw new Error(`Invalid widgetConfigId in mountingPointWidgets for pageVariant '${variantId}'`);
617
+ if (!Array.isArray(widget.tests)) throw new Error(`Invalid or missing tests in mountingPointWidgets for pageVariant '${variantId}'`);
618
+ }
619
+ }
620
+ if (variantType === "plp") {
621
+ if (typeof normalizedConfig.plpIdExtractor !== "string" || !normalizedConfig.plpIdExtractor) throw new Error(`Missing or invalid plpIdExtractor for PLP pageVariant '${variantId}'`);
622
+ }
623
+ if (variantType === "pdp") {
624
+ if (typeof normalizedConfig.productIdExtractor !== "string" || !normalizedConfig.productIdExtractor) throw new Error(`Missing or invalid productIdExtractor for PDP pageVariant '${variantId}'`);
625
+ if (normalizedConfig.parentProductIdExtractor && typeof normalizedConfig.parentProductIdExtractor !== "string") throw new Error(`Invalid parentProductIdExtractor for PDP pageVariant '${variantId}'. Must be string if provided`);
626
+ }
627
+ return normalizedConfig;
628
+ };
629
+ const validateAndTransformMountingConfig = (config, configKey) => {
630
+ const normalizedConfig = { ...config };
631
+ if (normalizedConfig.checkId && !normalizedConfig.testId) {
632
+ normalizedConfig.testId = normalizedConfig.checkId;
633
+ delete normalizedConfig.checkId;
634
+ }
635
+ if (typeof normalizedConfig.mountingConfigId !== "string" || !normalizedConfig.mountingConfigId) throw new Error(`Missing or invalid mountingConfigId for config '${configKey}'`);
636
+ if (typeof normalizedConfig.containerId !== "string" || !normalizedConfig.containerId) throw new Error(`Missing or invalid containerId for config '${configKey}'`);
637
+ if (typeof normalizedConfig.testId !== "string" || !normalizedConfig.testId) throw new Error(`Missing or invalid testId for config '${configKey}'`);
638
+ if (!normalizedConfig.insertionPoint || typeof normalizedConfig.insertionPoint !== "object" || Array.isArray(normalizedConfig.insertionPoint)) throw new Error(`Missing or invalid insertionPoint for config '${configKey}'`);
639
+ const insertionPoint = normalizedConfig.insertionPoint;
640
+ if (typeof insertionPoint.selector !== "string" || !insertionPoint.selector) throw new Error(`Missing or invalid insertionPoint.selector for config '${configKey}'`);
641
+ if (typeof insertionPoint.insertionType !== "string" || !insertionPoint.insertionType) throw new Error(`Missing or invalid insertionPoint.insertionType for config '${configKey}'`);
642
+ if (!Object.values(DOMInsertionType).includes(insertionPoint.insertionType)) throw new Error(`Invalid insertionPoint.insertionType '${insertionPoint.insertionType}' for config '${configKey}'. Valid types: ${Object.values(DOMInsertionType).join(", ")}`);
643
+ if (insertionPoint.selectionIndex != null && typeof insertionPoint.selectionIndex !== "number") throw new Error(`Invalid insertionPoint.selectionIndex for config '${configKey}'. Must be a number or null/undefined`);
644
+ let parentInsertionPoint;
645
+ if (normalizedConfig.parentInsertionPoint) {
646
+ if (typeof normalizedConfig.parentInsertionPoint !== "object" || Array.isArray(normalizedConfig.parentInsertionPoint)) throw new Error(`Invalid parentInsertionPoint for config '${configKey}'. Must be an object`);
647
+ const parentPoint = normalizedConfig.parentInsertionPoint;
648
+ if (typeof parentPoint.selector !== "string" || !parentPoint.selector) throw new Error(`Missing or invalid parentInsertionPoint.selector for config '${configKey}'`);
649
+ if (typeof parentPoint.insertionType !== "string" || !parentPoint.insertionType) throw new Error(`Missing or invalid parentInsertionPoint.insertionType for config '${configKey}'`);
650
+ if (!Object.values(DOMInsertionType).includes(parentPoint.insertionType)) throw new Error(`Invalid parentInsertionPoint.insertionType '${parentPoint.insertionType}' for config '${configKey}'. Valid types: ${Object.values(DOMInsertionType).join(", ")}`);
651
+ if (parentPoint.selectionIndex != null && typeof parentPoint.selectionIndex !== "number") throw new Error(`Invalid parentInsertionPoint.selectionIndex for config '${configKey}'. Must be a number or null/undefined`);
652
+ parentInsertionPoint = {
653
+ selector: parentPoint.selector,
654
+ insertionType: parentPoint.insertionType,
655
+ selectionIndex: parentPoint.selectionIndex
656
+ };
657
+ }
658
+ let wrappingElement;
659
+ if (normalizedConfig.wrappingElement) {
660
+ if (typeof normalizedConfig.wrappingElement !== "object" || Array.isArray(normalizedConfig.wrappingElement)) throw new Error(`Invalid wrappingElement for config '${configKey}'. Must be an object`);
661
+ const wrapping = normalizedConfig.wrappingElement;
662
+ if (typeof wrapping.className !== "string" || !wrapping.className) throw new Error(`Missing or invalid wrappingElement.className for config '${configKey}'`);
663
+ if (typeof wrapping.element !== "string" || !wrapping.element) throw new Error(`Missing or invalid wrappingElement.element for config '${configKey}'`);
664
+ if (typeof wrapping.insertionType !== "string" || !wrapping.insertionType) throw new Error(`Missing or invalid wrappingElement.insertionType for config '${configKey}'`);
665
+ if (!Object.values(DOMInsertionType).includes(wrapping.insertionType)) throw new Error(`Invalid wrappingElement.insertionType '${wrapping.insertionType}' for config '${configKey}'. Valid types: ${Object.values(DOMInsertionType).join(", ")}`);
666
+ wrappingElement = {
667
+ className: wrapping.className,
668
+ element: wrapping.element,
669
+ insertionType: wrapping.insertionType
670
+ };
671
+ }
672
+ if (normalizedConfig.divCheckSelector != null && typeof normalizedConfig.divCheckSelector !== "string") throw new Error(`Invalid divCheckSelector for config '${configKey}'. Must be a string or null/undefined`);
673
+ if (normalizedConfig.className != null && typeof normalizedConfig.className !== "string") throw new Error(`Invalid className for config '${configKey}'. Must be a string or null/undefined`);
674
+ if (normalizedConfig.suppressionSelector != null && typeof normalizedConfig.suppressionSelector !== "string") throw new Error(`Invalid suppressionSelector for config '${configKey}'. Must be a string or null/undefined`);
675
+ if (normalizedConfig.dataAttributes != null && (typeof normalizedConfig.dataAttributes !== "object" || Array.isArray(normalizedConfig.dataAttributes))) throw new Error(`Invalid dataAttributes for config '${configKey}'. Must be an object or null/undefined`);
676
+ if (normalizedConfig.style != null && (typeof normalizedConfig.style !== "object" || Array.isArray(normalizedConfig.style))) throw new Error(`Invalid style for config '${configKey}'. Must be an object or null/undefined`);
677
+ let gridInsertionType;
678
+ if (normalizedConfig.gridInsertionType) {
679
+ if (typeof normalizedConfig.gridInsertionType !== "string" || !normalizedConfig.gridInsertionType) throw new Error(`Invalid gridInsertionType for config '${configKey}'. Must be a string`);
680
+ if (!Object.values(GridInsertionType).includes(normalizedConfig.gridInsertionType)) throw new Error(`Invalid gridInsertionType '${normalizedConfig.gridInsertionType}' for config '${configKey}'. Valid types: ${Object.values(GridInsertionType).join(", ")}`);
681
+ gridInsertionType = normalizedConfig.gridInsertionType;
682
+ }
683
+ const result = {
684
+ mountingConfigId: normalizedConfig.mountingConfigId,
685
+ containerId: normalizedConfig.containerId,
686
+ testId: normalizedConfig.testId,
687
+ insertionPoint: {
688
+ selector: insertionPoint.selector,
689
+ insertionType: insertionPoint.insertionType,
690
+ ...insertionPoint.selectionIndex != null && { selectionIndex: insertionPoint.selectionIndex }
691
+ }
692
+ };
693
+ if (parentInsertionPoint) result.parentInsertionPoint = parentInsertionPoint;
694
+ if (gridInsertionType) result.gridInsertionType = gridInsertionType;
695
+ if (wrappingElement) result.wrappingElement = wrappingElement;
696
+ if (normalizedConfig.divCheckSelector) result.divCheckSelector = normalizedConfig.divCheckSelector;
697
+ if (normalizedConfig.className) result.className = normalizedConfig.className;
698
+ if (normalizedConfig.suppressionSelector) result.suppressionSelector = normalizedConfig.suppressionSelector;
699
+ if (normalizedConfig.dataAttributes) result.dataAttributes = normalizedConfig.dataAttributes;
700
+ if (normalizedConfig.style) result.style = normalizedConfig.style;
701
+ return result;
702
+ };
703
+ const validateAndTransformWidgetConfig = (config, configKey) => {
704
+ const normalizedConfig = transformSnakeToCamel(config);
705
+ if (typeof normalizedConfig.widgetConfigId !== "string" || !normalizedConfig.widgetConfigId) throw new Error(`Missing or invalid widgetConfigId for widget config '${configKey}'`);
706
+ if (typeof normalizedConfig.type !== "string" || !normalizedConfig.type) throw new Error(`Missing or invalid type for widget config '${configKey}'`);
707
+ if (normalizedConfig.contentId != null && typeof normalizedConfig.contentId !== "string") throw new Error(`Invalid contentId for widget config '${configKey}'. Must be a string or null/undefined`);
708
+ return normalizedConfig;
709
+ };
710
+ const validateGraphQLFrontendConfig = (data) => {
711
+ if (data === null || data === void 0) return;
712
+ if (typeof data !== "object" || Array.isArray(data)) {
713
+ logger_default.logWarn("Invalid GraphQL frontend config data: not an object", void 0, { data });
714
+ return;
715
+ }
716
+ const obj = data;
717
+ if ("merchant_override_css" in obj && typeof obj.merchant_override_css !== "string" && obj.merchant_override_css !== null) {
718
+ logger_default.logWarn("Invalid GraphQL frontend config data: merchant_override_css must be a string or null", void 0, { data });
719
+ return;
720
+ }
721
+ if ("page_variants" in obj) {
722
+ if (obj.page_variants !== void 0 && obj.page_variants !== null && !Array.isArray(obj.page_variants)) {
723
+ logger_default.logWarn("Invalid GraphQL frontend config data: page_variants must be an array or null/undefined", void 0, { data });
724
+ return;
725
+ }
726
+ }
727
+ if ("mounting_configs" in obj) {
728
+ if (obj.mounting_configs !== void 0 && obj.mounting_configs !== null && !Array.isArray(obj.mounting_configs)) {
729
+ logger_default.logWarn("Invalid GraphQL frontend config data: mounting_configs must be an array or null/undefined", void 0, { data });
730
+ return;
731
+ }
732
+ }
733
+ if ("widget_configs" in obj) {
734
+ if (obj.widget_configs !== void 0 && obj.widget_configs !== null && !Array.isArray(obj.widget_configs)) {
735
+ logger_default.logWarn("Invalid GraphQL frontend config data: widget_configs must be an array or null/undefined", void 0, { data });
736
+ return;
737
+ }
738
+ }
739
+ if ("ui_configs" in obj && typeof obj.ui_configs !== "object" && obj.ui_configs !== null) {
740
+ logger_default.logWarn("Invalid GraphQL frontend config data: ui_configs must be an object or null/undefined", void 0, { data });
741
+ return;
742
+ }
743
+ try {
744
+ const transformedData = transformSnakeToCamel(obj);
745
+ if (transformedData.pageVariants && Array.isArray(transformedData.pageVariants)) {
746
+ const pageVariantsArray = transformedData.pageVariants;
747
+ const validatedPageVariants = [];
748
+ for (const variant of pageVariantsArray) if (variant && typeof variant === "object" && typeof variant.variantId === "string") try {
749
+ const validatedVariant = validateAndTransformPageVariants(variant);
750
+ validatedPageVariants.push(validatedVariant);
751
+ } catch (error) {
752
+ logger_default.logWarn("Invalid page variant, skipping", error, {
753
+ variantId: variant.variantId,
754
+ variant
755
+ });
756
+ }
757
+ else logger_default.logWarn("Invalid page variant structure, skipping", void 0, { variant });
758
+ transformedData.pageVariants = validatedPageVariants;
759
+ }
760
+ if (transformedData.mountingConfigs && Array.isArray(transformedData.mountingConfigs)) {
761
+ const mountingConfigsArray = transformedData.mountingConfigs;
762
+ const mountingConfigsRecord = {};
763
+ for (const item of mountingConfigsArray) if (item && typeof item.key === "string" && item.config && typeof item.config === "object") try {
764
+ const config = item.config;
765
+ const validatedConfig = validateAndTransformMountingConfig(config, item.key);
766
+ mountingConfigsRecord[item.key] = validatedConfig;
767
+ } catch (error) {
768
+ logger_default.logWarn("Invalid mounting config, skipping", error, {
769
+ configKey: item.key,
770
+ config: item.config
771
+ });
772
+ }
773
+ else logger_default.logWarn("Invalid mounting config item structure, skipping", void 0, { item });
774
+ transformedData.mountingConfigs = mountingConfigsRecord;
775
+ }
776
+ if (transformedData.widgetConfigs && Array.isArray(transformedData.widgetConfigs)) {
777
+ const widgetConfigsArray = transformedData.widgetConfigs;
778
+ const widgetConfigsRecord = {};
779
+ for (const item of widgetConfigsArray) if (item && typeof item.key === "string" && item.config && typeof item.config === "object") try {
780
+ const config = item.config;
781
+ const validatedConfig = validateAndTransformWidgetConfig(config, item.key);
782
+ widgetConfigsRecord[item.key] = validatedConfig;
783
+ } catch (error) {
784
+ logger_default.logWarn("Invalid widget config, skipping", error, {
785
+ configKey: item.key,
786
+ config: item.config
787
+ });
788
+ }
789
+ else logger_default.logWarn("Invalid widget config item structure, skipping", void 0, { item });
790
+ transformedData.widgetConfigs = widgetConfigsRecord;
791
+ }
792
+ return transformedData;
793
+ } catch (error) {
794
+ logger_default.logWarn("Failed to validate and transform GraphQL frontend config data", error, { data });
795
+ return;
796
+ }
797
+ };
798
+
799
+ //#endregion
800
+ //#region src/application/models/validators/validateGraphQLOrgId.ts
801
+ const validateGraphQLOrgId = (data) => {
802
+ if (typeof data !== "string" || data === "") return;
803
+ return data;
804
+ };
805
+
806
+ //#endregion
807
+ //#region src/application/service/localStorageService.ts
808
+ let LocalStorageKeys = /* @__PURE__ */ function(LocalStorageKeys$1) {
809
+ LocalStorageKeys$1["ChatId"] = "v1-spiffy-chat-session-id";
810
+ LocalStorageKeys$1["SpiffyOnOverride"] = "spiffy_on";
811
+ LocalStorageKeys$1["EnviveOnOverride"] = "envive_on";
812
+ return LocalStorageKeys$1;
813
+ }({});
814
+ var LocalStorageService = class {
815
+ static setItem(key, value) {
816
+ localStorage.setItem(key, value);
817
+ window.dispatchEvent(new StorageEvent("storage", {
818
+ key,
819
+ newValue: value
820
+ }));
821
+ }
822
+ static getItem(key) {
823
+ return localStorage.getItem(key);
824
+ }
825
+ static setSpiffyOnFeatureFlag(value) {
826
+ if (value === true) localStorage.setItem(LocalStorageKeys.SpiffyOnOverride, "true");
827
+ else if (value === false) localStorage.setItem(LocalStorageKeys.SpiffyOnOverride, "false");
828
+ }
829
+ static getSpiffyOnFeatureFlag() {
830
+ return localStorage.getItem(LocalStorageKeys.SpiffyOnOverride);
831
+ }
832
+ static getLocalStorage() {
833
+ const ls = window?.localStorage;
834
+ if (!ls) logger_default.logError("localStorage is not available", void 0);
835
+ return ls;
836
+ }
837
+ static {
838
+ this.listenersCache = {};
839
+ }
840
+ static listenerForKey(listener) {
841
+ if (!this.listenersCache[listener.storageKey]) this.listenersCache[listener.storageKey] = (event) => {
842
+ if (event.key !== listener.storageKey) return;
843
+ logger_default.logDebug(`[spiffy-ai] Storage event key=${event.key}, value=`, event.newValue);
844
+ listener.listener(event);
845
+ };
846
+ return this.listenersCache[listener.storageKey];
847
+ }
848
+ /**
849
+ * Attach a listener to the window's storage event. Safe to call multiple times.
850
+ * @param listener
851
+ */
852
+ static attachListener(listener) {
853
+ window.addEventListener("storage", this.listenerForKey(listener));
854
+ }
855
+ static detachListener(listener) {
856
+ window.removeEventListener("storage", this.listenerForKey(listener));
857
+ }
858
+ };
859
+
860
+ //#endregion
861
+ //#region src/application/service/environmentService.ts
862
+ var EnvironmentService = class {
863
+ static getApiEndpoint() {
864
+ const { baseUrl } = useEnviveConfig();
865
+ return baseUrl || "https://commerce-api.dev.spiffy.ai";
866
+ }
867
+ static getContextSource() {
868
+ if (window.IS_STORYBOOK) return ContextSourceEnum.Test;
869
+ const { contextSource } = useEnviveConfig();
870
+ if (contextSource) return contextSource;
871
+ if (LocalStorageService.getSpiffyOnFeatureFlag() === "true") return ContextSourceEnum.Playground;
872
+ return ContextSourceEnum.App;
873
+ }
874
+ static getIdentifyingPrefix() {
875
+ return "spiffy";
876
+ }
877
+ static {
878
+ this.getEnvironment = () => {
879
+ const { env } = useEnviveConfig();
880
+ if (!env) return "dev";
881
+ switch (env.toLowerCase()) {
882
+ case "production":
883
+ case "prod": return "prod";
884
+ default: return "dev";
885
+ }
886
+ };
887
+ }
888
+ };
889
+
890
+ //#endregion
891
+ //#region src/application/utils/urlsParser.ts
892
+ const parseHref = (href) => {
893
+ try {
894
+ const url = new URL(href);
895
+ const urlSearchParams = new URLSearchParams(url.search);
896
+ return {
897
+ url,
898
+ urlSearchParams
899
+ };
900
+ } catch (e) {
901
+ return {
902
+ url: void 0,
903
+ urlSearchParams: void 0
904
+ };
905
+ }
906
+ };
907
+ const createUrlWithQueryParams = (url, queryParams) => {
908
+ const urlObj = new URL(url, window.location.href);
909
+ Object.entries(queryParams).forEach(([value, key]) => urlObj.searchParams.append(value, key));
910
+ return urlObj.href;
911
+ };
912
+ const getQueryParam = (key) => {
913
+ return new URL(window.location.href).searchParams.get(key);
914
+ };
915
+ const buildSearchHash = (message) => `#evs=true&s=${message.id}&q=${message.metadata.generatedQuery}`;
916
+ const buildSearchStartHash = (query) => `#evs=true&q=${query}`;
917
+ const parseSearchHash = (hash) => {
918
+ if (!hash.startsWith("#evs=true")) return {
919
+ id: null,
920
+ query: null
921
+ };
922
+ const params = Object.fromEntries(hash.split("&").map((param) => param.split("=")));
923
+ return {
924
+ id: params.s ? decodeURIComponent(params.s) : null,
925
+ query: params.q ? decodeURIComponent(params.q) : null
926
+ };
927
+ };
928
+ window.history.pushState(null, "");
929
+
930
+ //#endregion
931
+ //#region src/application/service/sessionStorageService.ts
932
+ var SessionStorageService = class {
933
+ static setItem(key, value) {
934
+ sessionStorage.setItem(key, value);
935
+ window.dispatchEvent(new StorageEvent("storage", {
936
+ key,
937
+ newValue: value
938
+ }));
939
+ }
940
+ static getItem(key) {
941
+ return sessionStorage.getItem(key);
942
+ }
943
+ static getSessionStorage() {
944
+ const ls = window?.sessionStorage;
945
+ if (!ls) logger_default.logError("sessionStorage is not available", void 0);
946
+ return ls;
947
+ }
948
+ };
949
+
950
+ //#endregion
951
+ //#region src/application/service/featureFlagService.ts
952
+ const FEATURE_FLAGS_STORAGE_KEY = "spiffy-feature-flags";
953
+ var FeatureFlagService = class {
954
+ constructor(featureGates) {
955
+ this.featureGates = featureGates;
956
+ this.getQueryParamFeatureGateOverrides = (featureGate) => {
957
+ const urlObj = new URL(window.location.href);
958
+ const params = new URLSearchParams(urlObj.search);
959
+ const value = Object.fromEntries(params.entries())[featureGate];
960
+ if (value != null) return value === "true";
961
+ };
962
+ this.getWindowFeatureGateOverrides = (featureGate) => {
963
+ const value = window._spiffy?.featureOverrides?.[String(featureGate)];
964
+ if (value != null) return value;
965
+ };
966
+ this.getStoredFeatureGateOverrides = (featureGate) => {
967
+ const featureFlags = SessionStorageService.getItem(FEATURE_FLAGS_STORAGE_KEY);
968
+ if (featureFlags) try {
969
+ return JSON.parse(featureFlags)[featureGate];
970
+ } catch (err) {
971
+ logger_default.logError("[spiffy-ai] getStoredFeatureGateOverrides: error parsing feature flags", err);
972
+ }
973
+ };
974
+ }
975
+ persistFeatureGateOverrides() {
976
+ const featureFlags = Object.values(FeatureGates).map((featureGate) => ({ [featureGate]: this.getFeatureFlagOverride(featureGate) })).filter((_, val) => val !== void 0).reduce((acc, curr) => ({
977
+ ...acc,
978
+ ...curr
979
+ }), {});
980
+ SessionStorageService.setItem(FEATURE_FLAGS_STORAGE_KEY, JSON.stringify(featureFlags));
981
+ }
982
+ getFeatureFlagOverride(featureGate) {
983
+ const queryOverride = this.getQueryParamFeatureGateOverrides(featureGate);
984
+ if (queryOverride != null) {
985
+ logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by URL param. New value: ${queryOverride}`);
986
+ return queryOverride;
987
+ }
988
+ const windowOverride = this.getWindowFeatureGateOverrides(featureGate);
989
+ if (windowOverride != null) {
990
+ logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by window param. New value: ${windowOverride}`);
991
+ return windowOverride;
992
+ }
993
+ const storedOverride = this.getStoredFeatureGateOverrides(featureGate);
994
+ if (storedOverride != null) {
995
+ logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by stored value. New value: ${storedOverride}`);
996
+ return storedOverride;
997
+ }
998
+ }
999
+ isFeatureGateEnabled(featureGate) {
1000
+ const gateValue = this.featureGates.find((gate) => gate.name === featureGate);
1001
+ const featureFlagOverride = this.getFeatureFlagOverride(featureGate);
1002
+ if (featureFlagOverride !== void 0) return featureFlagOverride;
1003
+ if (gateValue == null || gateValue.value == null) {
1004
+ logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} value is undefined - returning false`);
1005
+ return false;
1006
+ }
1007
+ return gateValue.value;
1008
+ }
1009
+ isClientSessionEnabled() {
1010
+ const gates = this.featureGates;
1011
+ return gates == null || gates?.filter((gate) => gate.name === FeatureGates.IsClientSessionEnabled && gate.value === true).length > 0;
1012
+ }
1013
+ getFeatureFlags() {
1014
+ return Object.fromEntries(Object.values(FeatureGates).map((featureGate) => [featureGate, this.isFeatureGateEnabled(featureGate)]));
1015
+ }
1016
+ };
1017
+
1018
+ //#endregion
1019
+ //#region src/application/service/windowDataLayerService.ts
1020
+ var WindowDataLayerService = class WindowDataLayerService {
1021
+ constructor(gaConfig) {
1022
+ this.gaConfig = gaConfig;
1023
+ this.dataLayer = window.dataLayer;
1024
+ this.originalDataLayerPush = this.dataLayer?.push;
1025
+ this.merchantGoogleMeasurementId = this.gaConfig.measurementId || "default";
1026
+ }
1027
+ /**
1028
+ * Pushes data to the dataLayer
1029
+ * @param data
1030
+ * data has the shape: { event: 'event_name', ... }
1031
+ * Example:
1032
+ * {
1033
+ * "event": "add_to_cart",
1034
+ * "currency": "USD",
1035
+ * "value": 30.03,
1036
+ * "items": [
1037
+ * {
1038
+ * "item_id": "SKU_12345",
1039
+ * "item_name": "Stan and Friends Tee",
1040
+ * "affiliation": "Google Merchandise Store",
1041
+ * "coupon": "SUMMER_FUN",
1042
+ * "discount": 2.22,
1043
+ * "index": 0,
1044
+ * "item_brand": "Google",
1045
+ * "item_category": "Apparel",
1046
+ * "item_category2": "Adult",
1047
+ * "item_category3": "Shirts",
1048
+ * "item_category4": "Crew",
1049
+ * "item_category5": "Short sleeve",
1050
+ * "item_list_id": "related_products",
1051
+ * "item_list_name": "Related Products",
1052
+ * "item_variant": "green",
1053
+ * "location_id": "ChIJIQBpAG2ahYAR_6128GcTUEo",
1054
+ * "price": 10.01,
1055
+ * "quantity": 3
1056
+ * }
1057
+ * ]
1058
+ * }
1059
+ */
1060
+ push(data) {
1061
+ this.dataLayer?.push(data);
1062
+ }
1063
+ static isDataLayerAvailable() {
1064
+ const windowDataLayer = window.dataLayer;
1065
+ if (windowDataLayer && windowDataLayer.push) return true;
1066
+ logger_default.logDebug("[spiffy-ai] DataLayerEventsListener dataLayer not available");
1067
+ return false;
1068
+ }
1069
+ static tryFlattenArguments(args) {
1070
+ function isArguments(obj) {
1071
+ return obj !== void 0 && Object.prototype.toString.call(obj) === "[object Arguments]";
1072
+ }
1073
+ try {
1074
+ const all_arguments = [];
1075
+ if (args.length > 0) for (let i = 0; i < args.length; i++) {
1076
+ const arg = args[i];
1077
+ if (isArguments(arg)) {
1078
+ const flattened = WindowDataLayerService.tryFlattenArguments(arg);
1079
+ all_arguments.push(...flattened);
1080
+ } else all_arguments.push(arguments[i]);
1081
+ }
1082
+ return all_arguments;
1083
+ } catch {
1084
+ return args;
1085
+ }
1086
+ }
1087
+ wrapWithProxyMethod(methodName, callback) {
1088
+ if (!this.dataLayer) {
1089
+ logger_default.logWarn("DataLayerEventsListener dataLayer not available", void 0);
1090
+ return;
1091
+ }
1092
+ const originalMethod = this.dataLayer[methodName];
1093
+ this.dataLayer[methodName] = function() {
1094
+ try {
1095
+ callback.apply(this, arguments);
1096
+ } catch (e) {
1097
+ logger_default.logError(`Error in dataLayer.${methodName}: `, e);
1098
+ } finally {
1099
+ originalMethod.apply(this, arguments);
1100
+ }
1101
+ };
1102
+ }
1103
+ static getSingletonInstanceOf(gaConfig) {
1104
+ if (!WindowDataLayerService.instance) WindowDataLayerService.instance = new WindowDataLayerService(gaConfig);
1105
+ return WindowDataLayerService.instance;
1106
+ }
1107
+ sendToGoogleAnalyticsCircularEventsSafe(eventName, eventProps) {
1108
+ const This = this;
1109
+ function doesEventExistInDataLayer(eventName$1) {
1110
+ return This.dataLayer?.find((event) => event.event === eventName$1);
1111
+ }
1112
+ if (doesEventExistInDataLayer(eventName)) {
1113
+ logger_default.logDebug(`[spiffy-ai] Event ${eventName} already exists in dataLayer. Skipping Google Analytics event.`);
1114
+ return;
1115
+ }
1116
+ function gtag() {
1117
+ if (This.originalDataLayerPush) This.originalDataLayerPush(arguments);
1118
+ else logger_default.logDebug("No originalDataLayerPush found - no metrics being logged");
1119
+ }
1120
+ gtag("event", eventName, {
1121
+ event: eventName,
1122
+ send_to: this.merchantGoogleMeasurementId,
1123
+ ...eventProps
1124
+ });
1125
+ }
1126
+ static {
1127
+ this.getGoogleAnalyticsClientId = () => {
1128
+ try {
1129
+ const gaCookie = document.cookie.split(";").find((c) => c.trim().startsWith("_ga="));
1130
+ if (!gaCookie) {
1131
+ logger_default.logWarn("[spiffy-ai] No GA cookie found", void 0);
1132
+ return;
1133
+ }
1134
+ return gaCookie.split(".").slice(2).join(".");
1135
+ } catch (error) {
1136
+ logger_default.logError("Error getting GA client ID:", error);
1137
+ return;
1138
+ }
1139
+ };
1140
+ }
1141
+ };
1142
+
1143
+ //#endregion
1144
+ //#region src/application/service/userIdentityService.ts
1145
+ const getUserAgentDetails = () => {
1146
+ const result = new UAParser().getResult();
1147
+ return {
1148
+ os: result?.os?.name,
1149
+ osVersion: result?.os?.version,
1150
+ deviceBrand: result?.device?.vendor,
1151
+ deviceManufacturer: result?.device?.vendor,
1152
+ deviceModel: result?.device?.model,
1153
+ browser: result?.browser?.name,
1154
+ browserVersion: result?.browser?.version,
1155
+ userAgent: result?.ua
1156
+ };
1157
+ };
1158
+ var UserIdentityService = class UserIdentityService {
1159
+ static {
1160
+ this.USER_ID_OVERRIDE_KEY = "v1-spiffy-user-id-override";
1161
+ }
1162
+ static {
1163
+ this.USER_ID_DEFAULT_KEY = "v1-spiffy-user-id-default";
1164
+ }
1165
+ static async identifyUser() {
1166
+ try {
1167
+ const cdpUserId = WindowDataLayerService.getGoogleAnalyticsClientId();
1168
+ const userId = UserIdentityService.getUserIdOrDefault();
1169
+ const userAgentDetails = getUserAgentDetails();
1170
+ if (!cdpUserId) {
1171
+ logger_default.logWarn("[spiffy-ai] No GA Client ID found, skipping identifyUser", void 0);
1172
+ return;
1173
+ }
1174
+ await api_default.identifyUser(userId, cdpUserId, userAgentDetails);
1175
+ } catch (error) {
1176
+ logger_default.logError("[spiffy-ai] Error identifying user", error);
1177
+ }
1178
+ }
1179
+ static getUserIdOrDefault() {
1180
+ const userIdOverride = UserIdentityService.getUserIdOverrideFromLocalStorage();
1181
+ if (userIdOverride) return userIdOverride;
1182
+ const defaultUserId = UserIdentityService.getUserIdDefaultFromLocalStorage();
1183
+ if (defaultUserId) return defaultUserId;
1184
+ return this.setUserIdDefaultInLocalStorage(`spiffy-user-id-${v4()}`);
1185
+ }
1186
+ static getUserIdOverrideFromLocalStorage() {
1187
+ return LocalStorageService.getLocalStorage()?.getItem(UserIdentityService.USER_ID_OVERRIDE_KEY) ?? void 0;
1188
+ }
1189
+ static getUserIdDefaultFromLocalStorage() {
1190
+ return LocalStorageService.getLocalStorage()?.getItem(UserIdentityService.USER_ID_DEFAULT_KEY) ?? void 0;
1191
+ }
1192
+ static setUserIdDefaultInLocalStorage(userId) {
1193
+ logger_default.logInfo(`setUserIdDefaultInLocalStorage - Setting user_id=${userId}`);
1194
+ LocalStorageService.getLocalStorage()?.setItem(UserIdentityService.USER_ID_DEFAULT_KEY, userId);
1195
+ window.dispatchEvent(new StorageEvent("storage", {
1196
+ key: UserIdentityService.USER_ID_DEFAULT_KEY,
1197
+ newValue: userId
1198
+ }));
1199
+ return userId;
1200
+ }
1201
+ static setUserIdOverrideInLocalStorage(userId) {
1202
+ logger_default.logInfo(`setUserIdOverrideInLocalStorage - Setting user_id=${userId}`);
1203
+ LocalStorageService.getLocalStorage()?.setItem(UserIdentityService.USER_ID_OVERRIDE_KEY, userId);
1204
+ window.dispatchEvent(new StorageEvent("storage", {
1205
+ key: UserIdentityService.USER_ID_OVERRIDE_KEY,
1206
+ newValue: userId
1207
+ }));
1208
+ return userId;
1209
+ }
1210
+ static clearUserIdOverrideInLocalStorage() {
1211
+ logger_default.logInfo(`clearUserIdOverrideInLocalStorage - Clearing user_id`);
1212
+ LocalStorageService.getLocalStorage()?.removeItem(UserIdentityService.USER_ID_OVERRIDE_KEY);
1213
+ window.dispatchEvent(new StorageEvent("storage", {
1214
+ key: UserIdentityService.USER_ID_OVERRIDE_KEY,
1215
+ newValue: void 0
1216
+ }));
1217
+ }
1218
+ };
1219
+
1220
+ //#endregion
1221
+ //#region src/atoms/chat/chatState.ts
1222
+ const userHasRepliedAtom = atom(false);
1223
+ const replyEventCategoryAtom = atom(UserEventCategory$1.AppLoaded);
1224
+ const userQueryAtom = atom();
1225
+ const suggestionAtom = atom(void 0);
1226
+ const askQuestionBtnClickedAtom = atom(false);
1227
+ const messagesAtom = atom([]);
1228
+ const userEventsAtom = atom([]);
1229
+ const suggestionsAtom = atom([]);
1230
+ const suggestionsLoadingAtom = atom(false);
1231
+ const responseStreamingAtom = atom(false);
1232
+ const chatIsOpenAtom = atom(false);
1233
+ const requestFailureAtom = atom(false);
1234
+ const formSubmitAtom = atom();
1235
+ const chatOnToggleAtom = atom(null, (get, set, triggerLocation) => {
1236
+ const isOpen = get(chatIsOpenAtom);
1237
+ set(chatIsOpenAtom, !isOpen);
1238
+ if (!isOpen) {
1239
+ window.dispatchEvent(new CustomEvent(SpiffyEventName.WidgetOpen));
1240
+ AmplitudeAdapter.trackEvent({
1241
+ eventName: SpiffyMetricsEventName.ChatComponentExpanded,
1242
+ eventProps: { message_metadata: { trigger_location: triggerLocation } }
1243
+ });
1244
+ } else {
1245
+ window.dispatchEvent(new CustomEvent(SpiffyEventName.WidgetClose));
1246
+ AmplitudeAdapter.trackEvent({ eventName: SpiffyMetricsEventName.ChatComponentCollapsed });
1247
+ }
1248
+ });
1249
+
1250
+ //#endregion
1251
+ //#region src/atoms/app/variant.ts
1252
+ const internalStorageUrlResolverAtom = atomWithStorage("spiffy-url-resolver", void 0, sessionStorageUtil, { getOnInit: true });
1253
+ const urlResolverAtom = atom((get) => {
1254
+ const maybeUrlResolver = get(internalStorageUrlResolverAtom);
1255
+ if (maybeUrlResolver == null) return {};
1256
+ return JSON.parse(maybeUrlResolver);
1257
+ }, (get, set, value) => {
1258
+ const newCache = {
1259
+ ...get(urlResolverAtom),
1260
+ [value.url]: value.response
1261
+ };
1262
+ set(internalStorageUrlResolverAtom, JSON.stringify(newCache));
1263
+ });
1264
+ const internalStorageSupportedEventAtom = atomWithStorage("spiffy-supported-event", void 0, sessionStorageUtil, { getOnInit: true });
1265
+ const internalSupportedEventAtom = atom(void 0);
1266
+ const supportedEventAtom = atom((get) => {
1267
+ const maybeSupportedEvent = get(internalStorageSupportedEventAtom);
1268
+ if (maybeSupportedEvent == null) return;
1269
+ return JSON.parse(maybeSupportedEvent);
1270
+ }, (get, set, value) => {
1271
+ if (value == null) {
1272
+ set(internalStorageSupportedEventAtom, void 0);
1273
+ set(internalSupportedEventAtom, void 0);
1274
+ return;
1275
+ }
1276
+ const featureFlagService = get(featureFlagServiceAtom);
1277
+ const variantCategory = get(internalSupportedEventAtom)?.category;
1278
+ const shortName = get(orgShortNameAtom);
1279
+ if (!featureFlagService.isFeatureGateEnabled(FeatureGates.IsNonShapewearEnabled) && variantCategory && variantCategory !== SupportedEventProductCategory.Shapewear && (shortName === OrgShortName.Spanx || shortName === OrgShortName.SpanxStaging)) {
1280
+ const modifiedSupportedEvent = {
1281
+ supported: false,
1282
+ ready: value.ready,
1283
+ category: value.category,
1284
+ numberOfReviews: value.numberOfReviews,
1285
+ collections: value.collections,
1286
+ top_category: value.top_category,
1287
+ merchant_tags: value.merchant_tags
1288
+ };
1289
+ set(internalSupportedEventAtom, modifiedSupportedEvent);
1290
+ set(internalStorageSupportedEventAtom, JSON.stringify(modifiedSupportedEvent));
1291
+ return;
1292
+ }
1293
+ set(internalSupportedEventAtom, value);
1294
+ set(internalStorageSupportedEventAtom, JSON.stringify(value));
1295
+ });
1296
+ const internalVariantIdAtom = atom();
1297
+ const internalProductIdAtom = atom();
1298
+ const internalParentProductIdAtom = atom();
1299
+ const internalProductUrlAtom = atom();
1300
+ const internalPlpIdAtom = atom();
1301
+ const internalUrlAtom = atom();
1302
+ const internalPageVisitCategoryAtom = atom();
1303
+ const internalVariantAtom = atom("pdp");
1304
+ const variantIdAtom = atom((get) => get(internalVariantIdAtom));
1305
+ const productIdAtom = atom((get) => get(internalProductIdAtom));
1306
+ const parentProductIdAtom = atom((get) => get(internalParentProductIdAtom));
1307
+ const productUrlAtom = atom((get) => get(internalProductUrlAtom));
1308
+ const plpIdAtom = atom((get) => get(internalPlpIdAtom));
1309
+ const urlAtom = atom((get) => get(internalUrlAtom));
1310
+ const pageVisitCategoryAtom = atom((get) => get(internalPageVisitCategoryAtom));
1311
+ const variantAtom = atom((get) => get(internalVariantAtom));
1312
+ const hasParsedVariantInfoAtom = atom(false);
1313
+ const variantInfoAtom = atom((get) => {
1314
+ const variant = get(variantAtom);
1315
+ if (variant === "pdp") return {
1316
+ variantId: get(variantIdAtom),
1317
+ variant,
1318
+ productId: get(productIdAtom),
1319
+ parentProductId: get(parentProductIdAtom),
1320
+ url: get(urlAtom)
1321
+ };
1322
+ if (variant === "plp") return {
1323
+ variantId: get(variantIdAtom),
1324
+ variant,
1325
+ plpId: get(plpIdAtom),
1326
+ url: get(urlAtom)
1327
+ };
1328
+ if (variant === "page_visit") return {
1329
+ variantId: get(variantIdAtom),
1330
+ variant,
1331
+ url: get(urlAtom),
1332
+ pageVisitCategory: get(pageVisitCategoryAtom)
1333
+ };
1334
+ throw new Error("Invalid variantInfo details");
1335
+ }, (_, set, newVariant) => {
1336
+ set(internalVariantAtom, newVariant.variant);
1337
+ set(internalVariantIdAtom, newVariant.variantId);
1338
+ if (newVariant.variant === "pdp") {
1339
+ set(internalProductIdAtom, newVariant.productId);
1340
+ set(internalParentProductIdAtom, newVariant.parentProductId);
1341
+ set(internalUrlAtom, newVariant.url);
1342
+ }
1343
+ if (newVariant.variant === "plp") {
1344
+ set(internalPlpIdAtom, newVariant.plpId);
1345
+ set(internalUrlAtom, newVariant.url);
1346
+ }
1347
+ if (newVariant.variant === "page_visit") {
1348
+ set(internalUrlAtom, newVariant.url);
1349
+ set(internalPageVisitCategoryAtom, newVariant.pageVisitCategory);
1350
+ }
1351
+ });
1352
+
1353
+ //#endregion
1354
+ //#region src/atoms/app/index.ts
1355
+ const internalUserIdAtom = atom(void 0);
1356
+ const userIdAtom = atom((get) => {
1357
+ const maybeUserId = get(internalUserIdAtom);
1358
+ if (maybeUserId) return maybeUserId;
1359
+ return UserIdentityService.getUserIdOrDefault();
1360
+ }, (_, set, value) => {
1361
+ set(internalUserIdAtom, value);
1362
+ });
1363
+ const appSourceAtom = atom((get) => get(sourceAtom) ?? ContextSourceEnum.App);
1364
+ const envAtom = atom(ContextEnvEnum.Dev);
1365
+ const chatIdAtom = atomWithStorage("v1-spiffy-chat-session-id", v4(), void 0, { getOnInit: true });
1366
+ const appDetailsAtom = atom((get) => ({
1367
+ orgId: get(orgIdAtom),
1368
+ orgShortName: get(orgShortNameAtom) ?? "spiffy-ai",
1369
+ chatId: get(chatIdAtom),
1370
+ userId: get(userIdAtom),
1371
+ source: get(appSourceAtom),
1372
+ env: get(envAtom),
1373
+ variantInfo: get(variantInfoAtom)
1374
+ }));
1375
+
1376
+ //#endregion
1377
+ //#region src/atoms/chat/messageQueue.ts
1378
+ const internalUserEventQueueAtom = atom([]);
1379
+ const userEventQueueAtom = atom((get) => {
1380
+ const queue = get(internalUserEventQueueAtom);
1381
+ return queue === void 0 ? [] : queue.filter((v) => v !== void 0);
1382
+ });
1383
+ /**
1384
+ * This atom is used to queue a new message for processing on `next_responses`
1385
+ * It receives a single `userEvent` that is added to the processing queue.
1386
+ * If the event has the same eventId as an existing message in the queue the NEW
1387
+ * event is ignored
1388
+ */
1389
+ const queueUserEventAtom = atom(null, (get, set, userEvent) => {
1390
+ if (userEvent === void 0) return;
1391
+ set(internalUserEventQueueAtom, [...get(internalUserEventQueueAtom), userEvent]);
1392
+ });
1393
+ /**
1394
+ * This atom exposes a function to reset the entire queue. All messages in the queue will be purged
1395
+ */
1396
+ const clearUserEventAtom = atom(null, (_, set) => {
1397
+ set(internalUserEventQueueAtom, []);
1398
+ });
1399
+ /**
1400
+ * This atom is used to mark events as processed and remove them from the queue
1401
+ * It accepts a list of eventId values and will remove all events with those eventIds from the queue.
1402
+ */
1403
+ const processUserEventAtom = atom(null, (get, set, eventIds) => {
1404
+ const remaining = get(internalUserEventQueueAtom)?.filter((event) => !eventIds.includes(event.eventId));
1405
+ set(internalUserEventQueueAtom, remaining);
1406
+ });
1407
+ const userQueueEventCountAtom = atom((get) => get(userEventQueueAtom).length);
1408
+ const createResponsePayload = ({ userEvents, generationParams }) => {
1409
+ const atomStore = getAtomStore();
1410
+ const context = atomStore.get(appDetailsAtom);
1411
+ const featureFlags = atomStore.get(featureFlagServiceAtom).getFeatureFlags();
1412
+ return {
1413
+ id: v4(),
1414
+ context,
1415
+ userEvents,
1416
+ featureFlags,
1417
+ generationParams
1418
+ };
1419
+ };
1420
+
1421
+ //#endregion
1422
+ //#region src/atoms/chat/replies.ts
1423
+ const handleReplyAtom = atom(null, (get, set, { message, userTyped }) => {
1424
+ if (message.type !== MessageType.QueryTyped) return;
1425
+ const queryTyped = message.metadata.content;
1426
+ set(replyEventCategoryAtom, UserEventCategory.QueryTyped);
1427
+ set(userQueryAtom, queryTyped);
1428
+ set(messagesAtom, [...get(messagesAtom), [message]]);
1429
+ set(userHasRepliedAtom, true);
1430
+ set(queueUserEventAtom, {
1431
+ eventId: message.id,
1432
+ createdAt: message.createdAt,
1433
+ category: UserEventCategory.QueryTyped,
1434
+ attributes: { query: queryTyped }
1435
+ });
1436
+ AmplitudeAdapter.trackEvent({
1437
+ eventName: SpiffyMetricsEventName.ChatUserMessageInput,
1438
+ eventProps: {
1439
+ message_id: message.id,
1440
+ message_role: message.role,
1441
+ message_type: message.type,
1442
+ message_metadata: {
1443
+ content: AmplitudeAdapter.amplitudeSafeString(message?.metadata?.content),
1444
+ created_at: message.createdAt,
1445
+ user_typed: userTyped
1446
+ }
1447
+ },
1448
+ alsoSendToGoogleAnalytics: true
1449
+ });
1450
+ });
1451
+
1452
+ //#endregion
1453
+ //#region src/atoms/chat/performanceMetrics.ts
1454
+ const APP_INITIAL_START_TIME_KEY = "spiffy-app-initial-start-time";
1455
+ const PAGE_LOAD_OFFSET_TIME_KEY = "spiffy-page-load-offset-time";
1456
+ /**
1457
+ * The different performance metrics that can be logged. All times are relative to the
1458
+ * initial start time of the app and are stored in milliseconds.
1459
+ */
1460
+ let PerfMetricsEvents = /* @__PURE__ */ function(PerfMetricsEvents$1) {
1461
+ PerfMetricsEvents$1["PageLoadOffset"] = "page_load_offset_ms";
1462
+ PerfMetricsEvents$1["MainBundleLoaded"] = "main_bundle_loaded_ms";
1463
+ PerfMetricsEvents$1["OrgConfigLoadStarted"] = "org_config_load_started_ms";
1464
+ PerfMetricsEvents$1["OrgConfigLoadEnded"] = "org_config_load_ended_ms";
1465
+ PerfMetricsEvents$1["FirstResponseStarted"] = "first_response_started_ms";
1466
+ PerfMetricsEvents$1["FirstResponseCompleted"] = "first_response_completed_ms";
1467
+ PerfMetricsEvents$1["FirstSuggestionsStarted"] = "first_suggestions_started_ms";
1468
+ PerfMetricsEvents$1["FirstSuggestionsCompleted"] = "first_suggestions_completed_ms";
1469
+ PerfMetricsEvents$1["EmbeddedWidgetRendered"] = "embedded_widget_rendered_ms";
1470
+ PerfMetricsEvents$1["FloatingButtonRendered"] = "floating_button_rendered_ms";
1471
+ PerfMetricsEvents$1["TopSuggestionsBarRendered"] = "top_suggestions_bar_rendered_ms";
1472
+ PerfMetricsEvents$1["BottomSuggestionsBarRendered"] = "bottom_suggestions_bar_rendered_ms";
1473
+ PerfMetricsEvents$1["SearchPromptRendered"] = "search_prompt_rendered_ms";
1474
+ return PerfMetricsEvents$1;
1475
+ }({});
1476
+ const internalPerfMetricsAtom = atom(/* @__PURE__ */ new Map());
1477
+ const appInitialStartTimeMsAtom = atomWithStorage(APP_INITIAL_START_TIME_KEY, sessionStorage.getItem(APP_INITIAL_START_TIME_KEY) ?? void 0, sessionStorageUtil, { getOnInit: true });
1478
+ const pageLoadOffsetTimeAtom = atomWithStorage(PAGE_LOAD_OFFSET_TIME_KEY, sessionStorage.getItem(PAGE_LOAD_OFFSET_TIME_KEY) ?? void 0, sessionStorageUtil, { getOnInit: true });
1479
+ /**
1480
+ * Resets the performance metrics atom to an empty map. This should be called after the performance
1481
+ * metrics have been reported to amplitude. On SPA, it ensures that we can still capture metrics as
1482
+ * the user navigates around the app (although there is more work to be done to fully enable this).
1483
+ * On non-SPA, it ensures that previously captured metrics are not reported again.
1484
+ */
1485
+ const resetPerformanceMetricsAtom = () => {
1486
+ getAtomStore().set(internalPerfMetricsAtom, /* @__PURE__ */ new Map());
1487
+ };
1488
+ const performanceMetricsAtom = atom((get) => get(internalPerfMetricsAtom));
1489
+ const hasReportedPerformanceMetricsAtom = atom(false);
1490
+ /**
1491
+ * Logs a performance metric by capturing the delta between the initial app start time
1492
+ * and the current time. If the metric has already been logged, it will not be logged again.
1493
+ *
1494
+ * @param value The performance metric name to log.
1495
+ */
1496
+ const logPerfMetricAtom = atom(null, (get, set, value) => {
1497
+ const initialTimeStorageValue = get(appInitialStartTimeMsAtom);
1498
+ const initialTimeMs = initialTimeStorageValue ? parseInt(initialTimeStorageValue, 10) : void 0;
1499
+ if (initialTimeMs == null) {
1500
+ logger_default.logWarn(`[spiffy-ai] No initial app start time found. Skipping...`, void 0);
1501
+ return;
1502
+ }
1503
+ const currentPerfMetrics = get(internalPerfMetricsAtom);
1504
+ if (currentPerfMetrics.has(value)) return;
1505
+ const deltaMs = Date.now() - initialTimeMs;
1506
+ currentPerfMetrics.set(value, deltaMs);
1507
+ set(internalPerfMetricsAtom, currentPerfMetrics);
1508
+ });
1509
+
1510
+ //#endregion
1511
+ //#region src/atoms/chat/form.ts
1512
+ const handleFormSubmittedAtom = atom(null, (_, set, form) => {
1513
+ set(replyEventCategoryAtom, UserEventCategory.FormSubmitted);
1514
+ set(formSubmitAtom, form);
1515
+ const formUserEvent = {
1516
+ eventId: v4(),
1517
+ category: UserEventCategory.FormSubmitted,
1518
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1519
+ attributes: form
1520
+ };
1521
+ set(queueUserEventAtom, formUserEvent);
1522
+ });
1523
+
1524
+ //#endregion
1525
+ //#region src/atoms/chat/suggestions.ts
1526
+ const handleSuggestionAtom = atom(null, (get, set, suggestion) => {
1527
+ const newMessage = {
1528
+ id: suggestion.id,
1529
+ role: MessageRole.User,
1530
+ type: MessageType.SuggestionClicked,
1531
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1532
+ metadata: {
1533
+ suggestionId: suggestion.id,
1534
+ suggestionContent: suggestion.content
1535
+ }
1536
+ };
1537
+ set(replyEventCategoryAtom, UserEventCategory.SuggestionClicked);
1538
+ set(suggestionAtom, suggestion);
1539
+ set(messagesAtom, [...get(messagesAtom), [newMessage]]);
1540
+ set(userHasRepliedAtom, true);
1541
+ set(queueUserEventAtom, {
1542
+ eventId: suggestion.id,
1543
+ category: UserEventCategory.SuggestionClicked,
1544
+ createdAt: newMessage.createdAt,
1545
+ attributes: { suggestionId: suggestion.id }
1546
+ });
1547
+ });
1548
+
1549
+ //#endregion
1550
+ //#region src/atoms/chat/lastMessage.ts
1551
+ const lastAssistantMessageAtom = atom((get) => {
1552
+ const messages = get(messagesAtom);
1553
+ const userHasReplied = get(userHasRepliedAtom);
1554
+ if (messages.length > 0 && !userHasReplied) return messages[messages.length - 1];
1555
+ return null;
1556
+ });
1557
+
1558
+ //#endregion
1559
+ //#region src/atoms/chat/renderedWidgetRefs.ts
1560
+ const internalWidgetArrayAtom = atom([]);
1561
+ const widgetArrayAtom = atom((get) => get(internalWidgetArrayAtom));
1562
+ /**
1563
+ * This function call is used to create a list of the Spiffy widgets
1564
+ * that are rendering on the page.
1565
+ *
1566
+ * It is used by the FloatingButton widget to slide out of view when it
1567
+ * overlaps with another Spiffy widget.
1568
+ *
1569
+ * The spiffy widgets should be added to the this array for the floating button
1570
+ * to know about them.
1571
+ *
1572
+ * Today the "SuggestionBar" widget is not added, but the other widgets are.
1573
+ *
1574
+ */
1575
+ const addWidget = (ref, idx) => {
1576
+ const atomStore = getAtomStore();
1577
+ const val = atomStore.get(internalWidgetArrayAtom);
1578
+ const insertIdx = idx ?? val.length;
1579
+ val[insertIdx] = ref;
1580
+ atomStore.set(internalWidgetArrayAtom, val);
1581
+ };
1582
+
1583
+ //#endregion
1584
+ //#region src/atoms/chat/index.ts
1585
+ const chatAtom = atom((get) => ({
1586
+ userHasReplied: get(userHasRepliedAtom),
1587
+ replyEventCategory: get(replyEventCategoryAtom),
1588
+ userQuery: get(userQueryAtom),
1589
+ suggestion: get(suggestionAtom),
1590
+ askQuestionBtnClicked: get(askQuestionBtnClickedAtom),
1591
+ messages: get(messagesAtom),
1592
+ userEvents: get(userEventsAtom),
1593
+ suggestions: get(suggestionsAtom),
1594
+ suggestionsLoading: get(suggestionsLoadingAtom),
1595
+ responseStreaming: get(responseStreamingAtom),
1596
+ isOpen: get(chatIsOpenAtom),
1597
+ onToggle: get(chatOnToggleAtom)
1598
+ }));
1599
+
1600
+ //#endregion
1601
+ //#region src/atoms/org/orgAnalyticsConfig.ts
1602
+ const internalOrgAnalyticsConfigAtom = atom(void 0);
1603
+ const orgAnalyticsConfigAtom = atom((get) => get(internalOrgAnalyticsConfigAtom), (_, set, value) => {
1604
+ set(internalOrgAnalyticsConfigAtom, value);
1605
+ });
1606
+ const orgAnalyticsAmplitudeConfigAtom = atom((get) => get(orgAnalyticsConfigAtom)?.amplitude);
1607
+ const orgAnalyticsCustomerServiceConfigAtom = atom((get) => get(orgAnalyticsConfigAtom)?.customerService);
1608
+ const orgAnalyticsGoogleAnalyticsConfigAtom = atom((get) => get(orgAnalyticsConfigAtom)?.googleAnalytics);
1609
+
1610
+ //#endregion
1611
+ //#region src/atoms/org/graphqlConfig.ts
1612
+ const internalGraphQLColorsConfigAtom = atom(void 0);
1613
+ const internalGraphQLFrontendConfigAtom = atom(void 0);
1614
+ const colorsConfigAtom = atom(async (get) => {
1615
+ const colors = get(internalGraphQLColorsConfigAtom);
1616
+ return {
1617
+ ...(await getOrgInfo(get(orgShortNameAtom))).orgColors(),
1618
+ ...colors
1619
+ };
1620
+ }, (_, set, value) => {
1621
+ set(internalGraphQLColorsConfigAtom, value);
1622
+ });
1623
+ const frontendConfigAtom = atom((get) => get(internalGraphQLFrontendConfigAtom), (_, set, value) => {
1624
+ set(internalGraphQLFrontendConfigAtom, value);
1625
+ });
1626
+
1627
+ //#endregion
1628
+ //#region src/atoms/org/orgUIConfig.ts
1629
+ const getCustomerServiceIntegrationMode = ({ integrationMode, isNewFeatureEnabled }) => {
1630
+ if (integrationMode !== CustomerServiceIntegrationMode.full) return integrationMode;
1631
+ return isNewFeatureEnabled ? integrationMode : CustomerServiceIntegrationMode.simple;
1632
+ };
1633
+ const internalOrgUIConfigAtom = atom(void 0);
1634
+ const orgUIConfigAtom = atom((get) => {
1635
+ const orgUIConfig = get(internalOrgUIConfigAtom);
1636
+ if (orgUIConfig) return orgUIConfig;
1637
+ throw new Error("OrgUIConfig is referenced before it is set");
1638
+ }, (_, set, value) => {
1639
+ set(internalOrgUIConfigAtom, value);
1640
+ });
1641
+ const getOrgUIConfig = async (graphqlOrgUIConfig, graphqlMerchantOverrideCss) => {
1642
+ const atomStore = getAtomStore();
1643
+ const orgShortName = atomStore.get(orgShortNameAtom);
1644
+ const localOrgUIConfig = (await getOrgInfo(orgShortName)).orgUIConfig() ?? {};
1645
+ const featureFlagService = atomStore.get(featureFlagServiceAtom);
1646
+ const isNewFeatureEnabled = featureFlagService.isFeatureGateEnabled(FeatureGates.IsNewFeatureEnabled);
1647
+ const enableWatermark = featureFlagService.isFeatureGateEnabled(FeatureGates.IsWatermarkEnabled);
1648
+ const userQueryAwaysEnabled = featureFlagService.isFeatureGateEnabled(FeatureGates.IsUserQueryAlwaysEnabled);
1649
+ const isGraphQLUIConfigsEnabled = featureFlagService.isFeatureGateEnabled(FeatureGates.IsGraphQLUIConfigsEnabled);
1650
+ const isGraphQLComponentConfigsEnabled = featureFlagService.isFeatureGateEnabled(FeatureGates.IsGraphQLComponentConfigsEnabled);
1651
+ let orgUIConfig = { ...localOrgUIConfig };
1652
+ if (isGraphQLUIConfigsEnabled && graphqlMerchantOverrideCss) orgUIConfig = {
1653
+ ...orgUIConfig,
1654
+ merchantOverrideCss: graphqlMerchantOverrideCss
1655
+ };
1656
+ if (isGraphQLComponentConfigsEnabled && graphqlOrgUIConfig) orgUIConfig = {
1657
+ ...orgUIConfig,
1658
+ ...graphqlOrgUIConfig
1659
+ };
1660
+ logger_default.logInfo("[spiffy-ai] Feature gate enableWatermark check", {
1661
+ enableWatermark,
1662
+ floatingChatConfig: orgUIConfig.floatingChatConfig
1663
+ });
1664
+ const updatedOrgUIConfig = {
1665
+ ...orgUIConfig,
1666
+ conversationalSearch: orgUIConfig.conversationalSearch ? {
1667
+ ...orgUIConfig.conversationalSearch,
1668
+ enabled: isNewFeatureEnabled
1669
+ } : void 0,
1670
+ customerServiceIntegration: {
1671
+ ...orgUIConfig.customerServiceIntegration,
1672
+ integrationMode: getCustomerServiceIntegrationMode({
1673
+ isNewFeatureEnabled,
1674
+ integrationMode: orgUIConfig.customerServiceIntegration?.integrationMode ?? CustomerServiceIntegrationMode.none
1675
+ })
1676
+ },
1677
+ floatingChatConfig: {
1678
+ ...orgUIConfig.floatingChatConfig,
1679
+ enableWatermark: orgUIConfig.floatingChatConfig?.enableWatermark && enableWatermark,
1680
+ userQueryInputEnabled: orgUIConfig.floatingChatConfig?.userQueryInputEnabled || userQueryAwaysEnabled
1681
+ }
1682
+ };
1683
+ atomStore.set(orgUIConfigAtom, updatedOrgUIConfig);
1684
+ };
1685
+ const orgCustomerServiceConfig = atom((get) => get(orgUIConfigAtom).customerServiceIntegration);
1686
+ const orgCustomerServiceService = atom((get) => {
1687
+ const { provider } = get(orgCustomerServiceConfig);
1688
+ return findCustomerServiceImpl(provider);
1689
+ });
1690
+
1691
+ //#endregion
1692
+ //#region src/atoms/org/org.ts
1693
+ const internalApiKeyAtom = atom(void 0);
1694
+ const internalEndpointURLAtom = atom(void 0);
1695
+ const internalSourceAtom = atom(EnvironmentService.getContextSource());
1696
+ const getApiKeyEnvVar = (shortName) => `VITE_${shortName.replace(/-/g, "_").toUpperCase()}_API_KEY`;
1697
+ const apiKeyAtom = atom((get) => {
1698
+ const apiKey = get(internalApiKeyAtom);
1699
+ if (apiKey) return apiKey;
1700
+ const { orgLevelApiKey, orgShortName } = useEnviveConfig();
1701
+ if (orgLevelApiKey) return orgLevelApiKey;
1702
+ if (window._spiffy?.publicKey && typeof window._spiffy.publicKey === "string") return window._spiffy.publicKey;
1703
+ if (!orgShortName) throw new Error("[spiffy-ai] orgShortName is required but is not set");
1704
+ throw new Error(`[spiffy-ai]: apiKey is missing`);
1705
+ }, (_, set, newVal) => {
1706
+ set(internalApiKeyAtom, newVal);
1707
+ });
1708
+ const endpointURLAtom = atom((get) => get(internalEndpointURLAtom) ?? EnvironmentService.getApiEndpoint(), (_, set, newVal) => {
1709
+ set(internalEndpointURLAtom, newVal);
1710
+ });
1711
+ const sourceAtom = atom((get) => get(internalSourceAtom), (_, set, newVal) => {
1712
+ set(internalSourceAtom, newVal);
1713
+ });
1714
+ const orgConfigStorageUtil = createJSONStorage(() => sessionStorage);
1715
+ const storedOrgConfigAtom = atomWithStorage("spiffy-org-config", void 0, orgConfigStorageUtil, { getOnInit: true });
1716
+ const internalFeatureFlagServiceAtom = atom(void 0);
1717
+ const internalOrgConfigAtom = atom(void 0);
1718
+ const internalOrgDomainAtom = atom(void 0);
1719
+ const internalOrgIdAtom = atom(void 0);
1720
+ const internalOrgShortNameAtom = atom(void 0);
1721
+ const featureFlagServiceAtom = atom((get) => {
1722
+ const featureFlagService = get(internalFeatureFlagServiceAtom);
1723
+ if (featureFlagService) return featureFlagService;
1724
+ const orgConfig = get(internalOrgConfigAtom);
1725
+ if (orgConfig) return new FeatureFlagService(orgConfig.gates);
1726
+ throw new Error("FeatureFlagService is referenced before it is set");
1727
+ }, (_, set, value) => {
1728
+ set(internalFeatureFlagServiceAtom, value);
1729
+ });
1730
+ const orgConfigAtom = atom((get) => {
1731
+ const orgConfig = get(internalOrgConfigAtom);
1732
+ if (orgConfig) return orgConfig;
1733
+ throw new Error("OrgConfig is referenced before it is set");
1734
+ }, (_, set, value) => {
1735
+ set(internalOrgConfigAtom, value);
1736
+ });
1737
+ const orgShortNameAtom = atom((get) => {
1738
+ const orgShortName = get(internalOrgShortNameAtom);
1739
+ if (orgShortName) return orgShortName;
1740
+ throw new Error("Org short name is referenced before it is set");
1741
+ }, (_, set, value) => {
1742
+ set(internalOrgShortNameAtom, value);
1743
+ });
1744
+ const orgDomainAtom = atom((get) => {
1745
+ const orgDomain = get(internalOrgDomainAtom);
1746
+ if (orgDomain) return orgDomain;
1747
+ throw new Error("Org domain is referenced before it is set");
1748
+ }, (_, set, value) => {
1749
+ set(internalOrgDomainAtom, value);
1750
+ });
1751
+ const orgIdAtom = atom((get) => {
1752
+ const orgId = get(internalOrgIdAtom);
1753
+ if (orgId) return orgId;
1754
+ throw new Error("Org id is referenced before it is set");
1755
+ }, (_, set, value) => {
1756
+ set(internalOrgIdAtom, value);
1757
+ });
1758
+ const resetStoredOrgConfigAtom = () => {
1759
+ getAtomStore().set(storedOrgConfigAtom, {});
1760
+ };
1761
+ const getGraphQLConfig = async (atomStore) => {
1762
+ const { colorsConfig, frontendConfig } = await GraphQLClient.getColorsAndFrontendConfig() ?? {};
1763
+ const rawFrontendConfig = atomStore.get(frontendConfigAtom);
1764
+ atomStore.set(colorsConfigAtom, colorsConfig);
1765
+ atomStore.set(frontendConfigAtom, {
1766
+ ...rawFrontendConfig,
1767
+ pageVariants: frontendConfig?.pageVariants,
1768
+ mountingConfigs: frontendConfig?.mountingConfigs,
1769
+ widgetConfigs: frontendConfig?.widgetConfigs
1770
+ });
1771
+ await getOrgUIConfig(frontendConfig?.uiConfigs, frontendConfig?.merchantOverrideCss);
1772
+ };
1773
+ /**
1774
+ * This function is used to return an orgConfig corresponding to a given API key
1775
+ *
1776
+ * @param apiKeyOverride an optional new api key to override the current key stored in apiKeyAtom
1777
+ *
1778
+ * @returns The OrgAnalyticsConfig object or throws an error if the config was not successfully retrieved
1779
+ */
1780
+ const getAsyncOrgConfig = async (apiKeyOverride) => {
1781
+ const atomStore = getAtomStore();
1782
+ const apiKey = apiKeyOverride ?? atomStore.get(apiKeyAtom);
1783
+ atomStore.set(apiKeyAtom, apiKey);
1784
+ atomStore.set(endpointURLAtom, EnvironmentService.getApiEndpoint());
1785
+ atomStore.set(sourceAtom, EnvironmentService.getContextSource());
1786
+ atomStore.set(logPerfMetricAtom, PerfMetricsEvents.OrgConfigLoadStarted);
1787
+ const maybeOrgConfigByApiKey = atomStore.get(storedOrgConfigAtom);
1788
+ let maybeOrgConfig = maybeOrgConfigByApiKey?.[apiKey];
1789
+ if (!maybeOrgConfig) {
1790
+ const userId = UserIdentityService.getUserIdOrDefault();
1791
+ maybeOrgConfig = await api_default.getOrgConfig(userId);
1792
+ }
1793
+ if (!maybeOrgConfig) throw new Error("[spiffy-ai] Org config is not defined but is required");
1794
+ const latestConfig = maybeOrgConfig.configs?.find((config) => config.isLatest);
1795
+ if (!latestConfig) throw new Error("[spiffy-ai] no latest org config is found");
1796
+ const orgConfig = {
1797
+ ...maybeOrgConfig,
1798
+ configs: [{ ...latestConfig }]
1799
+ };
1800
+ if (!orgConfig.org) throw new Error("[spiffy-ai] orgConfig.org is not defined but is required");
1801
+ atomStore.set(logPerfMetricAtom, PerfMetricsEvents.OrgConfigLoadEnded);
1802
+ atomStore.set(orgShortNameAtom, orgConfig.org.org.shortName);
1803
+ atomStore.set(orgDomainAtom, orgConfig.org.org.domain);
1804
+ atomStore.set(orgIdAtom, orgConfig.org.org.id);
1805
+ atomStore.set(storedOrgConfigAtom, {
1806
+ ...maybeOrgConfigByApiKey,
1807
+ [apiKey]: orgConfig
1808
+ });
1809
+ atomStore.set(orgConfigAtom, orgConfig);
1810
+ atomStore.set(orgAnalyticsConfigAtom, { ...latestConfig.config });
1811
+ atomStore.set(featureFlagServiceAtom, new FeatureFlagService(orgConfig.gates));
1812
+ await getGraphQLConfig(atomStore);
1813
+ return orgConfig;
1814
+ };
1815
+
1816
+ //#endregion
1817
+ //#region src/adapters/spiffy/commerce/graphql.ts
1818
+ const configVersion = () => getQueryParam("spiffy_config_version") || getQueryParam("envive_config_version") || "deployed";
1819
+ const colorsAndFrontendConfigQuery = () => `
1820
+ query ($version: String = "${configVersion()}") {
1821
+ me {
1822
+ getProductsConfigByVersion(version: $version) {
1823
+ frontend { values }
1824
+ colors { values }
1825
+ }
1826
+ }
1827
+ }
1828
+ `;
1829
+ var GraphQLClient = class GraphQLClient {
1830
+ static {
1831
+ this.setInstance = (apiKey, basePath) => {
1832
+ GraphQLClient.instance = new GraphQLClient(apiKey, basePath);
1833
+ };
1834
+ }
1835
+ static {
1836
+ this.getInstance = () => {
1837
+ if (!GraphQLClient.instance) {
1838
+ const apiKey = getAtomStore().get(apiKeyAtom);
1839
+ GraphQLClient.instance = new GraphQLClient(apiKey, EnvironmentService.getApiEndpoint());
1840
+ }
1841
+ return GraphQLClient.instance;
1842
+ };
1843
+ }
1844
+ constructor(apiKey, basePath) {
1845
+ this.apiKey = apiKey;
1846
+ this.basePath = basePath;
1847
+ }
1848
+ async executeQuery(query, variables) {
1849
+ const response = await fetch(`${this.basePath}/v1/graphql`, {
1850
+ method: "POST",
1851
+ headers: {
1852
+ "Content-Type": "application/json",
1853
+ Authorization: `Bearer ${this.apiKey}`
1854
+ },
1855
+ body: JSON.stringify({
1856
+ query,
1857
+ variables
1858
+ })
1859
+ });
1860
+ if (!response.ok) throw new Error(`GraphQL request failed: ${response.statusText}`);
1861
+ const result = await response.json();
1862
+ if (result.errors) throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`);
1863
+ return result.data;
1864
+ }
1865
+ static {
1866
+ this.getOrgId = async () => {
1867
+ const query = getMerchantOrgIdQuery;
1868
+ if (!query) throw new Error("Org id query is not defined");
1869
+ const response = await GraphQLClient.getInstance().executeQuery(query);
1870
+ return validateGraphQLOrgId(response.me.org?.id);
1871
+ };
1872
+ }
1873
+ static {
1874
+ this.getColorsAndFrontendConfig = async () => {
1875
+ try {
1876
+ const query = colorsAndFrontendConfigQuery();
1877
+ if (!query) throw new Error("Colors and frontend config query is not defined");
1878
+ const response = await GraphQLClient.getInstance().executeQuery(query);
1879
+ return {
1880
+ colorsConfig: validateGraphQLColorsConfig(response.me.getProductsConfigByVersion?.colors?.values),
1881
+ frontendConfig: validateGraphQLFrontendConfig(response.me.getProductsConfigByVersion?.frontend?.values)
1882
+ };
1883
+ } catch (err) {
1884
+ logger_default.logError("Error fetching graphql colors and frontend config", err);
1885
+ return {
1886
+ colorsConfig: void 0,
1887
+ frontendConfig: void 0
1888
+ };
1889
+ }
1890
+ };
1891
+ }
1892
+ static {
1893
+ this.getFrontendConfig = async () => {
1894
+ try {
1895
+ const query = getMerchantFrontendConfigQuery();
1896
+ if (!query) throw new Error("Frontend config query is not defined");
1897
+ const response = await GraphQLClient.getInstance().executeQuery(query);
1898
+ if (!response.me.getProductsConfigByVersion?.frontend) throw new Error("No frontend config found");
1899
+ return validateGraphQLFrontendConfig(response.me.getProductsConfigByVersion.frontend.values);
1900
+ } catch (err) {
1901
+ logger_default.logError("Error fetching graphql frontend config", err);
1902
+ return;
1903
+ }
1904
+ };
1905
+ }
1906
+ static {
1907
+ this.getColors = async () => {
1908
+ try {
1909
+ const query = getMerchantColorsQuery();
1910
+ if (!query) throw new Error("Colors query is not defined");
1911
+ const response = await GraphQLClient.getInstance().executeQuery(query);
1912
+ if (!response.me.getProductsConfigByVersion?.colors) throw new Error("No colors config found");
1913
+ return isGraphQLColorsConfig(response.me.getProductsConfigByVersion.colors.values) ? response.me.getProductsConfigByVersion.colors.values : void 0;
1914
+ } catch (err) {
1915
+ logger_default.logError("Error fetching graphql colors config", err);
1916
+ return;
1917
+ }
1918
+ };
1919
+ }
1920
+ };
1921
+
1922
+ //#endregion
1923
+ //#region src/application/models/graphql/queries/getMerchantFrontendConfigQuery.ts
1924
+ const getMerchantFrontendConfigQuery = () => `
1925
+ query ($version: "${configVersion()}") {
1926
+ me {
1927
+ getProductsConfigByVersion(version: $version) {
1928
+ frontend {
1929
+ values
1930
+ }
1931
+ }
1932
+ }
1933
+ }
1934
+ `;
1935
+
1936
+ //#endregion
1937
+ //#region src/application/models/graphql/queries/getMerchantColorsQuery.ts
1938
+ const getMerchantColorsQuery = () => `
1939
+ query ($version: "${configVersion()}") {
1940
+ me {
1941
+ getProductsConfigByVersion(version: $version) {
1942
+ colors {
1943
+ values
1944
+ }
1945
+ }
1946
+ }
1947
+ }
1948
+ `;
1949
+
1950
+ //#endregion
1951
+ //#region src/application/models/guards/isBaseEcommerceEvent.ts
1952
+ /**
1953
+ * Checks if an event is a base Google Analytics ecommerce event.
1954
+ *
1955
+ * @param data The event to check.
1956
+ *
1957
+ * @returns True if the event is a base ecommerce event, false otherwise.
1958
+ */
1959
+ const isBaseEcommerceEvent = (data) => data != null && typeof data === "object" && "ecommerce" in data && data.ecommerce != null && typeof data.ecommerce === "object" && "event" in data && typeof data.event === "string";
1960
+
1961
+ //#endregion
1962
+ //#region src/application/models/guards/isGA4EcommerceEvent.ts
1963
+ /**
1964
+ * Checks if an event is a Google Analytics 4 ecommerce event.
1965
+ *
1966
+ * @param data The event to check.
1967
+ *
1968
+ * @returns True if the event is a GA4 ecommerce event, false otherwise.
1969
+ */
1970
+ const isGA4EcommerceEvent = (data) => typeof data === "object" && data != null && "ecommerce" in data && data.ecommerce != null && typeof data.ecommerce === "object" && "items" in data.ecommerce && Array.isArray(data.ecommerce.items);
1971
+
1972
+ //#endregion
1973
+ //#region src/application/models/guards/isLegacyUAEcommerceEvent.ts
1974
+ /**
1975
+ * Checks if an event is a legacy Universal Analytics ecommerce event.
1976
+ *
1977
+ * @param data The event to check.
1978
+ *
1979
+ * @returns True if the event is a legacy UA ecommerce event, false otherwise.
1980
+ */
1981
+ const isLegacyUAEcommerceEvent = (data) => data != null && typeof data === "object" && "ecommerce" in data && data.ecommerce != null && typeof data.ecommerce === "object" && "add" in data.ecommerce && typeof data.ecommerce.add === "object";
1982
+
1983
+ //#endregion
1984
+ //#region src/application/models/guards/isMobilePLPChatPlacementParameter.ts
1985
+ const isMobilePLPChatPlacementParameter = (value) => value != null && typeof value === "object" && "row_index" in value && typeof value.row_index === "number";
1986
+
1987
+ //#endregion
1988
+ //#region src/application/models/guards/isSpanxTakeAQuizCtaParameter.ts
1989
+ const isSpanxTakeAQuizCtaParameter = (value) => value != null && typeof value === "object" && "text" in value && typeof value.text === "string";
1990
+
1991
+ //#endregion
1992
+ //#region src/application/models/guards/isVariantInfo.ts
1993
+ const isPDPVariantInfo = (variantInfo) => "variant" in variantInfo && variantInfo.variant === "pdp" && "productId" in variantInfo && typeof variantInfo.productId === "string";
1994
+ const isPLPVariantInfo = (variantInfo) => "variant" in variantInfo && variantInfo.variant === "plp" && "plpId" in variantInfo && typeof variantInfo.plpId === "string";
1995
+ const isPageVisitVariantInfo = (variantInfo) => "variant" in variantInfo && variantInfo.variant === "page_visit" && "url" in variantInfo && typeof variantInfo.url === "string" && "pageVisitCategory" in variantInfo && Object.values(PageVisitCategory).includes(variantInfo.pageVisitCategory);
1996
+ /**
1997
+ * Type guard to check if an object is a valid VariantInfo.
1998
+ *
1999
+ * @param variantInfo - The unknown object to check.
2000
+ *
2001
+ * @returns True if the data is a valid VariantInfo object, false otherwise.
2002
+ */
2003
+ const isVariantInfo = (variantInfo) => variantInfo != null && typeof variantInfo === "object" && "variantId" in variantInfo && (isPDPVariantInfo(variantInfo) || isPLPVariantInfo(variantInfo) || isPageVisitVariantInfo(variantInfo));
2004
+
2005
+ //#endregion
2006
+ //#region src/application/models/guards/api/isApiFormResponse.ts
2007
+ /**
2008
+ * Type guard to check if the provided data has the all of the properties (with the correct types) of
2009
+ * a FormResponseAttribute
2010
+ *
2011
+ * @param data - The data to check
2012
+ *
2013
+ * @returns true if the data has the correct properties, false otherwise
2014
+ */
2015
+ const isApiFormResponseAttributes = (data) => {
2016
+ if (data == null || typeof data !== "object") {
2017
+ logger_default.logError("isApiFormResponseAttributes: data is null or not an object", void 0, { data });
2018
+ return false;
2019
+ }
2020
+ if ("form_category" in data && typeof data.form_category !== "object") {
2021
+ logger_default.logError("isApiFormResponseAttributes: form_category is not an object", void 0, { data });
2022
+ return false;
2023
+ }
2024
+ if ("form_category" in data && typeof data.form_category === "object") {
2025
+ if (!hasPropertyOfType(data.form_category, "form_type", "string") || !Object.values(FormType).includes(data.form_category.form_type)) {
2026
+ logger_default.logError("isApiFormResponseAttributes: form_type is missing or not a valid form type", void 0, { data });
2027
+ return false;
2028
+ }
2029
+ }
2030
+ if (!hasPropertyOfType(data, "schema", "object")) {
2031
+ logger_default.logError("isApiFormResponseAttributes: schema is missing or not an object", void 0, { data });
2032
+ return false;
2033
+ }
2034
+ if (!hasPropertyOfType(data.schema, "properties", "object")) {
2035
+ logger_default.logError("isApiFormResponseAttributes: schema.properties is missing or not an object", void 0, { data });
2036
+ return false;
2037
+ }
2038
+ if (!hasPropertyOfType(data.schema, "required", "array")) {
2039
+ logger_default.logError("isApiFormResponseAttributes: schema.required is missing or not an array", void 0, { data });
2040
+ return false;
2041
+ }
2042
+ if (!data.schema.required.every((key) => typeof key === "string" && key in data.schema.properties)) {
2043
+ logger_default.logError("isApiFormResponseAttributes: schema.required contains invalid property keys", void 0, { data });
2044
+ return false;
2045
+ }
2046
+ return true;
2047
+ };
2048
+
2049
+ //#endregion
2050
+ //#region src/application/models/guards/api/isApiOrderResponseAttributes.ts
2051
+ const isApiOrderItemInfo = (data) => {
2052
+ if (data == null || typeof data !== "object") {
2053
+ logger_default.logError("OrderItemInfo must be an object", void 0, { data });
2054
+ return false;
2055
+ }
2056
+ if (!hasPropertyOfType(data, "order_item_id", "string")) {
2057
+ logger_default.logError("OrderItemInfo must have an order_item_id property", void 0, { data });
2058
+ return false;
2059
+ }
2060
+ if (!hasPropertyOfType(data, "item_title", "string")) {
2061
+ logger_default.logError("OrderItemInfo must have an item_title property", void 0, { data });
2062
+ return false;
2063
+ }
2064
+ if (!hasPropertyOfType(data, "item_price", "number")) {
2065
+ logger_default.logError("OrderItemInfo must have an item_price property", void 0, { data });
2066
+ return false;
2067
+ }
2068
+ if (!hasPropertyOfType(data, "item_quantity", "number")) {
2069
+ logger_default.logError("OrderItemInfo must have an item_quantity property", void 0, { data });
2070
+ return false;
2071
+ }
2072
+ if (!hasPropertyOfType(data, "image", "string", true)) {
2073
+ logger_default.logError("OrderItemInfo.image must be a string or null", void 0, { data });
2074
+ return false;
2075
+ }
2076
+ if (!hasPropertyOfType(data, "fulfillment_display_status", "string", true)) {
2077
+ logger_default.logError("OrderItemInfo.fulfillment_display_status must be a string or null", void 0, { data });
2078
+ return false;
2079
+ }
2080
+ if (!hasPropertyOfType(data, "tracking_url", "string", true)) {
2081
+ logger_default.logError("OrderItemInfo.tracking_url must be a string or null", void 0, { data });
2082
+ return false;
2083
+ }
2084
+ if (!hasPropertyOfType(data, "delivered_at", "string", true)) {
2085
+ logger_default.logError("OrderItemInfo.delivered_at must be a string or null", void 0, { data });
2086
+ return false;
2087
+ }
2088
+ if (!hasPropertyOfType(data, "estimated_delivery_at", "string", true)) {
2089
+ logger_default.logError("OrderItemInfo.estimated_delivery_at must be a string or null", void 0, { data });
2090
+ return false;
2091
+ }
2092
+ if (!hasPropertyOfType(data, "in_transit_at", "string", true)) {
2093
+ logger_default.logError("OrderItemInfo.in_transit_at must be a string or null", void 0, { data });
2094
+ return false;
2095
+ }
2096
+ return true;
2097
+ };
2098
+ const isApiOrderResponseAttributes = (data) => {
2099
+ if (data == null || typeof data !== "object") {
2100
+ logger_default.logError("Order response attributes must be an object", void 0, { data });
2101
+ return false;
2102
+ }
2103
+ if (!hasPropertyOfType(data, "created_at", "string")) {
2104
+ logger_default.logError("Order response attributes must have a created_at property and have type string", void 0, { data });
2105
+ return false;
2106
+ }
2107
+ if (!hasPropertyOfType(data, "latest_event_date", "string")) {
2108
+ logger_default.logError("Order response attributes must have a latest_event_date property and have type string", void 0, { data });
2109
+ return false;
2110
+ }
2111
+ if (!hasPropertyOfType(data, "line_items", "array") || !data.line_items.every((item) => isApiOrderItemInfo(item))) {
2112
+ logger_default.logError("Order response attributes must have a line_items property with at least one order item", void 0, { data });
2113
+ return false;
2114
+ }
2115
+ if (!hasPropertyOfType(data, "order_id", "string")) {
2116
+ logger_default.logError("Order response attributes must have an order_id property and have type string", void 0, { data });
2117
+ return false;
2118
+ }
2119
+ if (!hasPropertyOfType(data, "order_number", "string")) {
2120
+ logger_default.logError("Order response attributes must have an order_number property and have type string", void 0, { data });
2121
+ return false;
2122
+ }
2123
+ return true;
2124
+ };
2125
+
2126
+ //#endregion
2127
+ //#region src/application/models/guards/api/isApiOrganizationConfig.ts
2128
+ const isApiOrgAnalyticsConfigAmplitude = (data) => {
2129
+ if (data == null || typeof data !== "object") {
2130
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: data is not an object", data);
2131
+ return false;
2132
+ }
2133
+ if (!("session_replay_enabled" in data) || typeof data.session_replay_enabled !== "boolean") {
2134
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: session_replay_enabled is not a boolean", data);
2135
+ return false;
2136
+ }
2137
+ if (!("session_replay_sample_rate" in data) || typeof data.session_replay_sample_rate !== "number") {
2138
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: session_replay_sample_rate is not a number", data);
2139
+ return false;
2140
+ }
2141
+ if (!("tracking_enabled" in data) || typeof data.tracking_enabled !== "boolean") {
2142
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: tracking_enabled is not a boolean", data);
2143
+ return false;
2144
+ }
2145
+ return true;
2146
+ };
2147
+ const isApiOrgAnalyticsConfigCustomerService = (data) => {
2148
+ if (data == null || typeof data !== "object") {
2149
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigCustomerService: data is not an object", data);
2150
+ return false;
2151
+ }
2152
+ if (!("provider" in data) || typeof data.provider !== "string") {
2153
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigCustomerService: provider is not a string", data);
2154
+ return false;
2155
+ }
2156
+ return true;
2157
+ };
2158
+ const isApiOrgAnalyticsConfigGoogleAnalytics = (data) => {
2159
+ if (data == null || typeof data !== "object") {
2160
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigGoogleAnalytics: data is not an object", data);
2161
+ return false;
2162
+ }
2163
+ if (!("measurement_id" in data) || typeof data.measurement_id !== "string") {
2164
+ logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigGoogleAnalytics: measurement_id is not a string", data);
2165
+ return false;
2166
+ }
2167
+ return true;
2168
+ };
2169
+ /**
2170
+ *
2171
+ * @param data
2172
+ * @returns
2173
+ */
2174
+ const isApiOrgAnalyticsConfig = (data) => {
2175
+ if (data == null || typeof data !== "object") {
2176
+ logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: data is not an object", data);
2177
+ return false;
2178
+ }
2179
+ if ("amplitude" in data && !isApiOrgAnalyticsConfigAmplitude(data.amplitude)) {
2180
+ logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: amplitude is not an object", data);
2181
+ return false;
2182
+ }
2183
+ if ("customer_service" in data && !isApiOrgAnalyticsConfigCustomerService(data.customer_service)) {
2184
+ logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: customer_service is not an object", data);
2185
+ return false;
2186
+ }
2187
+ if ("google_analytics" in data && !isApiOrgAnalyticsConfigGoogleAnalytics(data.google_analytics)) {
2188
+ logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: google_analytics is not an object", data);
2189
+ return false;
2190
+ }
2191
+ return true;
2192
+ };
2193
+ /**
2194
+ *
2195
+ * @param data
2196
+ * @returns
2197
+ */
2198
+ const isApiOrganizationConfig = (data) => {
2199
+ if (data == null || typeof data !== "object") {
2200
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: data is not an object", data);
2201
+ return false;
2202
+ }
2203
+ if (!("created_at" in data)) {
2204
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: created_at is not defined", data);
2205
+ return false;
2206
+ }
2207
+ if (!("namespace" in data) || typeof data.namespace !== "string") {
2208
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: namespace is not a string", data);
2209
+ return false;
2210
+ }
2211
+ if (!("is_latest" in data) || typeof data.is_latest !== "boolean") {
2212
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: is_latest is not a boolean", data);
2213
+ return false;
2214
+ }
2215
+ if (!("version" in data) || typeof data.version !== "string") {
2216
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: version is not a string", data);
2217
+ return false;
2218
+ }
2219
+ if (!("updated_at" in data)) {
2220
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: updated_at is not defined", data);
2221
+ return false;
2222
+ }
2223
+ if (!("config" in data) || typeof data.config !== "object" || !isApiOrgAnalyticsConfig(data.config)) {
2224
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: config is not an object", data);
2225
+ return false;
2226
+ }
2227
+ if ("organization_id" in data && typeof data.organization_id !== "string") {
2228
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: organization_id is not a string", data);
2229
+ return false;
2230
+ }
2231
+ if ("id" in data && typeof data.id !== "string") {
2232
+ logger_default.logDebug("[spiffy-ai] isOrgConfig: id is not a string", data);
2233
+ return false;
2234
+ }
2235
+ return true;
2236
+ };
2237
+
2238
+ //#endregion
2239
+ //#region src/application/models/guards/api/isApiOrgConfigResults.ts
2240
+ const isApiOrgConfigExperiment = (data) => {
2241
+ if (data == null || typeof data !== "object") {
2242
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: data is not an object", void 0, { data });
2243
+ return false;
2244
+ }
2245
+ if ("group" in data && typeof data.group !== "string" && data.group !== void 0) {
2246
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: group is not a string or undefined", void 0, { data });
2247
+ return false;
2248
+ }
2249
+ if ("group_name" in data && typeof data.group_name !== "string" && data.group_name !== void 0) {
2250
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: group_name is not a string", void 0, { data });
2251
+ return false;
2252
+ }
2253
+ if ("name" in data && typeof data.name !== "string" && data.name !== void 0) {
2254
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: name is not a string", void 0, { data });
2255
+ return false;
2256
+ }
2257
+ if ("rule_id" in data && typeof data.rule_id !== "string" && data.rule_id !== void 0) {
2258
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: rule_id is not a string", void 0, { data });
2259
+ return false;
2260
+ }
2261
+ if ("value" in data && typeof data.value !== "object" && data.value !== void 0) {
2262
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: value is not an object", void 0, { data });
2263
+ return false;
2264
+ }
2265
+ return true;
2266
+ };
2267
+ const isApiOrgConfigFeatureGate = (data) => {
2268
+ if (data == null || typeof data !== "object") {
2269
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: data is not an object", void 0, { data });
2270
+ return false;
2271
+ }
2272
+ if ("name" in data && typeof data.name !== "string" && data.name !== void 0) {
2273
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: name is not a string", void 0, { data });
2274
+ return false;
2275
+ }
2276
+ if ("rule_id" in data && typeof data.rule_id !== "string" && data.rule_id !== void 0) {
2277
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: rule_id is not a string", void 0, { data });
2278
+ return false;
2279
+ }
2280
+ if ("value" in data && typeof data.value !== "boolean" && data.value !== void 0) {
2281
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: value is not a boolean", void 0, { data });
2282
+ return false;
2283
+ }
2284
+ return true;
2285
+ };
2286
+ const isApiOrganization = (data) => {
2287
+ if (data == null || typeof data !== "object") {
2288
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: data is not an object", void 0, { data });
2289
+ return false;
2290
+ }
2291
+ if (!("id" in data) || typeof data.id !== "string") {
2292
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: id is not a string", void 0, { data });
2293
+ return false;
2294
+ }
2295
+ if (!("display_name" in data) || typeof data.display_name !== "string") {
2296
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: display_name is not a string", void 0, { data });
2297
+ return false;
2298
+ }
2299
+ if (!("domain" in data) || typeof data.domain !== "string") {
2300
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: domain is not a string", void 0, { data });
2301
+ return false;
2302
+ }
2303
+ if (!("short_name" in data) || typeof data.short_name !== "string") {
2304
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: short_name is not a string", void 0, { data });
2305
+ return false;
2306
+ }
2307
+ if (!("status" in data) || !Object.values(OrganizationStatusEnum).includes(data.status)) {
2308
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: status is not a valid OrganizationStatusEnum value", void 0, { data });
2309
+ return false;
2310
+ }
2311
+ if ("created_at" in data && !(data.created_at instanceof Date) && typeof data.created_at !== "string" && data.created_at !== void 0) {
2312
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: created_at is not a Date", void 0, { data });
2313
+ return false;
2314
+ }
2315
+ if ("updated_at" in data && !(data.updated_at instanceof Date) && typeof data.updated_at !== "string" && data.updated_at !== void 0) {
2316
+ logger_default.logDebug("[spiffy-ai] isApiOrganization: updated_at is not a Date", void 0, { data });
2317
+ return false;
2318
+ }
2319
+ return true;
2320
+ };
2321
+ const isApiOrgConfigOrganizationSettings = (data) => {
2322
+ if (data == null || typeof data !== "object") {
2323
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigOrganizationSettings: data is not an object", void 0, { data });
2324
+ return false;
2325
+ }
2326
+ if (!("org" in data) || !isApiOrganization(data.org)) {
2327
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigOrganizationSettings: org is not an object", void 0, { data });
2328
+ return false;
2329
+ }
2330
+ return true;
2331
+ };
2332
+ /**
2333
+ *
2334
+ * @param data
2335
+ * @returns
2336
+ */
2337
+ const isApiOrgConfigResults = (data) => {
2338
+ if (data == null || typeof data !== "object") {
2339
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: data is not an object", void 0, { data });
2340
+ return false;
2341
+ }
2342
+ if (!("configs" in data) || !Array.isArray(data.configs) || !data.configs.every((config) => isApiOrganizationConfig(config))) {
2343
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: configs is not an array", void 0, { data });
2344
+ return false;
2345
+ }
2346
+ if ("experiments" in data && data.experiments !== void 0 && (!Array.isArray(data.experiments) || !data.experiments.every((exp) => isApiOrgConfigExperiment(exp)))) {
2347
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: experiments is not an array or contains invalid items", void 0, { data });
2348
+ return false;
2349
+ }
2350
+ if (!("gates" in data) || !Array.isArray(data.gates) || !data.gates.every((gate) => isApiOrgConfigFeatureGate(gate))) {
2351
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: gates is not an array or contains invalid items", void 0, { data });
2352
+ return false;
2353
+ }
2354
+ if (!("org" in data) || !isApiOrgConfigOrganizationSettings(data.org)) {
2355
+ logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: org is not an object or has invalid fields", void 0, { data });
2356
+ return false;
2357
+ }
2358
+ return true;
2359
+ };
2360
+
2361
+ //#endregion
2362
+ //#region src/application/models/guards/api/isApiPageResponseAttributes.ts
2363
+ const isApiPageResponseAttributes = (obj) => {
2364
+ if (obj == null || typeof obj !== "object") return false;
2365
+ if ("title" in obj && obj.title != null && typeof obj.title !== "string") return false;
2366
+ if ("description" in obj && typeof obj.description !== "string") return false;
2367
+ if ("url" in obj && typeof obj.url !== "string") return false;
2368
+ return true;
2369
+ };
2370
+
2371
+ //#endregion
2372
+ //#region src/application/models/guards/api/isApiProductSearchFilterAttributes.ts
2373
+ const isApiProductSearchFilterResponseAttributes = (attributes) => {
2374
+ if (attributes == null || typeof attributes !== "object") return false;
2375
+ if ("filter_name" in attributes && typeof attributes.filter_name !== "string") return false;
2376
+ return true;
2377
+ };
2378
+
2379
+ //#endregion
2380
+ //#region src/application/models/utils/stringToFulfillmentDisplayStatusEnumValue.ts
2381
+ /**
2382
+ * Converts a string to a FulfillmentDisplayStatus enum value.
2383
+ *
2384
+ * @param status - The string to convert.
2385
+ *
2386
+ * @returns The FulfillmentDisplayStatus enum value or undefined if the string
2387
+ * does not map to a valid enum
2388
+ */
2389
+ const stringToFulfillmentDisplayStatusEnumValue = (status) => {
2390
+ switch (status) {
2391
+ case "ATTEMPTED_DELIVERY": return FulfillmentDisplayStatus.ATTEMPTED_DELIVERY;
2392
+ case "CANCELED": return FulfillmentDisplayStatus.CANCELED;
2393
+ case "CONFIRMED": return FulfillmentDisplayStatus.CONFIRMED;
2394
+ case "DELIVERED": return FulfillmentDisplayStatus.DELIVERED;
2395
+ case "FAILURE": return FulfillmentDisplayStatus.FAILURE;
2396
+ case "FULFILLED": return FulfillmentDisplayStatus.FULFILLED;
2397
+ case "IN_TRANSIT": return FulfillmentDisplayStatus.IN_TRANSIT;
2398
+ case "LABEL_PRINTED": return FulfillmentDisplayStatus.LABEL_PRINTED;
2399
+ case "LABEL_PURCHASED": return FulfillmentDisplayStatus.LABEL_PURCHASED;
2400
+ case "LABEL_VOIDED": return FulfillmentDisplayStatus.LABEL_VOIDED;
2401
+ case "MARKED_AS_FULFILLED": return FulfillmentDisplayStatus.MARKED_AS_FULFILLED;
2402
+ case "NOT_DELIVERED": return FulfillmentDisplayStatus.NOT_DELIVERED;
2403
+ case "OUT_FOR_DELIVERY": return FulfillmentDisplayStatus.OUT_FOR_DELIVERY;
2404
+ case "PICKED_UP": return FulfillmentDisplayStatus.PICKED_UP;
2405
+ case "READY_FOR_PICKUP": return FulfillmentDisplayStatus.READY_FOR_PICKUP;
2406
+ case "SUBMITTED": return FulfillmentDisplayStatus.SUBMITTED;
2407
+ case "IN_PROGRESS": return FulfillmentDisplayStatus.IN_PROGRESS;
2408
+ case "ON_HOLD": return FulfillmentDisplayStatus.ON_HOLD;
2409
+ case "OPEN": return FulfillmentDisplayStatus.OPEN;
2410
+ case "PARTIALLY_FULFILLED": return FulfillmentDisplayStatus.PARTIALLY_FULFILLED;
2411
+ case "PENDING_FULFILLMENT": return FulfillmentDisplayStatus.PENDING_FULFILLMENT;
2412
+ case "REQUEST_DECLINED": return FulfillmentDisplayStatus.REQUEST_DECLINED;
2413
+ case "RESTOCKED": return FulfillmentDisplayStatus.RESTOCKED;
2414
+ case "SCHEDULED": return FulfillmentDisplayStatus.SCHEDULED;
2415
+ case "UNFULFILLED": return FulfillmentDisplayStatus.UNFULFILLED;
2416
+ default: return;
2417
+ }
2418
+ };
2419
+
2420
+ //#endregion
2421
+ //#region src/application/models/validators/validateMobilePLPChatPlacementParameter.ts
2422
+ const validateMobilePLPChatPlacementParameter = (value) => {
2423
+ if (!isMobilePLPChatPlacementParameter(value)) return;
2424
+ return { rowIndex: value.row_index };
2425
+ };
2426
+
2427
+ //#endregion
2428
+ //#region src/application/models/validators/validateOrganizationConfig.ts
2429
+ const validateOrganizationConfig = (data) => {
2430
+ if (!isApiOrganizationConfig(data)) return;
2431
+ return {
2432
+ id: data.id,
2433
+ createdAt: data.created_at.toISOString(),
2434
+ namespace: data.namespace,
2435
+ organizationId: data.organization_id,
2436
+ isLatest: data.is_latest,
2437
+ version: data.version,
2438
+ updatedAt: data.updated_at.toISOString(),
2439
+ config: {
2440
+ amplitude: data.config.amplitude ? {
2441
+ sessionReplayEnabled: data.config.amplitude.session_replay_enabled,
2442
+ sessionReplaySampleRate: data.config.amplitude.session_replay_sample_rate,
2443
+ trackingEnabled: data.config.amplitude.tracking_enabled
2444
+ } : void 0,
2445
+ customerService: data.config.customer_service ? { provider: data.config.customer_service.provider } : void 0,
2446
+ googleAnalytics: data.config.google_analytics ? { measurementId: data.config.google_analytics.measurement_id } : void 0
2447
+ }
2448
+ };
2449
+ };
2450
+
2451
+ //#endregion
2452
+ //#region src/application/models/validators/validateOrgConfigResults.ts
2453
+ /**
2454
+ *
2455
+ * @param data
2456
+ * @returns
2457
+ */
2458
+ const validateOrgConfigResults = (data) => {
2459
+ if (!isApiOrgConfigResults(data)) return;
2460
+ return {
2461
+ configs: data.configs.map((config) => validateOrganizationConfig(config)).filter((config) => config != null),
2462
+ experiments: data.experiments.map((experiment) => ({
2463
+ group: experiment.group,
2464
+ groupName: experiment.group_name,
2465
+ name: experiment.name,
2466
+ ruleId: experiment.rule_id,
2467
+ value: experiment.value
2468
+ })),
2469
+ gates: data.gates.map((gate) => ({
2470
+ groupName: gate.group_name,
2471
+ name: gate.name,
2472
+ ruleId: gate.rule_id,
2473
+ value: gate.value
2474
+ })),
2475
+ org: {
2476
+ org: {
2477
+ id: data.org.org.id,
2478
+ displayName: data.org.org.display_name,
2479
+ domain: data.org.org.domain,
2480
+ shortName: data.org.org.short_name,
2481
+ status: data.org.org.status,
2482
+ createdAt: data.org.org.created_at?.toISOString(),
2483
+ updatedAt: data.org.org.updated_at?.toISOString()
2484
+ },
2485
+ settings: {}
2486
+ }
2487
+ };
2488
+ };
2489
+
2490
+ //#endregion
2491
+ //#region src/application/models/validators/validateResponse.ts
2492
+ const richInformationFromCommerceRichInformation = (data) => ({
2493
+ cons: data.cons,
2494
+ pros: data.pros,
2495
+ reviewDate: data.review_date,
2496
+ reviewerTitle: data.reviewer_title,
2497
+ productFamiliarity: data.product_familiarity
2498
+ });
2499
+ const validateResponse = (data) => {
2500
+ if (!isApiResponse(data)) return;
2501
+ if (data.category === ResponseCategory.Text && isApiTextResponseAttributes(data.attributes)) return {
2502
+ id: data.id,
2503
+ createdAt: data.created_at,
2504
+ category: ResponseCategory.Text,
2505
+ attributes: { content: data.attributes.content }
2506
+ };
2507
+ if (data.category === ResponseCategory.Product && isApiProductResponseAttributes(data.attributes)) return {
2508
+ id: data.id,
2509
+ createdAt: data.created_at,
2510
+ category: ResponseCategory.Product,
2511
+ attributes: {
2512
+ id: data.attributes.id,
2513
+ description: data.attributes.description,
2514
+ imageUrl: data.attributes.image_url,
2515
+ imageUrls: data.attributes.image_urls,
2516
+ title: data.attributes.title,
2517
+ url: data.attributes.url,
2518
+ originalPrice: data.attributes.original_price,
2519
+ salePrice: data.attributes.sale_price,
2520
+ averageRating: data.attributes.average_rating,
2521
+ numberReviews: data.attributes.number_reviews,
2522
+ metadata: data.attributes.metadata,
2523
+ isForGrid: data.attributes.is_for_grid,
2524
+ colors: data.attributes.colors,
2525
+ sizes: data.attributes.sizes,
2526
+ filters: data.attributes.filters
2527
+ }
2528
+ };
2529
+ if (data.category === ResponseCategory.Review && isApiReviewResponseAttributes(data.attributes)) return {
2530
+ id: data.id,
2531
+ createdAt: data.created_at,
2532
+ category: ResponseCategory.Review,
2533
+ attributes: {
2534
+ id: data.attributes.id,
2535
+ productId: data.attributes.product_id,
2536
+ title: data.attributes.title,
2537
+ reviewer: data.attributes.reviewer,
2538
+ review: data.attributes.review,
2539
+ stars: data.attributes.stars,
2540
+ richInformation: data.attributes.rich_information ? richInformationFromCommerceRichInformation(data.attributes.rich_information) : void 0
2541
+ }
2542
+ };
2543
+ if (data.category === ResponseCategory.Separator) return {
2544
+ id: data.id,
2545
+ createdAt: data.created_at,
2546
+ category: ResponseCategory.Separator
2547
+ };
2548
+ if (data.category === ResponseCategory.Page && isApiPageResponseAttributes(data.attributes)) return {
2549
+ id: data.id,
2550
+ createdAt: data.created_at,
2551
+ category: ResponseCategory.Page,
2552
+ attributes: {
2553
+ id: data.attributes.id,
2554
+ title: data.attributes.title,
2555
+ description: data.attributes.description,
2556
+ url: data.attributes.url
2557
+ }
2558
+ };
2559
+ if (data.category === ResponseCategory.Form && isApiFormResponseAttributes(data.attributes)) return {
2560
+ id: data.id,
2561
+ createdAt: data.created_at,
2562
+ category: ResponseCategory.Form,
2563
+ attributes: {
2564
+ formCategory: data.attributes.form_category ? { formType: data.attributes.form_category.form_type } : void 0,
2565
+ schema: {
2566
+ properties: data.attributes.schema.properties,
2567
+ required: data.attributes.schema.required.map(String)
2568
+ }
2569
+ }
2570
+ };
2571
+ if (data.category === ResponseCategory.ProductSearch && isApiProductSearchResponseAttributes(data.attributes)) return {
2572
+ id: data.id,
2573
+ createdAt: data.created_at,
2574
+ category: ResponseCategory.ProductSearch,
2575
+ attributes: {
2576
+ generatedQuery: data.attributes.generated_query,
2577
+ productCount: data.attributes.product_count
2578
+ }
2579
+ };
2580
+ if (data.category === ResponseCategory.ProductSearchFilter && isApiProductSearchFilterResponseAttributes(data.attributes)) return {
2581
+ id: data.id,
2582
+ createdAt: data.created_at,
2583
+ category: ResponseCategory.ProductSearchFilter,
2584
+ attributes: { filterName: data.attributes.filter_name }
2585
+ };
2586
+ if (data.category === ResponseCategory.Order && isApiOrderResponseAttributes(data.attributes)) return {
2587
+ id: data.id,
2588
+ createdAt: data.created_at,
2589
+ category: ResponseCategory.Order,
2590
+ attributes: {
2591
+ orderId: data.attributes.order_id,
2592
+ orderNumber: data.attributes.order_number,
2593
+ createdAt: data.attributes.created_at,
2594
+ latestEventDate: data.attributes.latest_event_date,
2595
+ lineItems: data.attributes.line_items.map((item) => ({
2596
+ itemTitle: item.item_title,
2597
+ itemPrice: item.item_price,
2598
+ itemQuantity: item.item_quantity,
2599
+ orderItemId: item.order_item_id,
2600
+ image: item.image ?? void 0,
2601
+ inTransitAt: item.in_transit_at ?? void 0,
2602
+ deliveredAt: item.delivered_at ?? void 0,
2603
+ estimatedDeliveryAt: item.estimated_delivery_at ?? void 0,
2604
+ fulfillmentDisplayStatus: item.fulfillment_display_status ? stringToFulfillmentDisplayStatusEnumValue(item.fulfillment_display_status) : void 0,
2605
+ trackingUrl: item.tracking_url ?? void 0
2606
+ }))
2607
+ }
2608
+ };
2609
+ };
2610
+
2611
+ //#endregion
2612
+ //#region src/enabled-features.ts
2613
+ var EnabledFeatures = class {
2614
+ static {
2615
+ this.values = void 0;
2616
+ }
2617
+ static async get(orgConfig, featureFlagService) {
2618
+ if (this.values !== void 0) return this.values;
2619
+ const isSpiffyEnabled = async (orgConfig$1, featureFlagService$1) => {
2620
+ if (LocalStorageService.getSpiffyOnFeatureFlag() === "true") {
2621
+ logger_default.logDebug(`[spiffy-ai] spiffy enabled by "spiffy_on" override`);
2622
+ return true;
2623
+ }
2624
+ if (LocalStorageService.getSpiffyOnFeatureFlag() === "false") {
2625
+ logger_default.logDebug(`[spiffy-ai] envive disabled by "envive_on" override`);
2626
+ return false;
2627
+ }
2628
+ if (window._spiffy?.show != null && !window._spiffy.show) {
2629
+ logger_default.logDebug(`[spiffy-ai] spiffy disabled by window._spiffy.show`);
2630
+ return false;
2631
+ }
2632
+ if (!featureFlagService$1.isClientSessionEnabled()) {
2633
+ logger_default.logDebug(`[spiffy-ai] spiffy disabled by feature flag`);
2634
+ return false;
2635
+ }
2636
+ if (window._spiffy?.show != null && window._spiffy.show) {
2637
+ logger_default.logDebug(`[spiffy-ai] spiffy enabled by window._spiffy.show`);
2638
+ return true;
2639
+ }
2640
+ if ((await getOrgInfo(orgConfig$1.org.org.shortName)).alwaysEnabledMerchants) {
2641
+ logger_default.logDebug(`[spiffy-ai] spiffy enabled by org config and feature flag`);
2642
+ return true;
2643
+ }
2644
+ if (featureFlagService$1.isClientSessionEnabled()) {
2645
+ logger_default.logDebug(`[spiffy-ai] spiffy is enabled by feature flag`);
2646
+ return true;
2647
+ }
2648
+ logger_default.logDebug(`[spiffy-ai] spiffy is disabled because not all checks have passed`);
2649
+ return false;
2650
+ };
2651
+ const isSalesAgentEnabled = isSpiffyEnabled;
2652
+ this.values = {
2653
+ envive: await isSpiffyEnabled(orgConfig, featureFlagService),
2654
+ salesAgent: await isSalesAgentEnabled(orgConfig, featureFlagService)
2655
+ };
2656
+ return this.values;
2657
+ }
2658
+ static reset() {
2659
+ this.values = void 0;
2660
+ }
2661
+ };
2662
+
2663
+ //#endregion
2664
+ //#region src/adapters/amplitude/amplitudeAdapter.ts
2665
+ let SpiffyMetricsEventName = /* @__PURE__ */ function(SpiffyMetricsEventName$1) {
2666
+ SpiffyMetricsEventName$1["BundleLoaded"] = "Bundle Loaded";
2667
+ SpiffyMetricsEventName$1["ChatLiveAgentBtnClick"] = "Chat Live Agent Btn Click";
2668
+ SpiffyMetricsEventName$1["ChatFloatingButtonVisible"] = "Chat Floating Button Visible";
2669
+ SpiffyMetricsEventName$1["ChatComponentVisible"] = "Chat Component Visible";
2670
+ SpiffyMetricsEventName$1["ChatComponentExpanded"] = "Chat Component Expanded";
2671
+ SpiffyMetricsEventName$1["ChatComponentCollapsed"] = "Chat Component Collapsed";
2672
+ SpiffyMetricsEventName$1["ChatUserMessageInput"] = "Chat User Message Input";
2673
+ SpiffyMetricsEventName$1["ChatSuggestionClicked"] = "Chat Suggestion Clicked";
2674
+ SpiffyMetricsEventName$1["ChatAssistantResponse"] = "Chat Assistant Response";
2675
+ SpiffyMetricsEventName$1["ProductCardClicked"] = "Product Card Clicked";
2676
+ SpiffyMetricsEventName$1["ProductReviewCardClicked"] = "Product Review Card Clicked";
2677
+ SpiffyMetricsEventName$1["AddToCartClicked"] = "Add to Cart Clicked";
2678
+ SpiffyMetricsEventName$1["PromptCardClicked"] = "Prompt Card Clicked";
2679
+ SpiffyMetricsEventName$1["SupportedEvent"] = "Supported Event";
2680
+ SpiffyMetricsEventName$1["SearchBackToResponseClicked"] = "Search Back to Response Clicked";
2681
+ SpiffyMetricsEventName$1["PerformanceMetrics"] = "Performance Metrics";
2682
+ SpiffyMetricsEventName$1["SearchBarClicked"] = "Search Bar Clicked";
2683
+ SpiffyMetricsEventName$1["OrderLookupStarted"] = "Order Lookup Started";
2684
+ SpiffyMetricsEventName$1["OrderLookupFormSubmitted"] = "Order Lookup Form Submitted";
2685
+ SpiffyMetricsEventName$1["SearchComponentVisible"] = "Search Component Visible";
2686
+ SpiffyMetricsEventName$1["GlobalSearchPromptClicked"] = "Global Search Prompt Clicked";
2687
+ SpiffyMetricsEventName$1["SearchInputStarted"] = "Search Input Started";
2688
+ SpiffyMetricsEventName$1["SearchQuerySubmitted"] = "Search Query Submitted";
2689
+ SpiffyMetricsEventName$1["SearchResultsViewed"] = "Search Results Viewed";
2690
+ SpiffyMetricsEventName$1["SearchTimeToFirstClick"] = "Search Time to First Click";
2691
+ SpiffyMetricsEventName$1["SearchZeroResultsRate"] = "Search Zero Results Rate";
2692
+ SpiffyMetricsEventName$1["SearchFilterClicked"] = "Search Filter Clicked";
2693
+ SpiffyMetricsEventName$1["SearchSortClicked"] = "Search Sort Clicked";
2694
+ return SpiffyMetricsEventName$1;
2695
+ }({});
2696
+ var AmplitudeAdapter = class AmplitudeAdapter {
2697
+ constructor(userId, orgConfig, featureFlagService, orgGaConfig) {
2698
+ this.userId = userId;
2699
+ this.orgConfig = orgConfig;
2700
+ this.featureFlagService = featureFlagService;
2701
+ this.orgGaConfig = orgGaConfig;
2702
+ this.underlyingAmplitudeClient = void 0;
2703
+ this.internalEventTrackingEnrichment = void 0;
2704
+ this.eventPropsToPrefixedEventProps = (eventName, eventProps) => {
2705
+ const prefix = eventName.toLowerCase().replace(/\s+/g, "_");
2706
+ return Object.entries(eventProps).reduce((acc, [key, value]) => {
2707
+ acc[`${prefix}.${key}`] = value;
2708
+ return acc;
2709
+ }, {});
2710
+ };
2711
+ this.supplementalDefaultProps = {};
2712
+ }
2713
+ init() {
2714
+ this.underlyingAmplitudeClient = this.createUnderlyingClient();
2715
+ }
2716
+ getUnderlyingAmplitudeClient() {
2717
+ return this.underlyingAmplitudeClient;
2718
+ }
2719
+ getSupplementalDefaultProps() {
2720
+ return this.supplementalDefaultProps;
2721
+ }
2722
+ setSupplementalDefaultProps(supplementalDefaultProps) {
2723
+ this.supplementalDefaultProps = supplementalDefaultProps;
2724
+ }
2725
+ getEventTrackingEnrichment() {
2726
+ if (this.internalEventTrackingEnrichment !== void 0) return this.internalEventTrackingEnrichment;
2727
+ this.internalEventTrackingEnrichment = {
2728
+ name: "page-view-tracking-enrichment",
2729
+ type: "enrichment",
2730
+ setup: async () => void 0,
2731
+ execute: async (event) => {
2732
+ let enrichedEvent;
2733
+ if (["[Amplitude] Page Viewed", `[Spiffy] ${SpiffyMetricsEventName.BundleLoaded}`].includes(event.event_type)) {
2734
+ const windowProps = window._spiffy ? { ...window._spiffy } : {};
2735
+ if (windowProps.publicKey) delete windowProps.publicKey;
2736
+ const globalProperties = Object.entries(windowProps).reduce((acc, [key, value]) => ({
2737
+ ...acc,
2738
+ [`globalProperties.${key}`]: `${value}`
2739
+ }), {});
2740
+ const enabledFeatures = await EnabledFeatures.get(this.orgConfig, this.featureFlagService);
2741
+ const enabledFeaturesProperties = Object.entries(enabledFeatures).reduce((acc, [key, value]) => ({
2742
+ ...acc,
2743
+ [`enabledFeatures.${key}`]: `${value}`
2744
+ }), {});
2745
+ const timingProperties = { "timing.enriched_at_ms": window.performance?.now() };
2746
+ enrichedEvent = {
2747
+ ...event,
2748
+ event_properties: {
2749
+ ...event.event_properties,
2750
+ ...this.getDefaultTrackingProps(),
2751
+ ...globalProperties,
2752
+ ...enabledFeaturesProperties,
2753
+ ...timingProperties
2754
+ }
2755
+ };
2756
+ } else enrichedEvent = event;
2757
+ EventsDispatcher.dispatch(SpiffyEvent.AMPLITUDE_EVENT, enrichedEvent);
2758
+ return enrichedEvent;
2759
+ }
2760
+ };
2761
+ return this.internalEventTrackingEnrichment;
2762
+ }
2763
+ amplitudeSessionReplayInit() {
2764
+ const isEnabled = this.orgConfig.org.org.shortName === OrgShortName.UniqueVintage && this.featureFlagService.isClientSessionEnabled() && this.featureFlagService.isFeatureGateEnabled(FeatureGates.IsNewFeatureEnabled);
2765
+ const sampleRate = 1;
2766
+ try {
2767
+ logger_default.logDebug(`[spiffy-ai] amplitude session-replay initializing isEnabled=${isEnabled} sampleRate=${sampleRate}`);
2768
+ if (!isEnabled) return isEnabled;
2769
+ return isEnabled;
2770
+ } catch (e) {
2771
+ logger_default.logError("[spiffy-ai] Error initializing amplitude session-replay", e);
2772
+ return false;
2773
+ }
2774
+ }
2775
+ createUnderlyingClient() {
2776
+ const { amplitudeApiKey, dataResidency } = useEnviveConfig();
2777
+ const currentAmplitudeInstance = createInstance();
2778
+ const isSessionsEnabled = this.amplitudeSessionReplayInit();
2779
+ currentAmplitudeInstance.add(this.getEventTrackingEnrichment());
2780
+ currentAmplitudeInstance.init(amplitudeApiKey, this.userId, {
2781
+ serverZone: dataResidency,
2782
+ trackingOptions: { ipAddress: true },
2783
+ autocapture: {
2784
+ attribution: true,
2785
+ pageViews: { trackHistoryChanges: "pathOnly" },
2786
+ sessions: isSessionsEnabled,
2787
+ formInteractions: false,
2788
+ fileDownloads: false
2789
+ }
2790
+ });
2791
+ return currentAmplitudeInstance;
2792
+ }
2793
+ getDefaultTrackingProps() {
2794
+ const { env } = useEnviveConfig();
2795
+ const gatesProps = this.orgConfig.gates ? this.orgConfig.gates.reduce((acc, curr) => {
2796
+ if (curr.name && curr.value != null) return {
2797
+ ...acc,
2798
+ [`feature_gate.${curr.name}`]: curr.value
2799
+ };
2800
+ return acc;
2801
+ }, {}) : {};
2802
+ const experimentProps = this.orgConfig.experiments ? this.orgConfig.experiments.reduce((acc, curr) => {
2803
+ if (curr.name && curr.value != null) return {
2804
+ ...acc,
2805
+ [`product_experiment.${curr.name}`]: curr.value
2806
+ };
2807
+ return acc;
2808
+ }, {}) : {};
2809
+ return {
2810
+ ...gatesProps,
2811
+ ...experimentProps,
2812
+ ...this.supplementalDefaultProps,
2813
+ org_id: this.orgConfig.org?.org.id,
2814
+ app_id: "commerce-chat-react-component",
2815
+ chat_id: LocalStorageService.getItem(LocalStorageKeys.ChatId),
2816
+ env: env || "unknown",
2817
+ app_source: EnvironmentService.getContextSource(),
2818
+ "org.short_name": this.orgConfig.org?.org.shortName,
2819
+ "user.id": this.userId,
2820
+ "cdp.user_id": null,
2821
+ "cdp.provider": null,
2822
+ "event.source": "web-browser",
2823
+ "event.type": "user-activity",
2824
+ "event.id": null,
2825
+ "event.channel": "web",
2826
+ "event.timestamp": null
2827
+ };
2828
+ }
2829
+ static {
2830
+ this.trackEvent = async ({ eventName, eventProps, eventGroups, alsoSendToGoogleAnalytics = false }) => {
2831
+ try {
2832
+ const decoratedEventName = `[Spiffy] ${eventName}`;
2833
+ const amplitudeInstance = AmplitudeAdapter.getSingletonInstanceOf();
2834
+ const amplitudeClient = amplitudeInstance.getUnderlyingAmplitudeClient();
2835
+ if (!amplitudeClient) {
2836
+ logger_default.logWarn("amplitude instance undefined", void 0, { event_name: decoratedEventName });
2837
+ return;
2838
+ }
2839
+ const eventData = JSON.stringify({
2840
+ eventName,
2841
+ eventProps,
2842
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
2843
+ });
2844
+ const data = new TextEncoder().encode(eventData);
2845
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
2846
+ const currentInsertId = Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
2847
+ logger_default.logDebug(`amplitude tracking ${decoratedEventName}`, null, {
2848
+ event_name: decoratedEventName,
2849
+ props: eventProps
2850
+ });
2851
+ amplitudeClient.track(decoratedEventName, {
2852
+ ...amplitudeInstance.getDefaultTrackingProps(),
2853
+ ...eventProps,
2854
+ ...eventProps ? AmplitudeAdapter.getSingletonInstanceOf().eventPropsToPrefixedEventProps(eventName, eventProps) : {}
2855
+ }, {
2856
+ ...eventGroups,
2857
+ insert_id: currentInsertId
2858
+ });
2859
+ if (alsoSendToGoogleAnalytics && amplitudeInstance.orgGaConfig) {
2860
+ const dataLayer = WindowDataLayerService.getSingletonInstanceOf(amplitudeInstance.orgGaConfig);
2861
+ logger_default.logDebug("[spiffy-ai] GA tracking", decoratedEventName);
2862
+ dataLayer.sendToGoogleAnalyticsCircularEventsSafe(decoratedEventName, eventProps);
2863
+ }
2864
+ } catch (err) {
2865
+ logger_default.logError("[spiffy-ai] Error tracking event", err, {
2866
+ eventName,
2867
+ eventProps
2868
+ });
2869
+ }
2870
+ };
2871
+ }
2872
+ static amplitudeSafeString(input) {
2873
+ if (!input) return null;
2874
+ if (input.length > 1024) return input.slice(0, 1024);
2875
+ return input;
2876
+ }
2877
+ static getSingletonInstanceOf() {
2878
+ if (EnvironmentService.getContextSource() === ContextSourceEnum.Test) return new StubAmplitudeAdapter();
2879
+ const identifyingPrefix = EnvironmentService.getIdentifyingPrefix();
2880
+ if (!window[identifyingPrefix]) window[identifyingPrefix] = {};
2881
+ if (!window[identifyingPrefix]._amplitudeAdapter) {
2882
+ const atomStore = getAtomStore();
2883
+ const userId = atomStore.get(userIdAtom);
2884
+ const orgConfig = atomStore.get(orgConfigAtom);
2885
+ const orgGaConfig = atomStore.get(orgAnalyticsGoogleAnalyticsConfigAtom);
2886
+ const featureFlagService = atomStore.get(featureFlagServiceAtom);
2887
+ window[identifyingPrefix]._amplitudeAdapter = new AmplitudeAdapter(userId, orgConfig, featureFlagService, orgGaConfig);
2888
+ window[identifyingPrefix]._amplitudeAdapter?.init();
2889
+ }
2890
+ return window[identifyingPrefix]._amplitudeAdapter;
2891
+ }
2892
+ };
2893
+
2894
+ //#endregion
2895
+ //#region src/adapters/amplitude/stubAmplitudeAdapter.ts
2896
+ var StubAmplitudeAdapter = class extends AmplitudeAdapter {
2897
+ constructor() {
2898
+ super("test", {}, {});
2899
+ this.init = () => {};
2900
+ this.getUnderlyingAmplitudeClient = () => void 0;
2901
+ this.getSupplementalDefaultProps = () => ({});
2902
+ this.setSupplementalDefaultProps = () => {};
2903
+ this.getEventTrackingEnrichment = () => ({
2904
+ name: "stub-enrichment",
2905
+ type: "enrichment",
2906
+ setup: async () => void 0,
2907
+ execute: async (event) => event
2908
+ });
2909
+ this.amplitudeSessionReplayInit = () => false;
2910
+ this.createUnderlyingClient = () => ({});
2911
+ this.getDefaultTrackingProps = () => ({});
2912
+ this.trackEvent = () => Promise.resolve();
2913
+ }
2914
+ };
2915
+
2916
+ //#endregion
2917
+ //#region src/application/utils/analyticsUtils.ts
2918
+ const NORMALIZED_ADD_TO_CART_EVENT_NAMES = ["addtocart", "addedtocart"];
2919
+ const CHECK_DATA_LAYER_INTERVAL_MS = 500;
2920
+ const CHECK_DATA_LAYER_MAX_ATTEMPTS = 10;
2921
+ /**
2922
+ * Checks if a Google Analytics event is an add_to_cart event.
2923
+ *
2924
+ * @param event The event name to check.
2925
+ *
2926
+ * @returns True if the event is an add_to_cart event, false otherwise.
2927
+ */
2928
+ const isAddToCartEvent = (event) => {
2929
+ const normalizedEvent = event.replace(/[-_]/g, "").toLowerCase();
2930
+ return NORMALIZED_ADD_TO_CART_EVENT_NAMES.some((name) => normalizedEvent.includes(name));
2931
+ };
2932
+ /**
2933
+ * Tracks an add_to_cart event in Amplitude.
2934
+ *
2935
+ * @param event The event to track.
2936
+ */
2937
+ const handleAddToCartEvent = (event) => {
2938
+ let eventProps;
2939
+ if (isLegacyUAEcommerceEvent(event)) eventProps = {
2940
+ items: event.ecommerce.add.products.map((product) => ({
2941
+ item_name: product.name,
2942
+ item_category: product.category,
2943
+ price: product.price,
2944
+ quantity: product.quantity
2945
+ })),
2946
+ currency: event.ecommerce.add.currencyCode,
2947
+ event_format_version: "legacy_universal_analytics"
2948
+ };
2949
+ else if (isGA4EcommerceEvent(event)) eventProps = {
2950
+ items: event.ecommerce.items.map((item) => ({
2951
+ item_name: item.item_name,
2952
+ item_category: item.item_category,
2953
+ price: item.price,
2954
+ quantity: item.quantity
2955
+ })),
2956
+ currency: event.ecommerce.currency,
2957
+ event_format_version: "google_analytics_4"
2958
+ };
2959
+ else eventProps = {
2960
+ event_properties: { ...event },
2961
+ event_format_version: "unknown"
2962
+ };
2963
+ AmplitudeAdapter.trackEvent({
2964
+ eventName: SpiffyMetricsEventName.AddToCartClicked,
2965
+ eventProps
2966
+ });
2967
+ };
2968
+ /**
2969
+ * Wraps the window.dataLayer.push method to intercept add_to_cart events and send them to Amplitude.
2970
+ * This function runs on an interval until the dataLayer is available.
2971
+ */
2972
+ const initDataLayerWrapper = () => {
2973
+ let attempts = 0;
2974
+ const checkAndInitialize = () => {
2975
+ if (!window.dataLayer || !window.dataLayer.push) {
2976
+ attempts += 1;
2977
+ if (attempts >= CHECK_DATA_LAYER_MAX_ATTEMPTS) {
2978
+ logger_default.logDebug(`[spiffy-ai] dataLayer not available after ${CHECK_DATA_LAYER_MAX_ATTEMPTS} attempts`);
2979
+ return;
2980
+ }
2981
+ setTimeout(checkAndInitialize, CHECK_DATA_LAYER_INTERVAL_MS);
2982
+ return;
2983
+ }
2984
+ logger_default.logDebug("[spiffy-ai] dataLayer is available, wrapping push function...");
2985
+ const originalPush = window.dataLayer.push;
2986
+ window.dataLayer.push = (args) => {
2987
+ if (isBaseEcommerceEvent(args) && isAddToCartEvent(args.event)) handleAddToCartEvent(args);
2988
+ originalPush.apply(window.dataLayer, [args]);
2989
+ };
2990
+ };
2991
+ checkAndInitialize();
2992
+ };
2993
+ const initAmplitude = () => {
2994
+ AmplitudeAdapter.getSingletonInstanceOf();
2995
+ };
2996
+
2997
+ //#endregion
2998
+ //#region src/application/utils/coreContextToApiContext.ts
2999
+ const coreContextToApiContext = (context) => ({
3000
+ chat_id: context.chatId,
3001
+ org_id: context.orgId,
3002
+ user_id: context.userId,
3003
+ org_short_name: context.orgShortName,
3004
+ source: context.source,
3005
+ env: context.env
3006
+ });
3007
+
3008
+ //#endregion
3009
+ //#region src/application/utils/coreUserEventToApiUserEvent.ts
3010
+ const coreUserEventToApiUserEvent = (data) => {
3011
+ if (data.category === UserEventCategory.PdpVisit || data.category === UserEventCategory.AddToCart) return {
3012
+ event_id: data.eventId,
3013
+ created_at: data.createdAt,
3014
+ category: data.category,
3015
+ attributes: {
3016
+ product_id: data.attributes.productId,
3017
+ parent_product_id: data.attributes.parentProductId,
3018
+ url: data.attributes.url
3019
+ }
3020
+ };
3021
+ if (data.category === UserEventCategory.PlpVisit) return {
3022
+ event_id: data.eventId,
3023
+ created_at: data.createdAt,
3024
+ category: data.category,
3025
+ attributes: {
3026
+ category: PLPAttributeCategory.Id,
3027
+ attributes: { id: data.attributes.attributes.id }
3028
+ }
3029
+ };
3030
+ if (data.category === UserEventCategory.QueryTyped) return {
3031
+ event_id: data.eventId,
3032
+ created_at: data.createdAt,
3033
+ category: data.category,
3034
+ attributes: { query: data.attributes.query }
3035
+ };
3036
+ if (data.category === UserEventCategory.Search) return {
3037
+ event_id: data.eventId,
3038
+ created_at: data.createdAt,
3039
+ category: data.category,
3040
+ attributes: {
3041
+ search_term: data.attributes.searchTerm,
3042
+ selected_filters: data.attributes.selectedFilters
3043
+ }
3044
+ };
3045
+ if (data.category === UserEventCategory.SuggestionClicked) return {
3046
+ event_id: data.eventId,
3047
+ created_at: data.createdAt,
3048
+ category: data.category,
3049
+ attributes: { suggestion_id: data.attributes.suggestionId }
3050
+ };
3051
+ if (data.category === UserEventCategory.PageVisit) return {
3052
+ event_id: data.eventId,
3053
+ created_at: data.createdAt,
3054
+ category: data.category,
3055
+ attributes: {
3056
+ url: data.attributes.url,
3057
+ page_visit_category: data.attributes.pageVisitCategory
3058
+ }
3059
+ };
3060
+ if (data.category === UserEventCategory.FormSubmitted) return {
3061
+ event_id: data.eventId,
3062
+ created_at: data.createdAt,
3063
+ category: data.category,
3064
+ attributes: {
3065
+ filled_schema: { ...data.attributes.filledSchema },
3066
+ form_response_id: data.attributes.formResponseId,
3067
+ form_type: data.attributes.formType
3068
+ }
3069
+ };
3070
+ return {
3071
+ event_id: data.eventId,
3072
+ created_at: data.createdAt,
3073
+ category: data.category
3074
+ };
3075
+ };
3076
+
3077
+ //#endregion
3078
+ //#region src/application/utils/divideArray.ts
3079
+ const divideArray = (array, size) => {
3080
+ const rows = [];
3081
+ for (let i = 0; i < size; i += 1) rows.push(array.filter((_, index) => index % size === i));
3082
+ return rows;
3083
+ };
3084
+
3085
+ //#endregion
3086
+ //#region src/application/utils/mutationHelper.ts
3087
+ const compareTokens = (original, comparison) => {
3088
+ const originalTokens = new Set(original.split(" "));
3089
+ const comparisonTokens = new Set(comparison.split(" "));
3090
+ return [...originalTokens].filter((token) => !comparisonTokens.has(token));
3091
+ };
3092
+ var MutationHelper = class {
3093
+ static fireClassChange(record, node, fn) {
3094
+ if (node && record.oldValue !== node?.classList.value) fn(node?.classList);
3095
+ }
3096
+ static fireClassAdded(record, node, classMap) {
3097
+ if (node && record.oldValue) compareTokens(node?.classList.value, record.oldValue).forEach((className) => classMap.get(className)?.());
3098
+ }
3099
+ static fireClassRemoved(record, node, classMap) {
3100
+ if (node && record.oldValue) compareTokens(record.oldValue, node?.classList.value).forEach((className) => classMap.get(className)?.());
3101
+ }
3102
+ static fireSubtreeChange(nodes, fn) {
3103
+ nodes.length && fn?.(nodes);
3104
+ }
3105
+ static isClass(mutation) {
3106
+ return mutation.type === "attributes" && mutation.attributeName === "class";
3107
+ }
3108
+ static isChildList(mutation) {
3109
+ return mutation.type === "childList";
3110
+ }
3111
+ };
3112
+
3113
+ //#endregion
3114
+ //#region src/application/utils/elementObserver.ts
3115
+ /**
3116
+ * The `ElementObserver` class monitors all changes related to the specific element it is responsible for.
3117
+ * It is automatically instantiated by the `useElementObserver` hook, which manages all instances of this class.
3118
+ *
3119
+ * How it works:
3120
+ *
3121
+ * Each instance of `ElementObserver` holds several pieces of information related to the node it is monitoring,
3122
+ * such as the node's selector and its `MutationObserver`. This class is responsible for translating raw node
3123
+ * changes into a more user-friendly format. For example, when the node is added to the DOM, the `ElementObserver`
3124
+ * is notified by the `DOMObserver`, which triggers the `onAdd` callback function on the respective `useElementObserver`
3125
+ * instance.
3126
+ *
3127
+ * Instances of `ElementObserver` are fully managed by the `useElementObserver` hook, requiring no additional configuration.
3128
+ * When the hook is destroyed, its corresponding `ElementObserver` instance is automatically removed.
3129
+ *
3130
+ */
3131
+ var ElementObserver = class {
3132
+ constructor(selector) {
3133
+ this.selector = selector;
3134
+ this.mutation = null;
3135
+ this.node = null;
3136
+ this.eventListeners = /* @__PURE__ */ new Map();
3137
+ this.classAdded = /* @__PURE__ */ new Map();
3138
+ this.classRemoved = /* @__PURE__ */ new Map();
3139
+ this.nodeDisplay = "block";
3140
+ this.addFn = () => {};
3141
+ this.removeFn = () => {};
3142
+ this.changeFn = () => {};
3143
+ this.classChangeFn = () => {};
3144
+ this.addChildFn = void 0;
3145
+ this.removeChildFn = void 0;
3146
+ this.resetFn = () => {};
3147
+ }
3148
+ handleAttributes(mutationRecord) {
3149
+ mutationRecord.filter(MutationHelper.isClass).forEach((mutation) => {
3150
+ MutationHelper.fireClassChange(mutation, this.node, this.classChangeFn);
3151
+ MutationHelper.fireClassAdded(mutation, this.node, this.classAdded);
3152
+ MutationHelper.fireClassRemoved(mutation, this.node, this.classRemoved);
3153
+ });
3154
+ }
3155
+ handleChildList(mutationRecord) {
3156
+ if (!this.addChildFn && !this.removeChildFn) return;
3157
+ mutationRecord.filter(MutationHelper.isChildList).forEach((mutation) => {
3158
+ MutationHelper.fireSubtreeChange(mutation.addedNodes, this.addChildFn);
3159
+ MutationHelper.fireSubtreeChange(mutation.removedNodes, this.removeChildFn);
3160
+ });
3161
+ }
3162
+ addInitialListeners() {
3163
+ this.eventListeners.forEach((v, k) => this.node?.addEventListener(k, v));
3164
+ }
3165
+ clearEventListeners() {
3166
+ this.eventListeners.forEach((v, k) => this.node?.removeEventListener(k, v));
3167
+ this.eventListeners.clear();
3168
+ }
3169
+ renew(newNode) {
3170
+ if (newNode) {
3171
+ this.destroy();
3172
+ this.watch(newNode);
3173
+ }
3174
+ }
3175
+ getSelector() {
3176
+ return this.selector;
3177
+ }
3178
+ getNode() {
3179
+ return this.node;
3180
+ }
3181
+ synchronize() {
3182
+ const parsedNode = this.getSelector().parse();
3183
+ if (this.getNode() !== parsedNode) {
3184
+ this.renew(parsedNode);
3185
+ return;
3186
+ }
3187
+ if (!this.getNode() && parsedNode) {
3188
+ this.watch(parsedNode);
3189
+ return;
3190
+ }
3191
+ if (this.getNode() && !parsedNode) this.destroy();
3192
+ }
3193
+ init() {
3194
+ const node = this.getSelector().parse();
3195
+ if (node) this.watch(node);
3196
+ }
3197
+ watch(node) {
3198
+ if (!this.mutation) {
3199
+ this.mutation = new MutationObserver((mutationRecord) => {
3200
+ this.handleAttributes(mutationRecord);
3201
+ this.handleChildList(mutationRecord);
3202
+ this.changeFn(this.node);
3203
+ });
3204
+ this.mutation.observe(node, {
3205
+ childList: true,
3206
+ subtree: true,
3207
+ attributes: true,
3208
+ attributeOldValue: true
3209
+ });
3210
+ this.node = node;
3211
+ this.addFn(this.node);
3212
+ this.addInitialListeners();
3213
+ }
3214
+ }
3215
+ destroy() {
3216
+ this.resetFn();
3217
+ this.removeFn(this.node);
3218
+ this.mutation?.disconnect();
3219
+ this.clearEventListeners();
3220
+ this.classAdded.clear();
3221
+ this.classRemoved.clear();
3222
+ this.mutation = null;
3223
+ this.node = null;
3224
+ }
3225
+ render(fn) {
3226
+ if (this.node) return createPortal(fn(), this.node);
3227
+ }
3228
+ fire(event) {
3229
+ if (this.node) this.node.dispatchEvent(new MouseEvent(event, {
3230
+ bubbles: true,
3231
+ cancelable: true,
3232
+ view: window
3233
+ }));
3234
+ }
3235
+ show() {
3236
+ const display = this.node?.style.display;
3237
+ if (this.node && display === "none") this.node.style.display = this.nodeDisplay || "block";
3238
+ }
3239
+ hide() {
3240
+ const display = this.node?.style.display;
3241
+ if (this.node && display !== "none") {
3242
+ this.nodeDisplay = display || "block";
3243
+ this.node.style.display = "none";
3244
+ }
3245
+ }
3246
+ registerEvent(event, fn) {
3247
+ if (this.node) {
3248
+ const previousFn = this.eventListeners.get(event);
3249
+ if (previousFn) this.node.removeEventListener(event, previousFn);
3250
+ this.node.addEventListener(event, fn);
3251
+ }
3252
+ this.eventListeners.set(event, fn);
3253
+ }
3254
+ registerOnReset(fn) {
3255
+ this.resetFn = fn;
3256
+ }
3257
+ registerOnChange(fn) {
3258
+ this.changeFn = fn;
3259
+ }
3260
+ registerOnAdd(fn) {
3261
+ this.addFn = fn;
3262
+ }
3263
+ registerOnRemove(fn) {
3264
+ this.removeFn = fn;
3265
+ }
3266
+ registerOnclassChange(fn) {
3267
+ this.classChangeFn = fn;
3268
+ }
3269
+ registerOnAddChild(fn) {
3270
+ this.addChildFn = fn;
3271
+ }
3272
+ registerOnRemoveChild(fn) {
3273
+ this.removeChildFn = fn;
3274
+ }
3275
+ registerOnClassAdded(className, fn) {
3276
+ this.classAdded.set(className, fn);
3277
+ }
3278
+ registerOnClassRemoved(className, fn) {
3279
+ this.classRemoved.set(className, fn);
3280
+ }
3281
+ };
3282
+
3283
+ //#endregion
3284
+ //#region src/application/utils/domObserver.ts
3285
+ /**
3286
+ * This class manages a `MutationObserver` for the `document.body`. It monitors nodes that are
3287
+ * added or removed from the DOM and notifies the observers for each observable element
3288
+ * when they are ready to be watched.
3289
+ *
3290
+ * How that works:
3291
+ *
3292
+ * When the `observe` function is called, it attaches a `MutationObserver` to the `document.body` element.
3293
+ * All changes to `document.body` are tracked by this observer. When changes are detected, the `MutationObserver`
3294
+ * iterates through all added and removed nodes and checks if each node exists in the main map of observable elements.
3295
+ *
3296
+ * If a match is found, it notifies the corresponding `ElementObserver` instance to start monitoring changes for that element.
3297
+ *
3298
+ * The primary `MutationObserver` remains active until the `destroy` function is called. Calling `destroy` will disconnect all
3299
+ * individual element observers and release any associated resources.
3300
+ *
3301
+ * There is no need to explicitly call the `observe` function. It is automatically invoked when a `useElementObserver` hook is instantiated.
3302
+ *
3303
+ */
3304
+ var DOMObserver = class {
3305
+ static {
3306
+ this.listeners = /* @__PURE__ */ new Map();
3307
+ }
3308
+ static notifyAdition(records, nodeMapping) {
3309
+ records.forEach((record) => record.addedNodes.forEach((node) => {
3310
+ nodeMapping.get(node)?.watch(node);
3311
+ nodeMapping.delete(node);
3312
+ }));
3313
+ }
3314
+ static notifyRemoval(records, nodeMapping) {
3315
+ records.forEach((record) => record.removedNodes.forEach((node) => {
3316
+ nodeMapping.get(node)?.destroy();
3317
+ nodeMapping.delete(node);
3318
+ }));
3319
+ }
3320
+ static notifyChildrenChanges(nodeMapping) {
3321
+ Array.from(nodeMapping.values()).forEach((observer) => observer.synchronize());
3322
+ }
3323
+ static mapNodeInstancesToListeners() {
3324
+ const nodeMapping = /* @__PURE__ */ new Map();
3325
+ this.listeners.forEach((observer) => {
3326
+ const node = observer.getNode() || observer.getSelector()?.parse();
3327
+ if (node) nodeMapping.set(node, observer);
3328
+ });
3329
+ return nodeMapping;
3330
+ }
3331
+ static add(selector) {
3332
+ const node = selector.getPattern();
3333
+ let elementObserver = this.listeners.get(node);
3334
+ if (elementObserver) return elementObserver;
3335
+ elementObserver = new ElementObserver(selector);
3336
+ this.listeners.set(node, elementObserver);
3337
+ return elementObserver;
3338
+ }
3339
+ static remove(selector) {
3340
+ const node = selector.getPattern();
3341
+ this.listeners.get(node)?.destroy();
3342
+ this.listeners.delete(node);
3343
+ }
3344
+ static observe() {
3345
+ if (!this.documentObserver) {
3346
+ this.documentObserver = new MutationObserver((mutations) => {
3347
+ const nodeMapping = this.mapNodeInstancesToListeners();
3348
+ this.notifyAdition(mutations, nodeMapping);
3349
+ this.notifyRemoval(mutations, nodeMapping);
3350
+ this.notifyChildrenChanges(nodeMapping);
3351
+ });
3352
+ this.documentObserver.observe(document.body, {
3353
+ childList: true,
3354
+ subtree: true
3355
+ });
3356
+ }
3357
+ }
3358
+ static destroy() {
3359
+ this.documentObserver?.disconnect();
3360
+ this.listeners.forEach((listener) => listener.destroy());
3361
+ this.listeners.clear();
3362
+ this.documentObserver = null;
3363
+ }
3364
+ };
3365
+
3366
+ //#endregion
3367
+ //#region src/application/utils/imageFilter.ts
3368
+ const getRecentProductImageUrls = (lastMessages, currentProductId) => {
3369
+ const productMessages = lastMessages.filter((message) => message.type === MessageType.Product && message.metadata?.imageUrl).map((m) => m);
3370
+ return [...productMessages.filter((m) => m.metadata?.id === currentProductId), ...productMessages.filter((m) => m.metadata?.id !== currentProductId)].map((m) => m.metadata.imageUrl);
3371
+ };
3372
+
3373
+ //#endregion
3374
+ //#region src/application/utils/merchantUtils.ts
3375
+ const prepareMerchantPage = () => {
3376
+ let metaViewport = document.querySelector("meta[name='viewport']");
3377
+ if (metaViewport) {
3378
+ const content = metaViewport.getAttribute("content");
3379
+ if (!content?.includes("maximum-scale=1")) metaViewport.setAttribute("content", `${content}, maximum-scale=1`);
3380
+ return;
3381
+ }
3382
+ metaViewport = document.createElement("meta");
3383
+ metaViewport.setAttribute("name", "viewport");
3384
+ metaViewport.setAttribute("content", "width=device-width, initial-scale=1, maximum-scale=1");
3385
+ document.head.appendChild(metaViewport);
3386
+ };
3387
+
3388
+ //#endregion
3389
+ //#region src/application/utils/messageFromFormSubmittedEvent.ts
3390
+ const messageFromFormSubmittedEvent = (event, formResponseAttributes) => {
3391
+ if (event.category !== UserEventCategory.FormSubmitted) return;
3392
+ const formStringContents = Object.entries(formResponseAttributes.schema.properties).map(([key, value]) => `${value.title}: ${event.attributes.filledSchema[key]}`).join("\n");
3393
+ return {
3394
+ id: event.eventId,
3395
+ role: MessageRole.User,
3396
+ type: MessageType.QueryTyped,
3397
+ createdAt: event.createdAt,
3398
+ metadata: { content: formStringContents }
3399
+ };
3400
+ };
3401
+
3402
+ //#endregion
3403
+ //#region src/application/utils/messageFromQueryEvent.ts
3404
+ /**
3405
+ * Transforms a query UserEvent object into a Message object for presentation.
3406
+ *
3407
+ * @param event The user event object received from the server
3408
+ *
3409
+ * @returns A Message if the event is a query event, otherwise undefined
3410
+ */
3411
+ const messageFromQueryEvent = (event) => {
3412
+ if (event.category === UserEventCategory.QueryTyped) return {
3413
+ id: event.eventId,
3414
+ role: MessageRole.User,
3415
+ type: MessageType.QueryTyped,
3416
+ createdAt: event.createdAt,
3417
+ metadata: { content: event.attributes.query }
3418
+ };
3419
+ if (event.category === UserEventCategory.Search) return {
3420
+ id: event.eventId,
3421
+ role: MessageRole.User,
3422
+ type: MessageType.Search,
3423
+ createdAt: event.createdAt,
3424
+ metadata: {
3425
+ searchTerm: event.attributes.searchTerm || "",
3426
+ selectedFilters: event.attributes.selectedFilters || []
3427
+ }
3428
+ };
3429
+ };
3430
+
3431
+ //#endregion
3432
+ //#region src/application/utils/messageFromResponse.ts
3433
+ /**
3434
+ * Transforms a server Response object into a Message object for presentation.
3435
+ *
3436
+ * @param response The response object received from the server containing model generated content
3437
+ *
3438
+ * @returns A Message if the response contains known attributes, undefined otherwise
3439
+ */
3440
+ const messageFromResponse = (response) => {
3441
+ if (response == null) return;
3442
+ if (response.category === ResponseCategory.Text) return {
3443
+ id: response.id,
3444
+ createdAt: response.createdAt,
3445
+ type: MessageType.Text,
3446
+ role: MessageRole.Assistant,
3447
+ metadata: { content: response.attributes.content }
3448
+ };
3449
+ if (response.category === ResponseCategory.Product) return {
3450
+ id: response.id,
3451
+ createdAt: response.createdAt,
3452
+ role: MessageRole.Assistant,
3453
+ type: MessageType.Product,
3454
+ metadata: { ...response.attributes }
3455
+ };
3456
+ if (response.category === ResponseCategory.Review) return {
3457
+ id: response.id,
3458
+ createdAt: response.createdAt,
3459
+ type: MessageType.Review,
3460
+ role: MessageRole.Assistant,
3461
+ metadata: {
3462
+ review: response.attributes.review,
3463
+ reviewer: response.attributes.reviewer,
3464
+ stars: response.attributes.stars,
3465
+ title: response.attributes.title,
3466
+ richInformation: response.attributes.richInformation
3467
+ }
3468
+ };
3469
+ if (response.category === ResponseCategory.Separator) return {
3470
+ id: response.id,
3471
+ createdAt: response.createdAt,
3472
+ type: MessageType.Separator,
3473
+ role: MessageRole.Assistant
3474
+ };
3475
+ if (response.category === ResponseCategory.Page) return {
3476
+ id: response.id,
3477
+ createdAt: response.createdAt,
3478
+ role: MessageRole.Assistant,
3479
+ type: MessageType.Page,
3480
+ metadata: { ...response.attributes }
3481
+ };
3482
+ if (response.category === ResponseCategory.ProductSearch) return {
3483
+ id: response.id,
3484
+ createdAt: response.createdAt,
3485
+ role: MessageRole.Assistant,
3486
+ type: MessageType.ProductSearch,
3487
+ metadata: { ...response.attributes }
3488
+ };
3489
+ if (response.category === ResponseCategory.ProductSearchFilter) return {
3490
+ id: response.id,
3491
+ createdAt: response.createdAt,
3492
+ role: MessageRole.Assistant,
3493
+ type: MessageType.ProductSearchFilter,
3494
+ metadata: { ...response.attributes }
3495
+ };
3496
+ if (response.category === ResponseCategory.Form) return {
3497
+ id: response.id,
3498
+ createdAt: response.createdAt,
3499
+ role: MessageRole.Assistant,
3500
+ type: MessageType.Form,
3501
+ metadata: {
3502
+ formType: response.attributes.formCategory?.formType,
3503
+ fields: Object.entries(response.attributes.schema.properties).map(([key, value]) => ({
3504
+ key,
3505
+ title: value.title,
3506
+ type: value.type,
3507
+ format: value.format,
3508
+ required: response.attributes.schema.required.includes(key)
3509
+ }))
3510
+ }
3511
+ };
3512
+ if (response.category === ResponseCategory.Order) return {
3513
+ id: response.id,
3514
+ createdAt: response.createdAt,
3515
+ role: MessageRole.Assistant,
3516
+ type: MessageType.Order,
3517
+ metadata: { ...response.attributes }
3518
+ };
3519
+ };
3520
+
3521
+ //#endregion
3522
+ //#region src/application/utils/messageFromSuggestionEvent.ts
3523
+ /**
3524
+ * Transforms a UserEvent object into a Message object for presentation.
3525
+ *
3526
+ * @param event The UserEvent object received from the server
3527
+ * @param suggestions A list of generated suggestions to match the event to
3528
+ *
3529
+ * @returns A Message if the event is a suggestion click event, undefined otherwise
3530
+ */
3531
+ const messageFromSuggestionEvent = (event, suggestions) => {
3532
+ if (event.category === UserEventCategory.SuggestionClicked) {
3533
+ const { suggestionId } = event.attributes;
3534
+ return {
3535
+ id: event.eventId,
3536
+ role: MessageRole.User,
3537
+ type: MessageType.SuggestionClicked,
3538
+ createdAt: event.createdAt,
3539
+ metadata: {
3540
+ suggestionId,
3541
+ suggestionContent: suggestions.find((s) => s.id === suggestionId)?.content ?? ""
3542
+ }
3543
+ };
3544
+ }
3545
+ };
3546
+
3547
+ //#endregion
3548
+ //#region src/application/utils/nextMessageRequestToApiRequest.ts
3549
+ const messageRequestToCommerceMessageRequest = (data) => ({
3550
+ context: {
3551
+ chat_id: data.context.chatId,
3552
+ org_id: data.context.orgId,
3553
+ org_short_name: data.context.orgShortName,
3554
+ user_id: data.context.userId,
3555
+ source: data.context.source,
3556
+ env: data.context.env
3557
+ },
3558
+ id: data.id,
3559
+ feature_flags: data.featureFlags,
3560
+ user_events: data.userEvents?.map((userEvent) => coreUserEventToApiUserEvent(userEvent)),
3561
+ generation_params: {
3562
+ model: data.generationParams?.model,
3563
+ max_tokens: data.generationParams?.maxTokens,
3564
+ stop: data.generationParams?.stop,
3565
+ stream: data.generationParams?.stream,
3566
+ temperature: data.generationParams?.temperature,
3567
+ top_p: data.generationParams?.topP,
3568
+ num_suggestions: data.generationParams?.numSuggestions,
3569
+ response_system_prompt: data.generationParams?.responseSystemPrompt,
3570
+ suggestion_system_prompt: data.generationParams?.suggestionSystemPrompt,
3571
+ response_caching: data.generationParams?.responseCaching
3572
+ }
3573
+ });
3574
+
3575
+ //#endregion
3576
+ //#region src/application/utils/nodeSelector.ts
3577
+ var NodeSelector = class {
3578
+ constructor(pattern) {
3579
+ this.pattern = pattern;
3580
+ this.root = document;
3581
+ }
3582
+ getPattern() {
3583
+ return this.pattern;
3584
+ }
3585
+ setRoot(root) {
3586
+ this.root = root;
3587
+ }
3588
+ getRoot() {
3589
+ return this.root;
3590
+ }
3591
+ };
3592
+ var QuerySelector = class extends NodeSelector {
3593
+ parse() {
3594
+ return this.getRoot().querySelector(this.getPattern());
3595
+ }
3596
+ };
3597
+ var IDSelector = class extends NodeSelector {
3598
+ parse() {
3599
+ return this.getRoot().getElementById(this.getPattern());
3600
+ }
3601
+ };
3602
+ var XpathSelector = class extends NodeSelector {
3603
+ parse() {
3604
+ return this.getRoot()?.evaluate(this.getPattern(), this.getRoot(), null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)?.singleNodeValue;
3605
+ }
3606
+ };
3607
+ var ChainSelector = class extends NodeSelector {
3608
+ parse() {
3609
+ let selectorIndex = 0;
3610
+ const selectors = this.getPattern().split("@");
3611
+ const lastIndex = selectors.length - 1;
3612
+ const parseChain = (pattern, prevNode) => {
3613
+ const selector = SelectorFactory.parse(pattern);
3614
+ if (prevNode) selector.setRoot(prevNode);
3615
+ const currentNode = selector.parse();
3616
+ if (selectorIndex === lastIndex) return currentNode;
3617
+ let node = currentNode || document;
3618
+ if (currentNode?.shadowRoot) node = currentNode.shadowRoot;
3619
+ if (currentNode?.contentWindow) node = currentNode.contentWindow?.document;
3620
+ return parseChain(selectors[++selectorIndex].trim(), node);
3621
+ };
3622
+ return parseChain(selectors[selectorIndex].trim());
3623
+ }
3624
+ };
3625
+ var Empty = class extends NodeSelector {
3626
+ constructor() {
3627
+ super("");
3628
+ }
3629
+ parse() {
3630
+ return null;
3631
+ }
3632
+ };
3633
+ var SelectorFactory = class {
3634
+ static parse(composedSelector) {
3635
+ if (!composedSelector) return new Empty();
3636
+ const split = composedSelector.split("|");
3637
+ const type = split[0];
3638
+ const selector = split[1];
3639
+ switch (type) {
3640
+ case "id": return this.id(selector);
3641
+ case "query": return this.query(selector);
3642
+ case "xpath": return this.xpath(selector);
3643
+ default: return new Empty();
3644
+ }
3645
+ }
3646
+ static check(selector) {
3647
+ return selector ?? new Empty();
3648
+ }
3649
+ static chain(pattern) {
3650
+ return pattern ? new ChainSelector(pattern) : new Empty();
3651
+ }
3652
+ static id(pattern) {
3653
+ return pattern ? new IDSelector(pattern) : new Empty();
3654
+ }
3655
+ static query(pattern) {
3656
+ return pattern ? new QuerySelector(pattern) : new Empty();
3657
+ }
3658
+ static xpath(pattern) {
3659
+ return pattern ? new XpathSelector(pattern) : new Empty();
3660
+ }
3661
+ };
3662
+
3663
+ //#endregion
3664
+ //#region src/application/utils/overrides.ts
3665
+ function isPlainObject(x) {
3666
+ return !!x && typeof x === "object" && !Array.isArray(x) && !(x instanceof Date) && !(x instanceof RegExp);
3667
+ }
3668
+ function isReplace(x) {
3669
+ return !!x && typeof x === "object" && "$replace" in x;
3670
+ }
3671
+ function isDelete(x) {
3672
+ return !!x && typeof x === "object" && x.$delete === true;
3673
+ }
3674
+ function isPrimitiveValue(x) {
3675
+ const t = typeof x;
3676
+ return x === null || t === "string" || t === "number" || t === "boolean" || t === "bigint" || t === "symbol" || t === "undefined";
3677
+ }
3678
+ function isArrayOfPrimitives(arr) {
3679
+ if (arr.length === 0) return false;
3680
+ for (let i = 0; i < arr.length; i += 1) {
3681
+ const v = arr[i];
3682
+ if (v !== void 0 && !isPrimitiveValue(v)) return false;
3683
+ }
3684
+ return true;
3685
+ }
3686
+ function mergeAny(baseAny, patchAny, opts) {
3687
+ if (isReplace(patchAny)) return patchAny.$replace;
3688
+ if (isDelete(patchAny)) return void 0;
3689
+ if (Array.isArray(baseAny)) {
3690
+ if (Array.isArray(patchAny)) {
3691
+ const baseArr = baseAny;
3692
+ const patchArr = patchAny;
3693
+ if (opts.arrayStrategy === "replace" || isArrayOfPrimitives(baseArr) || isArrayOfPrimitives(patchArr)) return patchAny;
3694
+ const out = baseArr.slice();
3695
+ const max = Math.max(out.length, patchArr.length);
3696
+ for (let i = 0; i < max; i += 1) {
3697
+ const pVal = patchArr[i];
3698
+ if (pVal !== void 0) out[i] = mergeAny(out[i], pVal, opts);
3699
+ }
3700
+ return out;
3701
+ }
3702
+ return baseAny;
3703
+ }
3704
+ if (isPlainObject(baseAny) && isPlainObject(patchAny)) {
3705
+ const baseObj = baseAny;
3706
+ const patchObj = patchAny;
3707
+ const out = { ...baseObj };
3708
+ for (const key of Object.keys(patchObj)) {
3709
+ const pVal = patchObj[key];
3710
+ if (pVal === void 0) {} else if (opts.nullDeletes && pVal === null) delete out[key];
3711
+ else if (isReplace(pVal)) out[key] = pVal.$replace;
3712
+ else if (isDelete(pVal)) delete out[key];
3713
+ else out[key] = mergeAny(baseObj?.[key], pVal, opts);
3714
+ }
3715
+ return out;
3716
+ }
3717
+ return patchAny ?? baseAny;
3718
+ }
3719
+ function applyOverrides(base, patch, opts = {}) {
3720
+ const { arrayStrategy = "mergeByIndex", nullDeletes = false } = opts;
3721
+ if (isReplace(patch)) return patch.$replace;
3722
+ if (isDelete(patch)) return void 0;
3723
+ if (Array.isArray(base)) {
3724
+ if (isReplace(patch)) return patch.$replace;
3725
+ if (Array.isArray(patch)) {
3726
+ if (arrayStrategy === "replace") return patch;
3727
+ const out = base.slice();
3728
+ const max = Math.max(out.length, patch.length);
3729
+ for (let i = 0; i < max; i += 1) {
3730
+ const pVal = patch[i];
3731
+ if (pVal !== void 0) out[i] = mergeAny(out[i], pVal, opts);
3732
+ }
3733
+ return out;
3734
+ }
3735
+ return base;
3736
+ }
3737
+ if (isPlainObject(base) && isPlainObject(patch)) {
3738
+ const out = { ...base };
3739
+ const patchObj = patch;
3740
+ for (const key of Object.keys(patchObj)) {
3741
+ const pVal = patchObj[key];
3742
+ if (pVal === void 0) {} else if (nullDeletes && pVal === null) delete out[key];
3743
+ else if (isReplace(pVal)) out[key] = pVal.$replace;
3744
+ else if (isDelete(pVal)) delete out[key];
3745
+ else {
3746
+ const bVal = base[key];
3747
+ out[key] = mergeAny(bVal, pVal, opts);
3748
+ }
3749
+ }
3750
+ return out;
3751
+ }
3752
+ return patch ?? base;
3753
+ }
3754
+
3755
+ //#endregion
3756
+ //#region src/application/utils/stringUtils.ts
3757
+ var StringUtils = class StringUtils {
3758
+ static isNullOrEmpty(value) {
3759
+ const valueTrimmed = value?.trim();
3760
+ return value === void 0 || valueTrimmed === "";
3761
+ }
3762
+ static trimToNull(value) {
3763
+ const valueTrimmed = value?.trim();
3764
+ return StringUtils.isNullOrEmpty(valueTrimmed) ? void 0 : valueTrimmed;
3765
+ }
3766
+ static capitalize(type) {
3767
+ if (type === void 0) return "";
3768
+ return type.charAt(0).toUpperCase() + type.substring(1);
3769
+ }
3770
+ /**
3771
+ * Finds the first pattern in an array that matches a given URL.
3772
+ * Patterns can include a single wildcard '*' which matches any sequence of characters.
3773
+ *
3774
+ * @param patterns
3775
+ * @param urlToTest
3776
+ * @returns
3777
+ */
3778
+ static findMatchingPattern(patterns, urlToTest) {
3779
+ if (!urlToTest) return;
3780
+ for (const pattern of patterns) if (urlToTest.pathname !== "/") {
3781
+ const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
3782
+ if ((/* @__PURE__ */ new RegExp(`^${regexPattern}$`)).test(urlToTest.pathname)) return pattern;
3783
+ } else if (pattern.startsWith(urlToTest.hostname)) return pattern;
3784
+ }
3785
+ };
3786
+
3787
+ //#endregion
3788
+ //#region src/application/utils/supportedEventRequestToApiRequest.ts
3789
+ const coreSupportedEventRequestToApiRequest = (coreSupportedEventRequest) => ({
3790
+ id: coreSupportedEventRequest.id,
3791
+ user_event: coreUserEventToApiUserEvent(coreSupportedEventRequest.userEvent),
3792
+ context: coreContextToApiContext(coreSupportedEventRequest.context)
3793
+ });
3794
+
3795
+ //#endregion
3796
+ //#region src/application/utils/validation.ts
3797
+ const validateEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
3798
+
3799
+ //#endregion
3800
+ //#region src/adapters/spiffy/commerce/exceptions/sessionExceptions.ts
3801
+ var SessionRestartRequired = class extends Error {
3802
+ constructor() {
3803
+ super("Session restart required");
3804
+ this.name = "SessionRestartRequired";
3805
+ }
3806
+ };
3807
+
3808
+ //#endregion
3809
+ //#region src/adapters/spiffy/commerce/exceptions/unsupportedProductExceptions.ts
3810
+ var UnsupportedProductException = class extends Error {
3811
+ constructor() {
3812
+ super("Unsupported product");
3813
+ this.name = "UnsupportedProduct";
3814
+ }
3815
+ };
3816
+
3817
+ //#endregion
3818
+ //#region src/adapters/spiffy/commerce/api.ts
3819
+ async function errorResponseBody(error) {
3820
+ try {
3821
+ return await error.response.json();
3822
+ } catch {
3823
+ return {};
3824
+ }
3825
+ }
3826
+ async function throwSessionRestartRequiredIf(errorMsg, error) {
3827
+ if (!(error instanceof ResponseError)) {
3828
+ logger_default.logInfo(errorMsg, error);
3829
+ throw error;
3830
+ }
3831
+ const errorResponse = await errorResponseBody(error);
3832
+ if (errorResponse?.message?.toLowerCase() === "unsupported product" || errorResponse?.app_code?.toUpperCase() === "PRODUCT_NOT_FOUND") throw new UnsupportedProductException();
3833
+ else if (errorResponse?.app_code?.toUpperCase() === "RESTART_SESSION" || errorResponse?.sub_code?.toUpperCase() === "NOT_FOUND") {
3834
+ logger_default.logInfo("Session does not exist. Re-start session", error, error.response, errorResponse);
3835
+ throw new SessionRestartRequired();
3836
+ }
3837
+ logger_default.logInfo(errorMsg, error);
3838
+ throw error;
3839
+ }
3840
+ var CommerceApiClient = class CommerceApiClient {
3841
+ static {
3842
+ this.getInstance = () => {
3843
+ if (!CommerceApiClient.instance) {
3844
+ const apiKey = getAtomStore().get(apiKeyAtom);
3845
+ CommerceApiClient.instance = new CommerceApiClient(apiKey);
3846
+ }
3847
+ return CommerceApiClient.instance;
3848
+ };
3849
+ }
3850
+ constructor(apiKey, basePath) {
3851
+ this.suggestionsAbortController = new AbortController();
3852
+ this.responsesAbortController = new AbortController();
3853
+ const { baseUrl } = useEnviveConfig();
3854
+ const config = new Configuration({
3855
+ accessToken: apiKey,
3856
+ basePath: basePath || baseUrl,
3857
+ headers: {
3858
+ "Content-Type": "application/json",
3859
+ Accept: "application/json"
3860
+ }
3861
+ });
3862
+ this.defaultApi = new DefaultApi(config);
3863
+ this.inferenceApi = new InferenceApi(config);
3864
+ this.customerServiceApi = new CustomerServiceApi(config);
3865
+ }
3866
+ static {
3867
+ this.resolveUrl = async (url) => {
3868
+ const atomStore = getAtomStore();
3869
+ const appDetails = atomStore.get(appDetailsAtom);
3870
+ const featureFlagService = atomStore.get(featureFlagServiceAtom);
3871
+ const context = {
3872
+ user_id: appDetails.userId,
3873
+ org_id: appDetails.orgId,
3874
+ org_short_name: appDetails.orgShortName,
3875
+ chat_id: appDetails.chatId,
3876
+ source: appDetails.source,
3877
+ env: appDetails.env
3878
+ };
3879
+ const featureGates = featureFlagService.getFeatureFlags();
3880
+ const urlResolvingRequest = {
3881
+ url,
3882
+ context,
3883
+ feature_gates: featureGates
3884
+ };
3885
+ return await (await CommerceApiClient.getInstance().inferenceApi.v1UrlResolvingPostRaw({ UrlResolvingRequest: urlResolvingRequest })).raw.json();
3886
+ };
3887
+ }
3888
+ static {
3889
+ this.reportSession = async (reportRequest) => {
3890
+ await CommerceApiClient.getInstance().defaultApi.v1ChatsReportSessionIdPost({ ReportSessionRequest: reportRequest });
3891
+ };
3892
+ }
3893
+ static {
3894
+ this.getNextResponses = async (payload) => {
3895
+ try {
3896
+ return (await CommerceApiClient.getInstance().inferenceApi.v1NextResponsesPost({ NextMessageRequest: messageRequestToCommerceMessageRequest(payload) })).map((resp) => validateResponse(resp)).map((resp) => messageFromResponse(resp)).filter((m) => m != null);
3897
+ } catch (err) {
3898
+ logger_default.logInfo("Failed to get next responses", err, {
3899
+ payloadContext: payload?.context,
3900
+ userEvents: payload?.userEvents
3901
+ });
3902
+ await throwSessionRestartRequiredIf("Failed to get next responses", err);
3903
+ return [];
3904
+ }
3905
+ };
3906
+ }
3907
+ static {
3908
+ this.getNextResponseStreaming = (payload) => {
3909
+ async function* generate(inferenceApi, abortController) {
3910
+ try {
3911
+ const response = await inferenceApi.v1NextResponsesPostRaw({ NextMessageRequest: messageRequestToCommerceMessageRequest(payload) }, { signal: abortController.signal });
3912
+ if (!response.raw.body) {
3913
+ logger_default.logError("[spiffy-ai] No body in the streamed response", void 0, { response: response.raw });
3914
+ return;
3915
+ }
3916
+ const reader = response.raw.body.getReader();
3917
+ const decoder = new TextDecoder("utf-8");
3918
+ let partial = "";
3919
+ const safeParse = (line) => {
3920
+ try {
3921
+ return JSON.parse(line);
3922
+ } catch (err) {
3923
+ logger_default.logError("[spiffy-ai] Error parsing streamed line", err, {
3924
+ line,
3925
+ partial
3926
+ });
3927
+ partial = line;
3928
+ return partial;
3929
+ }
3930
+ };
3931
+ const processChunk = (chunk) => {
3932
+ return `${partial}${chunk}`.split("\n").map((line) => line.replace(/^data: /, "").trim()).filter((line) => line !== "" && line !== "[DONE]").map(safeParse).filter((v) => v);
3933
+ };
3934
+ while (true) {
3935
+ const { done, value } = await reader.read();
3936
+ if (done) break;
3937
+ const chunk = decoder.decode(value);
3938
+ const parsedLines = processChunk(chunk);
3939
+ for (const parsedLine of parsedLines) {
3940
+ const validatedResponse = validateResponse(parsedLine);
3941
+ if (validatedResponse) yield validatedResponse;
3942
+ }
3943
+ }
3944
+ } catch (error) {
3945
+ logger_default.logError("[spiffy-ai] Failed to get next streaming responses", error, {
3946
+ payloadContext: payload?.context,
3947
+ userEvents: payload?.userEvents
3948
+ });
3949
+ await throwSessionRestartRequiredIf("Failed to get next streaming responses", error);
3950
+ }
3951
+ }
3952
+ CommerceApiClient.getInstance().responsesAbortController.abort();
3953
+ CommerceApiClient.getInstance().responsesAbortController = new AbortController();
3954
+ return generate(CommerceApiClient.getInstance().inferenceApi, CommerceApiClient.getInstance().responsesAbortController);
3955
+ };
3956
+ }
3957
+ static {
3958
+ this.getNextSuggestions = async (payload) => {
3959
+ try {
3960
+ CommerceApiClient.getInstance().suggestionsAbortController.abort();
3961
+ CommerceApiClient.getInstance().suggestionsAbortController = new AbortController();
3962
+ return (await CommerceApiClient.getInstance().inferenceApi.v1NextSuggestionsPost({ NextMessageRequest: messageRequestToCommerceMessageRequest(payload) }, { signal: CommerceApiClient.getInstance().suggestionsAbortController.signal })).map((resp) => validateSuggestion(resp)).filter((suggestion) => suggestion != null);
3963
+ } catch (error) {
3964
+ logger_default.logInfo("Failed to get suggestions", error, {
3965
+ payloadContext: payload?.context,
3966
+ userEvents: payload?.userEvents
3967
+ });
3968
+ await throwSessionRestartRequiredIf("Failed to get suggestions", error);
3969
+ return [];
3970
+ }
3971
+ };
3972
+ }
3973
+ static {
3974
+ this.getResponses = async (orgId, chatId, userId) => {
3975
+ let data = {
3976
+ responses: [],
3977
+ suggestions: [],
3978
+ user_events: []
3979
+ };
3980
+ const request = {
3981
+ org_id: orgId,
3982
+ chat_id: chatId,
3983
+ user_id: userId
3984
+ };
3985
+ try {
3986
+ data = await CommerceApiClient.getInstance().defaultApi.v1GetSessionMessages(request);
3987
+ } catch (error) {
3988
+ await throwSessionRestartRequiredIf("Failed to get chat responses", error);
3989
+ }
3990
+ const responses = data?.responses?.map((turn) => turn.map((response) => validateResponse(response)).filter((response) => response != null));
3991
+ const suggestions = data?.suggestions.map((suggestion) => validateSuggestion(suggestion)).filter((suggestion) => suggestion != null);
3992
+ const userEvents = data?.user_events.map((event) => validateUserEvent(event)).filter((event) => event != null);
3993
+ const formSubmittedUserEventsFormIds = userEvents.filter((event) => event.category === UserEventCategory.FormSubmitted).map((event) => event.attributes.formResponseId);
3994
+ const assistantMessages = responses.map((turn) => turn.filter((response) => !(response.category === ResponseCategory.Form && formSubmittedUserEventsFormIds.includes(response.id))).map((response) => messageFromResponse(response)).filter((message) => message != null)).filter((turn) => turn.length > 0);
3995
+ const userMessages = userEvents.map((event) => {
3996
+ if ([UserEventCategory.QueryTyped, UserEventCategory.Search].includes(event.category)) return [messageFromQueryEvent(event)];
3997
+ if (event.category === UserEventCategory.SuggestionClicked) return [messageFromSuggestionEvent(event, suggestions)];
3998
+ if (event.category === UserEventCategory.FormSubmitted) {
3999
+ const formResponse = responses.flat().find((response) => response.id === event.attributes.formResponseId && event.attributes.formType !== FormType.Escalation);
4000
+ if (formResponse && formResponse.category === ResponseCategory.Form) return [messageFromFormSubmittedEvent(event, formResponse.attributes)];
4001
+ }
4002
+ return [];
4003
+ }).filter((message) => message.length > 0);
4004
+ const sortedMessages = [...assistantMessages, ...userMessages].sort((a, b) => new Date(a[0].createdAt).getTime() - new Date(b[0].createdAt).getTime());
4005
+ return {
4006
+ responses,
4007
+ userEvents,
4008
+ suggestions,
4009
+ messages: sortedMessages
4010
+ };
4011
+ };
4012
+ }
4013
+ static {
4014
+ this.isSupportedEvent = async (payload) => {
4015
+ try {
4016
+ const httpResponseText = await (await CommerceApiClient.getInstance().inferenceApi.v1SupportedEventPostRaw({ SupportedEventRequest: coreSupportedEventRequestToApiRequest(payload) })).raw.text();
4017
+ const httpResponseJson = JSON.parse(httpResponseText);
4018
+ return {
4019
+ ...httpResponseJson,
4020
+ numberOfReviews: httpResponseJson.num_of_reviews,
4021
+ merchant_tags: httpResponseJson.merchant_tags || []
4022
+ };
4023
+ } catch (err) {
4024
+ logger_default.logError("Failed to get response for v1SupportedEventPost", { err });
4025
+ return {
4026
+ supported: false,
4027
+ ready: false,
4028
+ category: void 0,
4029
+ collections: [],
4030
+ numberOfReviews: void 0,
4031
+ top_category: void 0,
4032
+ merchant_tags: []
4033
+ };
4034
+ }
4035
+ };
4036
+ }
4037
+ static {
4038
+ this.identifyUser = async (spiffyUserId, merchantUserId, uaDetails) => {
4039
+ try {
4040
+ await CommerceApiClient.getInstance().defaultApi.v1AnalyticsIdentifyPost({ AnalyticsIdentifyRequest: {
4041
+ user_id: spiffyUserId,
4042
+ os_name: uaDetails.os,
4043
+ os_version: uaDetails.osVersion,
4044
+ platform: uaDetails.os,
4045
+ device_id: uaDetails.deviceModel,
4046
+ device_brand: uaDetails.deviceBrand,
4047
+ device_manufacturer: uaDetails.deviceManufacturer,
4048
+ device_model: uaDetails.deviceModel,
4049
+ user_properties: {
4050
+ cdp_user_id: merchantUserId,
4051
+ browser: uaDetails.browser,
4052
+ browser_version: uaDetails.browserVersion,
4053
+ user_agent: uaDetails.userAgent
4054
+ }
4055
+ } });
4056
+ } catch (err) {
4057
+ logger_default.logError("Failed to identify user", err);
4058
+ }
4059
+ };
4060
+ }
4061
+ static {
4062
+ this.mapContextSourceToV1OrgConfigGetSource = (source) => {
4063
+ if (source === void 0) return void 0;
4064
+ switch (source) {
4065
+ case ContextSourceEnum.Fork: return V1OrgConfigGetSourceEnum.Fork;
4066
+ case ContextSourceEnum.Playground: return V1OrgConfigGetSourceEnum.Playground;
4067
+ case ContextSourceEnum.App: return V1OrgConfigGetSourceEnum.App;
4068
+ case ContextSourceEnum.Test: return V1OrgConfigGetSourceEnum.Test;
4069
+ default: return source;
4070
+ }
4071
+ };
4072
+ }
4073
+ static {
4074
+ this.getOrgConfig = async (user_id) => {
4075
+ try {
4076
+ const { reactAppName } = useEnviveConfig();
4077
+ const request = {
4078
+ namespace: reactAppName,
4079
+ user_id,
4080
+ source: this.mapContextSourceToV1OrgConfigGetSource(EnvironmentService.getContextSource()),
4081
+ include_experiments: Object.values(ProductExperiment),
4082
+ include_feature_gates: Object.values(FeatureGates)
4083
+ };
4084
+ const response = await CommerceApiClient.getInstance().defaultApi.v1OrgConfigGet(request);
4085
+ return validateOrgConfigResults(response);
4086
+ } catch (err) {
4087
+ logger_default.logError(`Failed to get org config`, err, { err });
4088
+ return;
4089
+ }
4090
+ };
4091
+ }
4092
+ static {
4093
+ this.addNoteToLatestConversation = async (spiffyUserId, email, customerServiceProvider) => {
4094
+ logger_default.logInfo(`addNoteToLatestConversation - user_id=${spiffyUserId} email=${email} customer_service_provider=${customerServiceProvider}`);
4095
+ try {
4096
+ await CommerceApiClient.getInstance().customerServiceApi.v1CustserviceAddNoteToLatestConversationPost({ AddNoteToLatestConversationRequest: {
4097
+ spiffy_user_id: spiffyUserId,
4098
+ email,
4099
+ customer_service_provider: customerServiceProvider
4100
+ } });
4101
+ } catch (err) {
4102
+ logger_default.logError("Failed to add note to latest conversation", { err });
4103
+ }
4104
+ };
4105
+ }
4106
+ static {
4107
+ this.getCustomerServiceApi = () => CommerceApiClient.getInstance().customerServiceApi;
4108
+ }
4109
+ };
4110
+ var api_default = CommerceApiClient;
4111
+
4112
+ //#endregion
4113
+ export { APP_INITIAL_START_TIME_KEY, AmplitudeAdapter, ChatElementDisplayLocation, DOMInsertionService, DOMInsertionType, DOMInsertionTypeToInsertPosition, DOMObserver, DomMutationObserverContinuation, DomObservationStrategy, ElementObserver, EnvironmentService, FeatureFlagService, FeatureGates, GoogleAnalyticsEvents, GridInsertionService, GridInsertionType, LocalStorageKeys, LocalStorageService, MessageRole, MessageType, MutationHelper, NodeSelector, PAGE_LOAD_OFFSET_TIME_KEY, PerfMetricsEvents, ProductExperiment, SelectorFactory, SessionRestartRequired, SessionStorageService, SpiffyEventName, SpiffyMetricsEventName, SpiffyWidgets, StringUtils, StubAmplitudeAdapter, UnsupportedProductException, UserIdentityService, WindowDataLayerService, addWidget, apiKeyAtom, api_default, appDetailsAtom, appInitialStartTimeMsAtom, appSourceAtom, applyOverrides, askQuestionBtnClickedAtom, buildSearchHash, buildSearchStartHash, chatAtom, chatIdAtom, chatIsOpenAtom, chatOnToggleAtom, clearUserEventAtom, colorsConfigAtom, coreContextToApiContext, coreSupportedEventRequestToApiRequest, coreUserEventToApiUserEvent, createResponsePayload, createUrlWithQueryParams, divideArray, endpointURLAtom, envAtom, featureFlagServiceAtom, formSubmitAtom, frontendConfigAtom, getApiKeyEnvVar, getAsyncOrgConfig, getMerchantColorsQuery, getMerchantFrontendConfigQuery, getMerchantOrgIdQuery, getOrgUIConfig, getQueryParam, getRecentProductImageUrls, handleFormSubmittedAtom, handleReplyAtom, handleSuggestionAtom, hasParsedVariantInfoAtom, hasReportedPerformanceMetricsAtom, initAmplitude, initDataLayerWrapper, isApiFormResponseAttributes, isApiFormSubmittedResponseAttributes, isApiOrderResponseAttributes, isApiOrgConfigResults, isApiOrganizationConfig, isApiPLPEventAttributes, isApiPLPIdAttribute, isApiPageResponseAttributes, isApiProductSearchFilterResponseAttributes, isBaseEcommerceEvent, isGA4EcommerceEvent, isGraphQLColorsConfig, isLegacyUAEcommerceEvent, isMobilePLPChatPlacementParameter, isSpanxTakeAQuizCtaParameter, isVariantInfo, lastAssistantMessageAtom, logPerfMetricAtom, messageFromFormSubmittedEvent, messageFromQueryEvent, messageFromResponse, messageFromSuggestionEvent, messageRequestToCommerceMessageRequest, messagesAtom, orgAnalyticsAmplitudeConfigAtom, orgAnalyticsConfigAtom, orgAnalyticsCustomerServiceConfigAtom, orgAnalyticsGoogleAnalyticsConfigAtom, orgConfigAtom, orgCustomerServiceConfig, orgCustomerServiceService, orgDomainAtom, orgIdAtom, orgShortNameAtom, orgUIConfigAtom, pageLoadOffsetTimeAtom, parseHref, parseSearchHash, performanceMetricsAtom, prepareMerchantPage, processUserEventAtom, queueUserEventAtom, replyEventCategoryAtom, requestFailureAtom, resetPerformanceMetricsAtom, resetStoredOrgConfigAtom, responseStreamingAtom, sourceAtom, storedOrgConfigAtom, stringToFulfillmentDisplayStatusEnumValue, suggestionAtom, suggestionsAtom, suggestionsLoadingAtom, supportedEventAtom, transformCamelToSnake, transformSnakeToCamel, urlResolverAtom, userEventQueueAtom, userEventsAtom, userHasRepliedAtom, userIdAtom, userQueryAtom, userQueueEventCountAtom, validateAndTransformMountingConfig, validateAndTransformPageVariants, validateAndTransformWidgetConfig, validateEmail, validateGraphQLColorsConfig, validateGraphQLFrontendConfig, validateGraphQLOrgId, validateMobilePLPChatPlacementParameter, validateOrgConfigResults, validateOrganizationConfig, validateResponse, validateSuggestion, validateUserEvent, variantInfoAtom, widgetArrayAtom };