@envive-ai/react-hooks 0.1.1 → 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 (301) 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-DpF-HUG_.js → bandolier-C7PAIw02.js} +17 -7
  74. package/dist/{bandolier-3rHPPhkF.cjs → bandolier-oMkFDJMF.cjs} +56 -46
  75. package/dist/{carpe-BG7Q_KCG.cjs → carpe-C0ccKuR9.cjs} +35 -25
  76. package/dist/{carpe-DLuc07V7.js → carpe-DFc78_lJ.js} +17 -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 +15 -4
  102. package/dist/contexts/index.d.cts +9 -1
  103. package/dist/contexts/index.d.ts +12 -4
  104. package/dist/contexts/index.js +15 -4
  105. package/dist/{contexts-Dq7tO_0y.js → contexts-DO75-Kmx.js} +19 -4326
  106. package/dist/{contexts-C4Iz162H.cjs → contexts-iAzSvZjb.cjs} +188 -4488
  107. package/dist/{coterie-FybYN_xE.js → coterie-BGT8hqFR.js} +18 -7
  108. package/dist/{coterie-DUdvJvAs.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-CKyjzyLc.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-CL94oJfj.js → default-wf_IORgo.js} +1 -1
  117. package/dist/divIds-BWvq-i6I.js +22 -0
  118. package/dist/{divIds-BOqjn3bE.cjs → divIds-CFyAjjp3.cjs} +6 -79
  119. package/dist/{dreamlandBaby-C8yzW4Nl.cjs → dreamlandBaby-BzuMvUFS.cjs} +28 -18
  120. package/dist/{dreamlandBaby-WXcbsTXO.js → dreamlandBaby-DZvM81LQ.js} +17 -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-CZYzZPl3.cjs → fiveCbd-DE-tDY3d.cjs} +32 -22
  134. package/dist/{fiveCbd-kl6CoxoF.js → fiveCbd-HNBPqPtX.js} +17 -7
  135. package/dist/{forLoveAndLemons-BD2qh-6B.js → forLoveAndLemons-BKmJJ9pq.js} +13 -5
  136. package/dist/{forLoveAndLemons-BNu-PfFB.cjs → forLoveAndLemons-BeVEBOiu.cjs} +17 -9
  137. package/dist/{types-DGoFEos_.d.cts → frontendConfig-KeNqU1wa.d.cts} +39 -275
  138. package/dist/{types-D4vlfTd0.d.ts → frontendConfig-cPvCTWm6.d.ts} +39 -275
  139. package/dist/globalSearch-BC0rOX3E.js +13 -0
  140. package/dist/globalSearch-hxbXekus.cjs +38 -0
  141. package/dist/{greenpan-LDDXZTsh.js → greenpan-BX1viAZB.js} +17 -7
  142. package/dist/{greenpan-D6fDmjU8.cjs → greenpan-chd3aa5I.cjs} +30 -20
  143. package/dist/{grooveLife-D-1qfxwj.js → grooveLife-CHot3rZw.js} +18 -8
  144. package/dist/{grooveLife-CcylXabB.cjs → grooveLife-DEob7rK0.cjs} +29 -19
  145. package/dist/{homegrownCannabis-BEZzwFlm.cjs → homegrownCannabis-CoIjcehi.cjs} +27 -16
  146. package/dist/{homegrownCannabis-BScZhy9v.js → homegrownCannabis-CwkS1qDA.js} +17 -6
  147. package/dist/hooks/index.cjs +15 -4
  148. package/dist/hooks/index.d.cts +15 -305
  149. package/dist/hooks/index.d.ts +15 -306
  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/index-C4zjAR1c.d.cts +227 -0
  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/index-tfRj22E1.d.ts +227 -0
  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-cJJVulZ9.js → jackArcher-BA-pkB4A.js} +17 -7
  176. package/dist/{jackArcher-BwMClqMP.cjs → jackArcher-bewC0q1T.cjs} +34 -24
  177. package/dist/{jordanCraig-DGsCO2o1.cjs → jordanCraig-B5k9nlAw.cjs} +77 -67
  178. package/dist/{jordanCraig-DNDMT0hn.js → jordanCraig-BsQ1mYbt.js} +17 -7
  179. package/dist/{kindredBravely-ROyesnVk.js → kindredBravely-BxYkCpGY.js} +16 -6
  180. package/dist/{kindredBravely-wV2XT1r_.cjs → kindredBravely-DsN0fo3s.cjs} +27 -17
  181. package/dist/{kutFromTheKloth-B6GR8tO9.cjs → kutFromTheKloth-BQTCu3ct.cjs} +28 -18
  182. package/dist/{kutFromTheKloth-BCUOHegv.js → kutFromTheKloth-bukOQM3P.js} +17 -7
  183. package/dist/{larryAndSerges-CqS02fnX.js → larryAndSerges-D1ecaT5a.js} +14 -5
  184. package/dist/{larryAndSerges-CIqB9tKz.cjs → larryAndSerges-bj7fgy9b.cjs} +21 -12
  185. package/dist/{leapsAndRebounds-CFj9F_z1.cjs → leapsAndRebounds-BfneG_0c.cjs} +30 -20
  186. package/dist/{leapsAndRebounds-j4YqSvNb.js → leapsAndRebounds-DhNpZETg.js} +17 -7
  187. package/dist/locators-C2DX_nX6.js +1 -0
  188. package/dist/locators-CUpyd9Wt.cjs +0 -0
  189. package/dist/logger-Dln20ans.cjs +25 -0
  190. package/dist/logger-pdEEY8T2.js +19 -0
  191. package/dist/{longevityrx-9sUQZCVZ.js → longevityrx-CnoGcw0w.js} +17 -7
  192. package/dist/{longevityrx-C-Yc5LPR.cjs → longevityrx-D0goIuX0.cjs} +25 -15
  193. package/dist/{lookOptic-dbaaorhR.cjs → lookOptic-C4afLPZP.cjs} +25 -15
  194. package/dist/{lookOptic-CQryypdM.js → lookOptic-uJWIKpER.js} +17 -7
  195. package/dist/{mantraBrand-D5MTZ6Mj.cjs → mantraBrand-8JUlYtCE.cjs} +46 -36
  196. package/dist/{mantraBrand-CifBQtHp.js → mantraBrand-DuwKHM26.js} +18 -8
  197. package/dist/{medterra-DhENCf-m.js → medterra-BQec8rzn.js} +17 -7
  198. package/dist/{medterra-BCrXdmFE.cjs → medterra-DH067P-V.cjs} +37 -27
  199. package/dist/{modells-aQrV10D7.js → modells-DAgLE2xo.js} +17 -7
  200. package/dist/{modells-C_P_894S.cjs → modells-DUFnLmAz.cjs} +31 -21
  201. package/dist/nodeSelector-DpKXszfU.d.ts +30 -0
  202. package/dist/nodeSelector-vKB44CDB.d.cts +30 -0
  203. package/dist/org-C11APG3v.js +63 -0
  204. package/dist/org-CnHL2I9B.cjs +106 -0
  205. package/dist/{pressedFloral-DErfwwl0.cjs → pressedFloral-DVZVfOSQ.cjs} +36 -26
  206. package/dist/{pressedFloral-D-amnTQK.js → pressedFloral-MdbuoRyA.js} +17 -7
  207. package/dist/search-CvHb1M3S.js +542 -0
  208. package/dist/search-bSYdOBhY.cjs +743 -0
  209. package/dist/search-filter-types-BsJjrxk0.d.ts +101 -0
  210. package/dist/search-filter-types-CqaGK3nM.d.cts +101 -0
  211. package/dist/{skinPerfection-DF6nQXjh.cjs → skinPerfection-BcEWICQN.cjs} +25 -15
  212. package/dist/{skinPerfection-DRVPJp3h.js → skinPerfection-bGiYxq1i.js} +17 -7
  213. package/dist/{snapSupplements-CLZjItJi.cjs → snapSupplements-BXSXTjqF.cjs} +25 -15
  214. package/dist/{snapSupplements-Yxs4jgC-.js → snapSupplements-D7hHhdC9.js} +17 -7
  215. package/dist/{spanx-DVDyAyFC.js → spanx-5-0yX3iK.js} +19 -9
  216. package/dist/{spanx-Cpbot5J5.cjs → spanx-lUzP6Lva.cjs} +31 -21
  217. package/dist/{spanxStaging-DAiFEMRU.js → spanxStaging-HglCMJag.js} +19 -9
  218. package/dist/{spanxStaging-DbaVonN6.cjs → spanxStaging-hreMR0MS.cjs} +35 -25
  219. package/dist/suggestionBarV2-types-B0RbMStE.js +9 -0
  220. package/dist/suggestionBarV2-types-DG3Ekk44.cjs +15 -0
  221. package/dist/{supergoop-C4McrZPT.js → supergoop-C9DDT3lY.js} +18 -7
  222. package/dist/{supergoop-B5VQlsoe.cjs → supergoop-CkjtuRck.cjs} +29 -18
  223. package/dist/test-types-C9b_OdfO.d.ts +39 -0
  224. package/dist/test-types-CpKCxk8U.d.cts +39 -0
  225. package/dist/types/index.cjs +6 -0
  226. package/dist/types/index.d.cts +3 -0
  227. package/dist/types/index.d.ts +3 -0
  228. package/dist/types/index.js +4 -0
  229. package/dist/types-BE4faOO_.d.cts +32 -0
  230. package/dist/{types-QJObznro.cjs → types-BUjohkXp.cjs} +58 -58
  231. package/dist/{types-DZzSQ5a6.js → types-BVsTRyxL.js} +58 -58
  232. package/dist/types-TD8g7LnH.d.ts +32 -0
  233. package/dist/{uniqueVintage-BLp_UtBR.cjs → uniqueVintage-DIMGtYAU.cjs} +47 -37
  234. package/dist/{uniqueVintage-CS4TgOJW.js → uniqueVintage-DPWA5Ed6.js} +17 -7
  235. package/dist/useMessageInterceptor-B-P_rw73.cjs +72 -0
  236. package/dist/useMessageInterceptor-C2RZM-fo.js +57 -0
  237. package/dist/utilityTypes-BVikejDo.js +1 -0
  238. package/dist/utilityTypes-C4h2wgAK.cjs +0 -0
  239. package/dist/variant-BGjOVpY3.d.cts +12 -0
  240. package/dist/variant-XITncuI3.d.ts +12 -0
  241. package/dist/variantInfo-CNRTY0gH.cjs +0 -0
  242. package/dist/variantInfo-CzhR5W6h.js +1 -0
  243. package/dist/{venaCbd-DfnFV7Qp.js → venaCbd-B-znfAsl.js} +17 -7
  244. package/dist/{venaCbd-BxmadOeJ.cjs → venaCbd-BOwOtpOz.cjs} +30 -20
  245. package/dist/{westonJonBoucher-BZdusJgo.cjs → westonJonBoucher-CraTzRVt.cjs} +30 -20
  246. package/dist/{westonJonBoucher-C0FE4Wup.js → westonJonBoucher-DCRagGu3.js} +17 -7
  247. package/dist/{wineEnthusiast-CmhNg47M.js → wineEnthusiast-Bv7umajk.js} +17 -7
  248. package/dist/{wineEnthusiast-DQxdV8Yg.cjs → wineEnthusiast-sVuATrq6.cjs} +29 -19
  249. package/dist/{wolfMattress-vMvqmwgI.js → wolfMattress-BUH-Rhov.js} +17 -6
  250. package/dist/{wolfMattress-CqyOUgPB.cjs → wolfMattress-DpVHIEnJ.cjs} +29 -18
  251. package/dist/{wolfTactical-q3TVDP85.cjs → wolfTactical-BcvF_sy-.cjs} +29 -19
  252. package/dist/{wolfTactical-DvqxZtoA.js → wolfTactical-Q14A1fpw.js} +17 -7
  253. package/package.json +101 -3
  254. package/src/adapters/amplitude/amplitudeAdapter.ts +1 -1
  255. package/src/adapters/spiffy/commerce/api.ts +1 -1
  256. package/src/adapters/spiffy/commerce/graphql.ts +61 -37
  257. package/src/application/config/index.ts +1 -0
  258. package/src/application/models/index.ts +102 -17
  259. package/src/application/models/supportedOrgs.ts +89 -65
  260. package/src/application/service/index.ts +32 -0
  261. package/src/application/service/pageVariantService.ts +201 -114
  262. package/src/application/service/searchService.ts +1 -1
  263. package/src/application/service/windowFrontendConfigService.ts +40 -18
  264. package/src/application/utils/index.ts +22 -3
  265. package/src/atoms/app/variant.ts +48 -29
  266. package/src/atoms/atomStore/index.ts +1 -0
  267. package/src/atoms/chat/messageQueue.ts +34 -17
  268. package/src/atoms/chat/performanceMetrics.ts +51 -38
  269. package/src/atoms/chat/renderedWidgetRefs.ts +14 -15
  270. package/src/atoms/globalSearch/index.ts +1 -0
  271. package/src/atoms/org/org.ts +1 -3
  272. package/src/atoms/org/orgUIConfig.ts +31 -24
  273. package/src/contexts/chatContext.tsx +124 -72
  274. package/src/events/registerAnalyticsListeners.ts +13 -9
  275. package/src/hooks/useFileUpload.ts +9 -7
  276. package/src/hooks/useSearch.tsx +3 -3
  277. package/src/initialize.ts +1 -1
  278. package/src/interceptors/index.ts +3 -0
  279. package/src/main.tsx +1 -1
  280. package/src/types/index.ts +4 -0
  281. package/dist/GridInsertionService-C00upKLB.js +0 -40
  282. package/dist/GridInsertionService-CMJVhD6q.cjs +0 -52
  283. package/dist/custservice-types-BgjGHCtD.cjs +0 -16
  284. package/dist/custservice-types-V6FWABp4.js +0 -10
  285. package/dist/default-DMtAjA62.cjs +0 -4
  286. package/dist/default-zcmT2032.js +0 -4
  287. package/dist/divIds-Cfp3v_rG.js +0 -35
  288. package/dist/domInsertionService-BtzuH2Sc.js +0 -65
  289. package/dist/domInsertionService-Cb9814oM.cjs +0 -89
  290. package/dist/suggestionBarV2-types-XHYD3j8E.cjs +0 -46
  291. package/dist/suggestionBarV2-types-aiQmVx5m.js +0 -34
  292. package/src/atoms/index.ts +0 -5
  293. package/src/index.ts +0 -31
  294. /package/dist/{cdnService-CAyO3axV.js → cdnService-DvDSpfVJ.js} +0 -0
  295. /package/dist/{cdnService-DIF1i7VC.cjs → cdnService-dJU3sHpF.cjs} +0 -0
  296. /package/dist/{entrypoints-RmIbdYxh.js → entrypoints-CmmOszXO.js} +0 -0
  297. /package/dist/{entrypoints-C8JwiMYA.cjs → entrypoints-fowCLUT2.cjs} +0 -0
  298. /package/dist/{socialProofClasses-CaA83vI4.cjs → socialProofClasses-BYLiEXpU.cjs} +0 -0
  299. /package/dist/{socialProofClasses-KB7zOMmg.js → socialProofClasses-CkJufEGb.js} +0 -0
  300. /package/src/atoms/{atomStore.ts → atomStore/atomStore.ts} +0 -0
  301. /package/src/atoms/{globalSearch.ts → globalSearch/globalSearch.ts} +0 -0
@@ -1,3629 +1,17 @@
1
- import { GridInsertionType, logger_default } from "./GridInsertionService-C00upKLB.js";
2
- import { DOMInsertionType, FeatureGates, MessageRole, MessageType } from "./domInsertionService-BtzuH2Sc.js";
3
- import { CategoryExtractorType, ColorNames, OrgShortName, PageVariantTestType, getOrgInfo } from "./types-DZzSQ5a6.js";
4
- import { useEnviveConfig } from "./enviveConfigContext-CUGLpPGU.js";
5
- import { Configuration, ContextEnvEnum, ContextSourceEnum, CustomerServiceApi, CustomerServiceProvider, DefaultApi, FormType, FulfillmentDisplayStatus, InferenceApi, OrganizationStatusEnum, PLPAttributeCategory, PageVisitCategory, ResponseCategory, ResponseError, SearchApi, SuggestionCategory, SupportedEventProductCategory, UserEventCategory, V1OrgConfigGetSourceEnum } from "@spiffy-ai/commerce-api-client";
6
- import { atom, getDefaultStore, useAtom, useAtomValue, useSetAtom } from "jotai";
1
+ import { logger_default } from "./logger-pdEEY8T2.js";
2
+ import { AmplitudeAdapter, DOMObserver, MessageRole, MessageType, PerfMetricsEvents, SelectorFactory, SessionRestartRequired, SpiffyEventName, SpiffyMetricsEventName, SpiffyWidgets, StringUtils, api_default, appDetailsAtom, chatAtom, chatIdAtom, chatOnToggleAtom, clearUserEventAtom, createResponsePayload, endpointURLAtom, featureFlagServiceAtom, hasParsedVariantInfoAtom, lastAssistantMessageAtom, logPerfMetricAtom, messageFromResponse, messagesAtom, orgCustomerServiceService, orgIdAtom, orgUIConfigAtom, parseHref, processUserEventAtom, queueUserEventAtom, requestFailureAtom, responseStreamingAtom, suggestionsAtom, suggestionsLoadingAtom, supportedEventAtom, urlResolverAtom, userEventQueueAtom, userEventsAtom, userHasRepliedAtom, userIdAtom, userQueueEventCountAtom, variantInfoAtom } from "./api-NJEaveju.js";
3
+ import { CategoryExtractorType, OrgShortName, PageVariantTestType } from "./types-BVsTRyxL.js";
4
+ import { getAtomStore } from "./atomStore-BFtpknLM.js";
5
+ import { customerServiceAttachment, orgPageConfigAtom } from "./org-C11APG3v.js";
6
+ import { ProductSorting, addSearchFilterAtom, chatSearchIsLoadingAtom, chatSearchProductSortingAtom, chatSearchProducts, chatSearchStateAtom, clearSearchFiltersAtom, createFilterOption, filteredSearchProductsAtom, formatFilterDisplayName, handleSearchResultsAtom, performSearchAtom, removeSearchFilterAtom, searchAtom, searchFiltersAtom, searchParamsAtom, searchProductSortingAtom, searchSelectedFiltersAtom } from "./search-CvHb1M3S.js";
7
+ import { autocompleteStateAtom, isFilterOpenAtom } from "./globalSearch-BC0rOX3E.js";
8
+ import { useMessageInterceptor } from "./useMessageInterceptor-C2RZM-fo.js";
9
+ import { PLPAttributeCategory, PageVisitCategory, UserEventCategory } from "@spiffy-ai/commerce-api-client";
10
+ import { useAtom, useAtomValue, useSetAtom } from "jotai";
7
11
  import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
8
- import { atomWithStorage, createJSONStorage } from "jotai/utils";
9
12
  import { jsx } from "react/jsx-runtime";
10
- import UAParser from "ua-parser-js";
11
13
  import { v4 } from "uuid";
12
- import { UserEventCategory as UserEventCategory$1 } from "@spiffy-ai/commerce-api-client/dist/models/UserEventCategory";
13
- import { createInstance } from "@amplitude/analytics-browser";
14
- import { createPortal } from "react-dom";
15
-
16
- //#region src/application/models/guards/api/isApiSuggestion.ts
17
- const isSuggestion = (data) => {
18
- if (data == null || typeof data !== "object") return false;
19
- if (!("id" in data) || typeof data.id !== "string") return false;
20
- if (!("category" in data) || typeof data.category !== "string" || !Object.values(SuggestionCategory).includes(data.category)) return false;
21
- if (!("created_at" in data) || typeof data.created_at !== "string") return false;
22
- if (!("content" in data) || typeof data.content !== "string") return false;
23
- if ("is_answer" in data && data.is_answer != null && typeof data.is_answer !== "boolean") return false;
24
- return true;
25
- };
26
-
27
- //#endregion
28
- //#region src/application/models/validators/validateSuggestion.ts
29
- const validateSuggestion = (data) => {
30
- if (!isSuggestion(data)) return;
31
- return {
32
- id: data.id,
33
- category: data.category,
34
- content: data.content,
35
- createdAt: data.created_at,
36
- isAnswer: data.is_answer
37
- };
38
- };
39
-
40
- //#endregion
41
- //#region src/application/models/guards/api/isApiUserEvent.ts
42
- const isApiUserEvent = (data) => {
43
- if (data == null || typeof data !== "object") return false;
44
- if (!("event_id" in data) || typeof data.event_id !== "string") return false;
45
- if (!("created_at" in data) || typeof data.created_at !== "string") return false;
46
- if (!("category" in data) || typeof data.category !== "string" || !Object.values(UserEventCategory).includes(data.category)) return false;
47
- return true;
48
- };
49
-
50
- //#endregion
51
- //#region src/application/models/guards/api/isApiPDPEventAttributes.ts
52
- const isApiPDPAttributes = (data) => {
53
- if (data == null || typeof data !== "object") return false;
54
- if (!("product_id" in data) || typeof data.product_id !== "string") return false;
55
- if ("parent_product_id" in data && typeof data.parent_product_id !== "string") return false;
56
- if ("url" in data && data.url != null && typeof data.url !== "string") return false;
57
- return true;
58
- };
59
-
60
- //#endregion
61
- //#region src/application/models/guards/api/isApiQueryTypedEventAttributes.ts
62
- const isApiQueryTypedAttributes = (data) => data != null && typeof data === "object" && "query" in data && typeof data.query === "string";
63
-
64
- //#endregion
65
- //#region src/application/models/guards/api/isApiSearchEventAttributes.ts
66
- const isApiSearchAttributes = (data) => {
67
- if (data == null || typeof data !== "object") return false;
68
- if (!("search_term" in data) || typeof data.search_term !== "string") return false;
69
- if ("selected_filters" in data && !Array.isArray(data.selected_filters)) return false;
70
- if (!!data.search_term) return true;
71
- if (!("search_results" in data) || !Array.isArray(data.search_results) || !data.search_results.every((v) => typeof v === "string")) return false;
72
- return true;
73
- };
74
-
75
- //#endregion
76
- //#region src/application/models/guards/api/isApiSuggestionClickedEventAttributes.ts
77
- const isApiSuggestionClickedAttributes = (data) => data != null && typeof data === "object" && "suggestion_id" in data && typeof data.suggestion_id === "string";
78
-
79
- //#endregion
80
- //#region src/application/models/guards/api/isApiPLPEventAttributes.ts
81
- const isApiPLPIdAttribute = (data) => {
82
- if (data == null || typeof data !== "object") return false;
83
- if (!("id" in data) || typeof data.id !== "string") return false;
84
- return true;
85
- };
86
- const isApiPLPEventAttributes = (data) => {
87
- if (data == null || typeof data !== "object") return false;
88
- if (!("category" in data) || typeof data.category !== "string" || !Object.values(PLPAttributeCategory).includes(data.category)) return false;
89
- if (!("attributes" in data) || typeof data.attributes !== "object" || !isApiPLPIdAttribute(data.attributes)) return false;
90
- return true;
91
- };
92
-
93
- //#endregion
94
- //#region src/application/models/guards/utils.ts
95
- /**
96
- * Checks if an object has a property of a specific type
97
- *
98
- * @param obj - The object to check
99
- * @param prop - The property name to check
100
- * @param type - The expected type of the property
101
- * @param isOptional - Whether the property is optional (defaults to false)
102
- *
103
- * @returns boolean indicating if the object has the property of the specified type
104
- */
105
- const hasPropertyOfType = (obj, prop, type, isOptional = false) => {
106
- try {
107
- if (obj == null || typeof obj !== "object") return false;
108
- if (!(prop in obj)) return isOptional;
109
- const value = obj[prop];
110
- if (isOptional && value == null) return true;
111
- if (type === "array") return Array.isArray(value);
112
- return typeof value === type;
113
- } catch (err) {
114
- return false;
115
- }
116
- };
117
-
118
- //#endregion
119
- //#region src/application/models/guards/api/isApiFormSubmittedResponseAttributes.ts
120
- const isApiFormSubmittedResponseAttributes = (data) => {
121
- if (data == null || typeof data !== "object") {
122
- logger_default.logError("isApiFormSubmittedResponseAttributes", "data is null or not an object", data);
123
- return false;
124
- }
125
- if (!hasPropertyOfType(data, "filled_schema", "object")) {
126
- logger_default.logError("isApiFormSubmittedResponseAttributes", "filled_schema is not an object", data);
127
- return false;
128
- }
129
- if (!hasPropertyOfType(data, "form_response_id", "string")) {
130
- logger_default.logError("isApiFormSubmittedResponseAttributes", "form_response_id is not a string", data);
131
- return false;
132
- }
133
- if (!("form_type" in data) || !Object.values(FormType).includes(data.form_type)) {
134
- logger_default.logError("isApiFormSubmittedResponseAttributes", "form_type is not a valid form type enum", data);
135
- return false;
136
- }
137
- return true;
138
- };
139
-
140
- //#endregion
141
- //#region src/application/models/validators/validateUserEvent.ts
142
- const validateUserEvent = (data) => {
143
- if (!isApiUserEvent(data)) return;
144
- if (data.category === UserEventCategory.PdpVisit && isApiPDPAttributes(data.attributes)) return {
145
- eventId: data.event_id,
146
- createdAt: data.created_at,
147
- category: UserEventCategory.PdpVisit,
148
- attributes: {
149
- productId: data.attributes.product_id,
150
- parentProductId: data.attributes.parent_product_id,
151
- url: data.attributes.url
152
- }
153
- };
154
- if (data.category === UserEventCategory.QueryTyped && isApiQueryTypedAttributes(data.attributes)) return {
155
- eventId: data.event_id,
156
- createdAt: data.created_at,
157
- category: UserEventCategory.QueryTyped,
158
- attributes: { query: data.attributes.query }
159
- };
160
- if (data.category === UserEventCategory.Search && isApiSearchAttributes(data.attributes)) return {
161
- eventId: data.event_id,
162
- createdAt: data.created_at,
163
- category: UserEventCategory.Search,
164
- attributes: {
165
- searchTerm: data.attributes.search_term,
166
- selectedFilters: data.attributes.selected_filters
167
- }
168
- };
169
- if (data.category === UserEventCategory.SuggestionClicked && isApiSuggestionClickedAttributes(data.attributes)) return {
170
- eventId: data.event_id,
171
- createdAt: data.created_at,
172
- category: UserEventCategory.SuggestionClicked,
173
- attributes: { suggestionId: data.attributes.suggestion_id }
174
- };
175
- if (data.category === UserEventCategory.PlpVisit && isApiPLPEventAttributes(data.attributes)) {
176
- if (isApiPLPIdAttribute(data.attributes)) return {
177
- eventId: data.event_id,
178
- createdAt: data.created_at,
179
- category: UserEventCategory.PlpVisit,
180
- attributes: {
181
- category: data.attributes.category,
182
- attributes: { id: data.attributes.id }
183
- }
184
- };
185
- }
186
- if (data.category === UserEventCategory.FormSubmitted && isApiFormSubmittedResponseAttributes(data.attributes)) return {
187
- eventId: data.event_id,
188
- createdAt: data.created_at,
189
- category: UserEventCategory.FormSubmitted,
190
- attributes: {
191
- filledSchema: { ...data.attributes.filled_schema },
192
- formResponseId: data.attributes.form_response_id,
193
- formType: data.attributes.form_type
194
- }
195
- };
196
- return {
197
- eventId: data.event_id,
198
- createdAt: data.created_at,
199
- category: UserEventCategory.AppLoaded
200
- };
201
- };
202
-
203
- //#endregion
204
- //#region src/application/utils/messageFromQueryEvent.ts
205
- /**
206
- * Transforms a query UserEvent object into a Message object for presentation.
207
- *
208
- * @param event The user event object received from the server
209
- *
210
- * @returns A Message if the event is a query event, otherwise undefined
211
- */
212
- const messageFromQueryEvent = (event) => {
213
- if (event.category === UserEventCategory.QueryTyped) return {
214
- id: event.eventId,
215
- role: MessageRole.User,
216
- type: MessageType.QueryTyped,
217
- createdAt: event.createdAt,
218
- metadata: { content: event.attributes.query }
219
- };
220
- if (event.category === UserEventCategory.Search) return {
221
- id: event.eventId,
222
- role: MessageRole.User,
223
- type: MessageType.Search,
224
- createdAt: event.createdAt,
225
- metadata: {
226
- searchTerm: event.attributes.searchTerm || "",
227
- selectedFilters: event.attributes.selectedFilters || []
228
- }
229
- };
230
- };
231
-
232
- //#endregion
233
- //#region src/application/utils/messageFromResponse.ts
234
- /**
235
- * Transforms a server Response object into a Message object for presentation.
236
- *
237
- * @param response The response object received from the server containing model generated content
238
- *
239
- * @returns A Message if the response contains known attributes, undefined otherwise
240
- */
241
- const messageFromResponse = (response) => {
242
- if (response == null) return;
243
- if (response.category === ResponseCategory.Text) return {
244
- id: response.id,
245
- createdAt: response.createdAt,
246
- type: MessageType.Text,
247
- role: MessageRole.Assistant,
248
- metadata: { content: response.attributes.content }
249
- };
250
- if (response.category === ResponseCategory.Product) return {
251
- id: response.id,
252
- createdAt: response.createdAt,
253
- role: MessageRole.Assistant,
254
- type: MessageType.Product,
255
- metadata: { ...response.attributes }
256
- };
257
- if (response.category === ResponseCategory.Review) return {
258
- id: response.id,
259
- createdAt: response.createdAt,
260
- type: MessageType.Review,
261
- role: MessageRole.Assistant,
262
- metadata: {
263
- review: response.attributes.review,
264
- reviewer: response.attributes.reviewer,
265
- stars: response.attributes.stars,
266
- title: response.attributes.title,
267
- richInformation: response.attributes.richInformation
268
- }
269
- };
270
- if (response.category === ResponseCategory.Separator) return {
271
- id: response.id,
272
- createdAt: response.createdAt,
273
- type: MessageType.Separator,
274
- role: MessageRole.Assistant
275
- };
276
- if (response.category === ResponseCategory.Page) return {
277
- id: response.id,
278
- createdAt: response.createdAt,
279
- role: MessageRole.Assistant,
280
- type: MessageType.Page,
281
- metadata: { ...response.attributes }
282
- };
283
- if (response.category === ResponseCategory.ProductSearch) return {
284
- id: response.id,
285
- createdAt: response.createdAt,
286
- role: MessageRole.Assistant,
287
- type: MessageType.ProductSearch,
288
- metadata: { ...response.attributes }
289
- };
290
- if (response.category === ResponseCategory.ProductSearchFilter) return {
291
- id: response.id,
292
- createdAt: response.createdAt,
293
- role: MessageRole.Assistant,
294
- type: MessageType.ProductSearchFilter,
295
- metadata: { ...response.attributes }
296
- };
297
- if (response.category === ResponseCategory.Form) return {
298
- id: response.id,
299
- createdAt: response.createdAt,
300
- role: MessageRole.Assistant,
301
- type: MessageType.Form,
302
- metadata: {
303
- formType: response.attributes.formCategory?.formType,
304
- fields: Object.entries(response.attributes.schema.properties).map(([key, value]) => ({
305
- key,
306
- title: value.title,
307
- type: value.type,
308
- format: value.format,
309
- required: response.attributes.schema.required.includes(key)
310
- }))
311
- }
312
- };
313
- if (response.category === ResponseCategory.Order) return {
314
- id: response.id,
315
- createdAt: response.createdAt,
316
- role: MessageRole.Assistant,
317
- type: MessageType.Order,
318
- metadata: { ...response.attributes }
319
- };
320
- };
321
-
322
- //#endregion
323
- //#region src/application/utils/messageFromSuggestionEvent.ts
324
- /**
325
- * Transforms a UserEvent object into a Message object for presentation.
326
- *
327
- * @param event The UserEvent object received from the server
328
- * @param suggestions A list of generated suggestions to match the event to
329
- *
330
- * @returns A Message if the event is a suggestion click event, undefined otherwise
331
- */
332
- const messageFromSuggestionEvent = (event, suggestions) => {
333
- if (event.category === UserEventCategory.SuggestionClicked) {
334
- const { suggestionId } = event.attributes;
335
- return {
336
- id: event.eventId,
337
- role: MessageRole.User,
338
- type: MessageType.SuggestionClicked,
339
- createdAt: event.createdAt,
340
- metadata: {
341
- suggestionId,
342
- suggestionContent: suggestions.find((s) => s.id === suggestionId)?.content ?? ""
343
- }
344
- };
345
- }
346
- };
347
-
348
- //#endregion
349
- //#region src/application/utils/coreUserEventToApiUserEvent.ts
350
- const coreUserEventToApiUserEvent = (data) => {
351
- if (data.category === UserEventCategory.PdpVisit || data.category === UserEventCategory.AddToCart) return {
352
- event_id: data.eventId,
353
- created_at: data.createdAt,
354
- category: data.category,
355
- attributes: {
356
- product_id: data.attributes.productId,
357
- parent_product_id: data.attributes.parentProductId,
358
- url: data.attributes.url
359
- }
360
- };
361
- if (data.category === UserEventCategory.PlpVisit) return {
362
- event_id: data.eventId,
363
- created_at: data.createdAt,
364
- category: data.category,
365
- attributes: {
366
- category: PLPAttributeCategory.Id,
367
- attributes: { id: data.attributes.attributes.id }
368
- }
369
- };
370
- if (data.category === UserEventCategory.QueryTyped) return {
371
- event_id: data.eventId,
372
- created_at: data.createdAt,
373
- category: data.category,
374
- attributes: { query: data.attributes.query }
375
- };
376
- if (data.category === UserEventCategory.Search) return {
377
- event_id: data.eventId,
378
- created_at: data.createdAt,
379
- category: data.category,
380
- attributes: {
381
- search_term: data.attributes.searchTerm,
382
- selected_filters: data.attributes.selectedFilters
383
- }
384
- };
385
- if (data.category === UserEventCategory.SuggestionClicked) return {
386
- event_id: data.eventId,
387
- created_at: data.createdAt,
388
- category: data.category,
389
- attributes: { suggestion_id: data.attributes.suggestionId }
390
- };
391
- if (data.category === UserEventCategory.PageVisit) return {
392
- event_id: data.eventId,
393
- created_at: data.createdAt,
394
- category: data.category,
395
- attributes: {
396
- url: data.attributes.url,
397
- page_visit_category: data.attributes.pageVisitCategory
398
- }
399
- };
400
- if (data.category === UserEventCategory.FormSubmitted) return {
401
- event_id: data.eventId,
402
- created_at: data.createdAt,
403
- category: data.category,
404
- attributes: {
405
- filled_schema: { ...data.attributes.filledSchema },
406
- form_response_id: data.attributes.formResponseId,
407
- form_type: data.attributes.formType
408
- }
409
- };
410
- return {
411
- event_id: data.eventId,
412
- created_at: data.createdAt,
413
- category: data.category
414
- };
415
- };
416
-
417
- //#endregion
418
- //#region src/application/utils/nextMessageRequestToApiRequest.ts
419
- const messageRequestToCommerceMessageRequest = (data) => ({
420
- context: {
421
- chat_id: data.context.chatId,
422
- org_id: data.context.orgId,
423
- org_short_name: data.context.orgShortName,
424
- user_id: data.context.userId,
425
- source: data.context.source,
426
- env: data.context.env
427
- },
428
- id: data.id,
429
- feature_flags: data.featureFlags,
430
- user_events: data.userEvents?.map((userEvent) => coreUserEventToApiUserEvent(userEvent)),
431
- generation_params: {
432
- model: data.generationParams?.model,
433
- max_tokens: data.generationParams?.maxTokens,
434
- stop: data.generationParams?.stop,
435
- stream: data.generationParams?.stream,
436
- temperature: data.generationParams?.temperature,
437
- top_p: data.generationParams?.topP,
438
- num_suggestions: data.generationParams?.numSuggestions,
439
- response_system_prompt: data.generationParams?.responseSystemPrompt,
440
- suggestion_system_prompt: data.generationParams?.suggestionSystemPrompt,
441
- response_caching: data.generationParams?.responseCaching
442
- }
443
- });
444
-
445
- //#endregion
446
- //#region src/application/models/guards/api/isApiPageResponseAttributes.ts
447
- const isApiPageResponseAttributes = (obj) => {
448
- if (obj == null || typeof obj !== "object") return false;
449
- if ("title" in obj && obj.title != null && typeof obj.title !== "string") return false;
450
- if ("description" in obj && typeof obj.description !== "string") return false;
451
- if ("url" in obj && typeof obj.url !== "string") return false;
452
- return true;
453
- };
454
-
455
- //#endregion
456
- //#region src/application/models/guards/api/isApiProductResponseAttributes.ts
457
- const isApiProductResponseAttributes = (attributes) => {
458
- if (attributes == null || typeof attributes !== "object") {
459
- logger_default.logError("isApiProductResponseAttributes: attributes is null or not an object", void 0, { attributes });
460
- return false;
461
- }
462
- if (!hasPropertyOfType(attributes, "description", "string", true)) {
463
- logger_default.logError("isApiProductResponseAttributes: description is not a string", void 0, { attributes });
464
- return false;
465
- }
466
- if (!hasPropertyOfType(attributes, "image_url", "string", true)) {
467
- logger_default.logError("isApiProductResponseAttributes: image_url is not a string", void 0, { attributes });
468
- return false;
469
- }
470
- if (!hasPropertyOfType(attributes, "title", "string")) {
471
- logger_default.logError("isApiProductResponseAttributes: title is not a string", void 0, { attributes });
472
- return false;
473
- }
474
- if (!hasPropertyOfType(attributes, "url", "string")) {
475
- logger_default.logError("isApiProductResponseAttributes: url is not a string", void 0, { attributes });
476
- return false;
477
- }
478
- if (!hasPropertyOfType(attributes, "original_price", "number", true)) {
479
- logger_default.logError("isApiProductResponseAttributes: original_price is not a number", void 0, { attributes });
480
- return false;
481
- }
482
- if (!hasPropertyOfType(attributes, "sale_price", "number", true)) {
483
- logger_default.logError("isApiProductResponseAttributes: sale_price is not a number", void 0, { attributes });
484
- return false;
485
- }
486
- if (!hasPropertyOfType(attributes, "average_rating", "number", true)) {
487
- logger_default.logError("isApiProductResponseAttributes: average_rating is not a number", void 0, { attributes });
488
- return false;
489
- }
490
- if (!hasPropertyOfType(attributes, "number_reviews", "number", true)) {
491
- logger_default.logError("isApiProductResponseAttributes: number_reviews is not a number", void 0, { attributes });
492
- return false;
493
- }
494
- if (!hasPropertyOfType(attributes, "metadata", "array", true)) {
495
- logger_default.logError("isApiProductResponseAttributes: metadata is not an array", void 0, { attributes });
496
- return false;
497
- }
498
- return true;
499
- };
500
-
501
- //#endregion
502
- //#region src/application/models/guards/api/isApiResponse.ts
503
- const isApiResponse = (data) => {
504
- if (data == null || typeof data !== "object") {
505
- logger_default.logError("isApiResponse: data is null or not an object", void 0, { data });
506
- return false;
507
- }
508
- if (!hasPropertyOfType(data, "id", "string")) {
509
- logger_default.logError("isApiResponse: id is not a string", void 0, { data });
510
- return false;
511
- }
512
- if (!hasPropertyOfType(data, "category", "string") || !Object.values(ResponseCategory).includes(data.category)) {
513
- logger_default.logError("isApiResponse: category is not a string or not a valid response category", void 0, { data });
514
- return false;
515
- }
516
- if (!hasPropertyOfType(data, "created_at", "string")) {
517
- logger_default.logError("isApiResponse: created_at is not a string", void 0, { data });
518
- return false;
519
- }
520
- if (!hasPropertyOfType(data, "attributes", "object", true)) {
521
- logger_default.logError("isApiResponse: attributes is not an object", void 0, { data });
522
- return false;
523
- }
524
- return true;
525
- };
526
-
527
- //#endregion
528
- //#region src/application/models/guards/api/isApiReviewRichInformation.ts
529
- const isApiReviewRichInformation = (richInfo) => {
530
- if (richInfo == null || typeof richInfo !== "object") return false;
531
- if ("cons" in richInfo && (!Array.isArray(richInfo.cons) || richInfo.cons.some((con) => typeof con !== "string"))) return false;
532
- if ("pros" in richInfo && (!Array.isArray(richInfo.pros) || richInfo.pros.some((pro) => typeof pro !== "string"))) return false;
533
- if ("review_date" in richInfo && typeof richInfo.review_date !== "string") return false;
534
- if ("reviewer_title" in richInfo && typeof richInfo.reviewer_title !== "string") return false;
535
- if ("product_familiarity" in richInfo && typeof richInfo.product_familiarity !== "string") return false;
536
- return true;
537
- };
538
-
539
- //#endregion
540
- //#region src/application/models/guards/api/isApiReviewResponseAttributes.ts
541
- const isApiReviewResponseAttributes = (obj) => {
542
- if (obj == null || typeof obj !== "object") return false;
543
- if ("title" in obj && obj.title != null && typeof obj.title !== "string") return false;
544
- if ("review" in obj && typeof obj.review !== "string") return false;
545
- if ("reviewer" in obj && typeof obj.reviewer !== "string") return false;
546
- if ("stars" in obj && typeof obj.stars !== "number") return false;
547
- if ("rich_information" in obj && !isApiReviewRichInformation(obj.rich_information)) return false;
548
- return true;
549
- };
550
-
551
- //#endregion
552
- //#region src/application/models/guards/api/isApiTextResponseAttributes.ts
553
- const isApiTextResponseAttributes = (attributes) => typeof attributes === "object" && attributes != null && "content" in attributes && typeof attributes.content === "string";
554
-
555
- //#endregion
556
- //#region src/application/models/guards/api/isApiProductSearchAttributes.ts
557
- const isApiProductSearchResponseAttributes = (attributes) => {
558
- if (attributes == null || typeof attributes !== "object") return false;
559
- if ("generated_query" in attributes && typeof attributes.generated_query !== "string") return false;
560
- if ("product_count" in attributes && attributes.product_count != null && typeof attributes.product_count !== "number") return false;
561
- return true;
562
- };
563
-
564
- //#endregion
565
- //#region src/application/models/guards/api/isApiFormResponse.ts
566
- /**
567
- * Type guard to check if the provided data has the all of the properties (with the correct types) of
568
- * a FormResponseAttribute
569
- *
570
- * @param data - The data to check
571
- *
572
- * @returns true if the data has the correct properties, false otherwise
573
- */
574
- const isApiFormResponseAttributes = (data) => {
575
- if (data == null || typeof data !== "object") {
576
- logger_default.logError("isApiFormResponseAttributes: data is null or not an object", void 0, { data });
577
- return false;
578
- }
579
- if ("form_category" in data && typeof data.form_category !== "object") {
580
- logger_default.logError("isApiFormResponseAttributes: form_category is not an object", void 0, { data });
581
- return false;
582
- }
583
- if ("form_category" in data && typeof data.form_category === "object") {
584
- if (!hasPropertyOfType(data.form_category, "form_type", "string") || !Object.values(FormType).includes(data.form_category.form_type)) {
585
- logger_default.logError("isApiFormResponseAttributes: form_type is missing or not a valid form type", void 0, { data });
586
- return false;
587
- }
588
- }
589
- if (!hasPropertyOfType(data, "schema", "object")) {
590
- logger_default.logError("isApiFormResponseAttributes: schema is missing or not an object", void 0, { data });
591
- return false;
592
- }
593
- if (!hasPropertyOfType(data.schema, "properties", "object")) {
594
- logger_default.logError("isApiFormResponseAttributes: schema.properties is missing or not an object", void 0, { data });
595
- return false;
596
- }
597
- if (!hasPropertyOfType(data.schema, "required", "array")) {
598
- logger_default.logError("isApiFormResponseAttributes: schema.required is missing or not an array", void 0, { data });
599
- return false;
600
- }
601
- if (!data.schema.required.every((key) => typeof key === "string" && key in data.schema.properties)) {
602
- logger_default.logError("isApiFormResponseAttributes: schema.required contains invalid property keys", void 0, { data });
603
- return false;
604
- }
605
- return true;
606
- };
607
-
608
- //#endregion
609
- //#region src/application/models/guards/api/isApiOrderResponseAttributes.ts
610
- const isApiOrderItemInfo = (data) => {
611
- if (data == null || typeof data !== "object") {
612
- logger_default.logError("OrderItemInfo must be an object", void 0, { data });
613
- return false;
614
- }
615
- if (!hasPropertyOfType(data, "order_item_id", "string")) {
616
- logger_default.logError("OrderItemInfo must have an order_item_id property", void 0, { data });
617
- return false;
618
- }
619
- if (!hasPropertyOfType(data, "item_title", "string")) {
620
- logger_default.logError("OrderItemInfo must have an item_title property", void 0, { data });
621
- return false;
622
- }
623
- if (!hasPropertyOfType(data, "item_price", "number")) {
624
- logger_default.logError("OrderItemInfo must have an item_price property", void 0, { data });
625
- return false;
626
- }
627
- if (!hasPropertyOfType(data, "item_quantity", "number")) {
628
- logger_default.logError("OrderItemInfo must have an item_quantity property", void 0, { data });
629
- return false;
630
- }
631
- if (!hasPropertyOfType(data, "image", "string", true)) {
632
- logger_default.logError("OrderItemInfo.image must be a string or null", void 0, { data });
633
- return false;
634
- }
635
- if (!hasPropertyOfType(data, "fulfillment_display_status", "string", true)) {
636
- logger_default.logError("OrderItemInfo.fulfillment_display_status must be a string or null", void 0, { data });
637
- return false;
638
- }
639
- if (!hasPropertyOfType(data, "tracking_url", "string", true)) {
640
- logger_default.logError("OrderItemInfo.tracking_url must be a string or null", void 0, { data });
641
- return false;
642
- }
643
- if (!hasPropertyOfType(data, "delivered_at", "string", true)) {
644
- logger_default.logError("OrderItemInfo.delivered_at must be a string or null", void 0, { data });
645
- return false;
646
- }
647
- if (!hasPropertyOfType(data, "estimated_delivery_at", "string", true)) {
648
- logger_default.logError("OrderItemInfo.estimated_delivery_at must be a string or null", void 0, { data });
649
- return false;
650
- }
651
- if (!hasPropertyOfType(data, "in_transit_at", "string", true)) {
652
- logger_default.logError("OrderItemInfo.in_transit_at must be a string or null", void 0, { data });
653
- return false;
654
- }
655
- return true;
656
- };
657
- const isApiOrderResponseAttributes = (data) => {
658
- if (data == null || typeof data !== "object") {
659
- logger_default.logError("Order response attributes must be an object", void 0, { data });
660
- return false;
661
- }
662
- if (!hasPropertyOfType(data, "created_at", "string")) {
663
- logger_default.logError("Order response attributes must have a created_at property and have type string", void 0, { data });
664
- return false;
665
- }
666
- if (!hasPropertyOfType(data, "latest_event_date", "string")) {
667
- logger_default.logError("Order response attributes must have a latest_event_date property and have type string", void 0, { data });
668
- return false;
669
- }
670
- if (!hasPropertyOfType(data, "line_items", "array") || !data.line_items.every((item) => isApiOrderItemInfo(item))) {
671
- logger_default.logError("Order response attributes must have a line_items property with at least one order item", void 0, { data });
672
- return false;
673
- }
674
- if (!hasPropertyOfType(data, "order_id", "string")) {
675
- logger_default.logError("Order response attributes must have an order_id property and have type string", void 0, { data });
676
- return false;
677
- }
678
- if (!hasPropertyOfType(data, "order_number", "string")) {
679
- logger_default.logError("Order response attributes must have an order_number property and have type string", void 0, { data });
680
- return false;
681
- }
682
- return true;
683
- };
684
-
685
- //#endregion
686
- //#region src/application/models/utils/stringToFulfillmentDisplayStatusEnumValue.ts
687
- /**
688
- * Converts a string to a FulfillmentDisplayStatus enum value.
689
- *
690
- * @param status - The string to convert.
691
- *
692
- * @returns The FulfillmentDisplayStatus enum value or undefined if the string
693
- * does not map to a valid enum
694
- */
695
- const stringToFulfillmentDisplayStatusEnumValue = (status) => {
696
- switch (status) {
697
- case "ATTEMPTED_DELIVERY": return FulfillmentDisplayStatus.ATTEMPTED_DELIVERY;
698
- case "CANCELED": return FulfillmentDisplayStatus.CANCELED;
699
- case "CONFIRMED": return FulfillmentDisplayStatus.CONFIRMED;
700
- case "DELIVERED": return FulfillmentDisplayStatus.DELIVERED;
701
- case "FAILURE": return FulfillmentDisplayStatus.FAILURE;
702
- case "FULFILLED": return FulfillmentDisplayStatus.FULFILLED;
703
- case "IN_TRANSIT": return FulfillmentDisplayStatus.IN_TRANSIT;
704
- case "LABEL_PRINTED": return FulfillmentDisplayStatus.LABEL_PRINTED;
705
- case "LABEL_PURCHASED": return FulfillmentDisplayStatus.LABEL_PURCHASED;
706
- case "LABEL_VOIDED": return FulfillmentDisplayStatus.LABEL_VOIDED;
707
- case "MARKED_AS_FULFILLED": return FulfillmentDisplayStatus.MARKED_AS_FULFILLED;
708
- case "NOT_DELIVERED": return FulfillmentDisplayStatus.NOT_DELIVERED;
709
- case "OUT_FOR_DELIVERY": return FulfillmentDisplayStatus.OUT_FOR_DELIVERY;
710
- case "PICKED_UP": return FulfillmentDisplayStatus.PICKED_UP;
711
- case "READY_FOR_PICKUP": return FulfillmentDisplayStatus.READY_FOR_PICKUP;
712
- case "SUBMITTED": return FulfillmentDisplayStatus.SUBMITTED;
713
- case "IN_PROGRESS": return FulfillmentDisplayStatus.IN_PROGRESS;
714
- case "ON_HOLD": return FulfillmentDisplayStatus.ON_HOLD;
715
- case "OPEN": return FulfillmentDisplayStatus.OPEN;
716
- case "PARTIALLY_FULFILLED": return FulfillmentDisplayStatus.PARTIALLY_FULFILLED;
717
- case "PENDING_FULFILLMENT": return FulfillmentDisplayStatus.PENDING_FULFILLMENT;
718
- case "REQUEST_DECLINED": return FulfillmentDisplayStatus.REQUEST_DECLINED;
719
- case "RESTOCKED": return FulfillmentDisplayStatus.RESTOCKED;
720
- case "SCHEDULED": return FulfillmentDisplayStatus.SCHEDULED;
721
- case "UNFULFILLED": return FulfillmentDisplayStatus.UNFULFILLED;
722
- default: return;
723
- }
724
- };
725
-
726
- //#endregion
727
- //#region src/application/models/guards/api/isApiProductSearchFilterAttributes.ts
728
- const isApiProductSearchFilterResponseAttributes = (attributes) => {
729
- if (attributes == null || typeof attributes !== "object") return false;
730
- if ("filter_name" in attributes && typeof attributes.filter_name !== "string") return false;
731
- return true;
732
- };
733
-
734
- //#endregion
735
- //#region src/application/models/validators/validateResponse.ts
736
- const richInformationFromCommerceRichInformation = (data) => ({
737
- cons: data.cons,
738
- pros: data.pros,
739
- reviewDate: data.review_date,
740
- reviewerTitle: data.reviewer_title,
741
- productFamiliarity: data.product_familiarity
742
- });
743
- const validateResponse = (data) => {
744
- if (!isApiResponse(data)) return;
745
- if (data.category === ResponseCategory.Text && isApiTextResponseAttributes(data.attributes)) return {
746
- id: data.id,
747
- createdAt: data.created_at,
748
- category: ResponseCategory.Text,
749
- attributes: { content: data.attributes.content }
750
- };
751
- if (data.category === ResponseCategory.Product && isApiProductResponseAttributes(data.attributes)) return {
752
- id: data.id,
753
- createdAt: data.created_at,
754
- category: ResponseCategory.Product,
755
- attributes: {
756
- id: data.attributes.id,
757
- description: data.attributes.description,
758
- imageUrl: data.attributes.image_url,
759
- imageUrls: data.attributes.image_urls,
760
- title: data.attributes.title,
761
- url: data.attributes.url,
762
- originalPrice: data.attributes.original_price,
763
- salePrice: data.attributes.sale_price,
764
- averageRating: data.attributes.average_rating,
765
- numberReviews: data.attributes.number_reviews,
766
- metadata: data.attributes.metadata,
767
- isForGrid: data.attributes.is_for_grid,
768
- colors: data.attributes.colors,
769
- sizes: data.attributes.sizes,
770
- filters: data.attributes.filters
771
- }
772
- };
773
- if (data.category === ResponseCategory.Review && isApiReviewResponseAttributes(data.attributes)) return {
774
- id: data.id,
775
- createdAt: data.created_at,
776
- category: ResponseCategory.Review,
777
- attributes: {
778
- id: data.attributes.id,
779
- productId: data.attributes.product_id,
780
- title: data.attributes.title,
781
- reviewer: data.attributes.reviewer,
782
- review: data.attributes.review,
783
- stars: data.attributes.stars,
784
- richInformation: data.attributes.rich_information ? richInformationFromCommerceRichInformation(data.attributes.rich_information) : void 0
785
- }
786
- };
787
- if (data.category === ResponseCategory.Separator) return {
788
- id: data.id,
789
- createdAt: data.created_at,
790
- category: ResponseCategory.Separator
791
- };
792
- if (data.category === ResponseCategory.Page && isApiPageResponseAttributes(data.attributes)) return {
793
- id: data.id,
794
- createdAt: data.created_at,
795
- category: ResponseCategory.Page,
796
- attributes: {
797
- id: data.attributes.id,
798
- title: data.attributes.title,
799
- description: data.attributes.description,
800
- url: data.attributes.url
801
- }
802
- };
803
- if (data.category === ResponseCategory.Form && isApiFormResponseAttributes(data.attributes)) return {
804
- id: data.id,
805
- createdAt: data.created_at,
806
- category: ResponseCategory.Form,
807
- attributes: {
808
- formCategory: data.attributes.form_category ? { formType: data.attributes.form_category.form_type } : void 0,
809
- schema: {
810
- properties: data.attributes.schema.properties,
811
- required: data.attributes.schema.required.map(String)
812
- }
813
- }
814
- };
815
- if (data.category === ResponseCategory.ProductSearch && isApiProductSearchResponseAttributes(data.attributes)) return {
816
- id: data.id,
817
- createdAt: data.created_at,
818
- category: ResponseCategory.ProductSearch,
819
- attributes: {
820
- generatedQuery: data.attributes.generated_query,
821
- productCount: data.attributes.product_count
822
- }
823
- };
824
- if (data.category === ResponseCategory.ProductSearchFilter && isApiProductSearchFilterResponseAttributes(data.attributes)) return {
825
- id: data.id,
826
- createdAt: data.created_at,
827
- category: ResponseCategory.ProductSearchFilter,
828
- attributes: { filterName: data.attributes.filter_name }
829
- };
830
- if (data.category === ResponseCategory.Order && isApiOrderResponseAttributes(data.attributes)) return {
831
- id: data.id,
832
- createdAt: data.created_at,
833
- category: ResponseCategory.Order,
834
- attributes: {
835
- orderId: data.attributes.order_id,
836
- orderNumber: data.attributes.order_number,
837
- createdAt: data.attributes.created_at,
838
- latestEventDate: data.attributes.latest_event_date,
839
- lineItems: data.attributes.line_items.map((item) => ({
840
- itemTitle: item.item_title,
841
- itemPrice: item.item_price,
842
- itemQuantity: item.item_quantity,
843
- orderItemId: item.order_item_id,
844
- image: item.image ?? void 0,
845
- inTransitAt: item.in_transit_at ?? void 0,
846
- deliveredAt: item.delivered_at ?? void 0,
847
- estimatedDeliveryAt: item.estimated_delivery_at ?? void 0,
848
- fulfillmentDisplayStatus: item.fulfillment_display_status ? stringToFulfillmentDisplayStatusEnumValue(item.fulfillment_display_status) : void 0,
849
- trackingUrl: item.tracking_url ?? void 0
850
- }))
851
- }
852
- };
853
- };
854
-
855
- //#endregion
856
- //#region src/application/utils/coreContextToApiContext.ts
857
- const coreContextToApiContext = (context) => ({
858
- chat_id: context.chatId,
859
- org_id: context.orgId,
860
- user_id: context.userId,
861
- org_short_name: context.orgShortName,
862
- source: context.source,
863
- env: context.env
864
- });
865
-
866
- //#endregion
867
- //#region src/application/utils/supportedEventRequestToApiRequest.ts
868
- const coreSupportedEventRequestToApiRequest = (coreSupportedEventRequest) => ({
869
- id: coreSupportedEventRequest.id,
870
- user_event: coreUserEventToApiUserEvent(coreSupportedEventRequest.userEvent),
871
- context: coreContextToApiContext(coreSupportedEventRequest.context)
872
- });
873
-
874
- //#endregion
875
- //#region src/adapters/spiffy/commerce/exceptions/sessionExceptions.ts
876
- var SessionRestartRequired = class extends Error {
877
- constructor() {
878
- super("Session restart required");
879
- this.name = "SessionRestartRequired";
880
- }
881
- };
882
-
883
- //#endregion
884
- //#region src/adapters/spiffy/commerce/exceptions/unsupportedProductExceptions.ts
885
- var UnsupportedProductException = class extends Error {
886
- constructor() {
887
- super("Unsupported product");
888
- this.name = "UnsupportedProduct";
889
- }
890
- };
891
-
892
- //#endregion
893
- //#region src/atoms/atomStore.ts
894
- let atomStore = null;
895
- const getAtomStore = () => {
896
- if (!atomStore) atomStore = getDefaultStore();
897
- return atomStore;
898
- };
899
- const sessionStorageUtil = createJSONStorage(() => sessionStorage);
900
-
901
- //#endregion
902
- //#region src/application/service/localStorageService.ts
903
- let LocalStorageKeys = /* @__PURE__ */ function(LocalStorageKeys$1) {
904
- LocalStorageKeys$1["ChatId"] = "v1-spiffy-chat-session-id";
905
- LocalStorageKeys$1["SpiffyOnOverride"] = "spiffy_on";
906
- LocalStorageKeys$1["EnviveOnOverride"] = "envive_on";
907
- return LocalStorageKeys$1;
908
- }({});
909
- var LocalStorageService = class {
910
- static setItem(key, value) {
911
- localStorage.setItem(key, value);
912
- window.dispatchEvent(new StorageEvent("storage", {
913
- key,
914
- newValue: value
915
- }));
916
- }
917
- static getItem(key) {
918
- return localStorage.getItem(key);
919
- }
920
- static setSpiffyOnFeatureFlag(value) {
921
- if (value === true) localStorage.setItem(LocalStorageKeys.SpiffyOnOverride, "true");
922
- else if (value === false) localStorage.setItem(LocalStorageKeys.SpiffyOnOverride, "false");
923
- }
924
- static getSpiffyOnFeatureFlag() {
925
- return localStorage.getItem(LocalStorageKeys.SpiffyOnOverride);
926
- }
927
- static getLocalStorage() {
928
- const ls = window?.localStorage;
929
- if (!ls) logger_default.logError("localStorage is not available", void 0);
930
- return ls;
931
- }
932
- static {
933
- this.listenersCache = {};
934
- }
935
- static listenerForKey(listener) {
936
- if (!this.listenersCache[listener.storageKey]) this.listenersCache[listener.storageKey] = (event) => {
937
- if (event.key !== listener.storageKey) return;
938
- logger_default.logDebug(`[spiffy-ai] Storage event key=${event.key}, value=`, event.newValue);
939
- listener.listener(event);
940
- };
941
- return this.listenersCache[listener.storageKey];
942
- }
943
- /**
944
- * Attach a listener to the window's storage event. Safe to call multiple times.
945
- * @param listener
946
- */
947
- static attachListener(listener) {
948
- window.addEventListener("storage", this.listenerForKey(listener));
949
- }
950
- static detachListener(listener) {
951
- window.removeEventListener("storage", this.listenerForKey(listener));
952
- }
953
- };
954
-
955
- //#endregion
956
- //#region src/application/service/environmentService.ts
957
- var EnvironmentService = class {
958
- static getApiEndpoint() {
959
- const { baseUrl } = useEnviveConfig();
960
- return baseUrl || "https://commerce-api.dev.spiffy.ai";
961
- }
962
- static getContextSource() {
963
- if (window.IS_STORYBOOK) return ContextSourceEnum.Test;
964
- const { contextSource } = useEnviveConfig();
965
- if (contextSource) return contextSource;
966
- if (LocalStorageService.getSpiffyOnFeatureFlag() === "true") return ContextSourceEnum.Playground;
967
- return ContextSourceEnum.App;
968
- }
969
- static getIdentifyingPrefix() {
970
- return "spiffy";
971
- }
972
- static {
973
- this.getEnvironment = () => {
974
- const { env } = useEnviveConfig();
975
- if (!env) return "dev";
976
- switch (env.toLowerCase()) {
977
- case "production":
978
- case "prod": return "prod";
979
- default: return "dev";
980
- }
981
- };
982
- }
983
- };
984
-
985
- //#endregion
986
- //#region src/application/models/productExperiment.ts
987
- let ProductExperiment = /* @__PURE__ */ function(ProductExperiment$1) {
988
- ProductExperiment$1["Default"] = "default";
989
- return ProductExperiment$1;
990
- }({});
991
-
992
- //#endregion
993
- //#region src/application/models/guards/api/isApiOrganizationConfig.ts
994
- const isApiOrgAnalyticsConfigAmplitude = (data) => {
995
- if (data == null || typeof data !== "object") {
996
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: data is not an object", data);
997
- return false;
998
- }
999
- if (!("session_replay_enabled" in data) || typeof data.session_replay_enabled !== "boolean") {
1000
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: session_replay_enabled is not a boolean", data);
1001
- return false;
1002
- }
1003
- if (!("session_replay_sample_rate" in data) || typeof data.session_replay_sample_rate !== "number") {
1004
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: session_replay_sample_rate is not a number", data);
1005
- return false;
1006
- }
1007
- if (!("tracking_enabled" in data) || typeof data.tracking_enabled !== "boolean") {
1008
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigAmplitude: tracking_enabled is not a boolean", data);
1009
- return false;
1010
- }
1011
- return true;
1012
- };
1013
- const isApiOrgAnalyticsConfigCustomerService = (data) => {
1014
- if (data == null || typeof data !== "object") {
1015
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigCustomerService: data is not an object", data);
1016
- return false;
1017
- }
1018
- if (!("provider" in data) || typeof data.provider !== "string") {
1019
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigCustomerService: provider is not a string", data);
1020
- return false;
1021
- }
1022
- return true;
1023
- };
1024
- const isApiOrgAnalyticsConfigGoogleAnalytics = (data) => {
1025
- if (data == null || typeof data !== "object") {
1026
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigGoogleAnalytics: data is not an object", data);
1027
- return false;
1028
- }
1029
- if (!("measurement_id" in data) || typeof data.measurement_id !== "string") {
1030
- logger_default.logDebug("[spiffy-ai] isApiOrgAnalyticsConfigGoogleAnalytics: measurement_id is not a string", data);
1031
- return false;
1032
- }
1033
- return true;
1034
- };
1035
- /**
1036
- *
1037
- * @param data
1038
- * @returns
1039
- */
1040
- const isApiOrgAnalyticsConfig = (data) => {
1041
- if (data == null || typeof data !== "object") {
1042
- logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: data is not an object", data);
1043
- return false;
1044
- }
1045
- if ("amplitude" in data && !isApiOrgAnalyticsConfigAmplitude(data.amplitude)) {
1046
- logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: amplitude is not an object", data);
1047
- return false;
1048
- }
1049
- if ("customer_service" in data && !isApiOrgAnalyticsConfigCustomerService(data.customer_service)) {
1050
- logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: customer_service is not an object", data);
1051
- return false;
1052
- }
1053
- if ("google_analytics" in data && !isApiOrgAnalyticsConfigGoogleAnalytics(data.google_analytics)) {
1054
- logger_default.logDebug("[spiffy-ai] isOrgAnalyticsConfig: google_analytics is not an object", data);
1055
- return false;
1056
- }
1057
- return true;
1058
- };
1059
- /**
1060
- *
1061
- * @param data
1062
- * @returns
1063
- */
1064
- const isApiOrganizationConfig = (data) => {
1065
- if (data == null || typeof data !== "object") {
1066
- logger_default.logDebug("[spiffy-ai] isOrgConfig: data is not an object", data);
1067
- return false;
1068
- }
1069
- if (!("created_at" in data)) {
1070
- logger_default.logDebug("[spiffy-ai] isOrgConfig: created_at is not defined", data);
1071
- return false;
1072
- }
1073
- if (!("namespace" in data) || typeof data.namespace !== "string") {
1074
- logger_default.logDebug("[spiffy-ai] isOrgConfig: namespace is not a string", data);
1075
- return false;
1076
- }
1077
- if (!("is_latest" in data) || typeof data.is_latest !== "boolean") {
1078
- logger_default.logDebug("[spiffy-ai] isOrgConfig: is_latest is not a boolean", data);
1079
- return false;
1080
- }
1081
- if (!("version" in data) || typeof data.version !== "string") {
1082
- logger_default.logDebug("[spiffy-ai] isOrgConfig: version is not a string", data);
1083
- return false;
1084
- }
1085
- if (!("updated_at" in data)) {
1086
- logger_default.logDebug("[spiffy-ai] isOrgConfig: updated_at is not defined", data);
1087
- return false;
1088
- }
1089
- if (!("config" in data) || typeof data.config !== "object" || !isApiOrgAnalyticsConfig(data.config)) {
1090
- logger_default.logDebug("[spiffy-ai] isOrgConfig: config is not an object", data);
1091
- return false;
1092
- }
1093
- if ("organization_id" in data && typeof data.organization_id !== "string") {
1094
- logger_default.logDebug("[spiffy-ai] isOrgConfig: organization_id is not a string", data);
1095
- return false;
1096
- }
1097
- if ("id" in data && typeof data.id !== "string") {
1098
- logger_default.logDebug("[spiffy-ai] isOrgConfig: id is not a string", data);
1099
- return false;
1100
- }
1101
- return true;
1102
- };
1103
-
1104
- //#endregion
1105
- //#region src/application/models/guards/api/isApiOrgConfigResults.ts
1106
- const isApiOrgConfigExperiment = (data) => {
1107
- if (data == null || typeof data !== "object") {
1108
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: data is not an object", void 0, { data });
1109
- return false;
1110
- }
1111
- if ("group" in data && typeof data.group !== "string" && data.group !== void 0) {
1112
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: group is not a string or undefined", void 0, { data });
1113
- return false;
1114
- }
1115
- if ("group_name" in data && typeof data.group_name !== "string" && data.group_name !== void 0) {
1116
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: group_name is not a string", void 0, { data });
1117
- return false;
1118
- }
1119
- if ("name" in data && typeof data.name !== "string" && data.name !== void 0) {
1120
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: name is not a string", void 0, { data });
1121
- return false;
1122
- }
1123
- if ("rule_id" in data && typeof data.rule_id !== "string" && data.rule_id !== void 0) {
1124
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: rule_id is not a string", void 0, { data });
1125
- return false;
1126
- }
1127
- if ("value" in data && typeof data.value !== "object" && data.value !== void 0) {
1128
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigExperiment: value is not an object", void 0, { data });
1129
- return false;
1130
- }
1131
- return true;
1132
- };
1133
- const isApiOrgConfigFeatureGate = (data) => {
1134
- if (data == null || typeof data !== "object") {
1135
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: data is not an object", void 0, { data });
1136
- return false;
1137
- }
1138
- if ("name" in data && typeof data.name !== "string" && data.name !== void 0) {
1139
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: name is not a string", void 0, { data });
1140
- return false;
1141
- }
1142
- if ("rule_id" in data && typeof data.rule_id !== "string" && data.rule_id !== void 0) {
1143
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: rule_id is not a string", void 0, { data });
1144
- return false;
1145
- }
1146
- if ("value" in data && typeof data.value !== "boolean" && data.value !== void 0) {
1147
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigFeatureGate: value is not a boolean", void 0, { data });
1148
- return false;
1149
- }
1150
- return true;
1151
- };
1152
- const isApiOrganization = (data) => {
1153
- if (data == null || typeof data !== "object") {
1154
- logger_default.logDebug("[spiffy-ai] isApiOrganization: data is not an object", void 0, { data });
1155
- return false;
1156
- }
1157
- if (!("id" in data) || typeof data.id !== "string") {
1158
- logger_default.logDebug("[spiffy-ai] isApiOrganization: id is not a string", void 0, { data });
1159
- return false;
1160
- }
1161
- if (!("display_name" in data) || typeof data.display_name !== "string") {
1162
- logger_default.logDebug("[spiffy-ai] isApiOrganization: display_name is not a string", void 0, { data });
1163
- return false;
1164
- }
1165
- if (!("domain" in data) || typeof data.domain !== "string") {
1166
- logger_default.logDebug("[spiffy-ai] isApiOrganization: domain is not a string", void 0, { data });
1167
- return false;
1168
- }
1169
- if (!("short_name" in data) || typeof data.short_name !== "string") {
1170
- logger_default.logDebug("[spiffy-ai] isApiOrganization: short_name is not a string", void 0, { data });
1171
- return false;
1172
- }
1173
- if (!("status" in data) || !Object.values(OrganizationStatusEnum).includes(data.status)) {
1174
- logger_default.logDebug("[spiffy-ai] isApiOrganization: status is not a valid OrganizationStatusEnum value", void 0, { data });
1175
- return false;
1176
- }
1177
- if ("created_at" in data && !(data.created_at instanceof Date) && typeof data.created_at !== "string" && data.created_at !== void 0) {
1178
- logger_default.logDebug("[spiffy-ai] isApiOrganization: created_at is not a Date", void 0, { data });
1179
- return false;
1180
- }
1181
- if ("updated_at" in data && !(data.updated_at instanceof Date) && typeof data.updated_at !== "string" && data.updated_at !== void 0) {
1182
- logger_default.logDebug("[spiffy-ai] isApiOrganization: updated_at is not a Date", void 0, { data });
1183
- return false;
1184
- }
1185
- return true;
1186
- };
1187
- const isApiOrgConfigOrganizationSettings = (data) => {
1188
- if (data == null || typeof data !== "object") {
1189
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigOrganizationSettings: data is not an object", void 0, { data });
1190
- return false;
1191
- }
1192
- if (!("org" in data) || !isApiOrganization(data.org)) {
1193
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigOrganizationSettings: org is not an object", void 0, { data });
1194
- return false;
1195
- }
1196
- return true;
1197
- };
1198
- /**
1199
- *
1200
- * @param data
1201
- * @returns
1202
- */
1203
- const isApiOrgConfigResults = (data) => {
1204
- if (data == null || typeof data !== "object") {
1205
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: data is not an object", void 0, { data });
1206
- return false;
1207
- }
1208
- if (!("configs" in data) || !Array.isArray(data.configs) || !data.configs.every((config) => isApiOrganizationConfig(config))) {
1209
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: configs is not an array", void 0, { data });
1210
- return false;
1211
- }
1212
- if ("experiments" in data && data.experiments !== void 0 && (!Array.isArray(data.experiments) || !data.experiments.every((exp) => isApiOrgConfigExperiment(exp)))) {
1213
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: experiments is not an array or contains invalid items", void 0, { data });
1214
- return false;
1215
- }
1216
- if (!("gates" in data) || !Array.isArray(data.gates) || !data.gates.every((gate) => isApiOrgConfigFeatureGate(gate))) {
1217
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: gates is not an array or contains invalid items", void 0, { data });
1218
- return false;
1219
- }
1220
- if (!("org" in data) || !isApiOrgConfigOrganizationSettings(data.org)) {
1221
- logger_default.logDebug("[spiffy-ai] isApiOrgConfigResults: org is not an object or has invalid fields", void 0, { data });
1222
- return false;
1223
- }
1224
- return true;
1225
- };
1226
-
1227
- //#endregion
1228
- //#region src/application/models/validators/validateOrganizationConfig.ts
1229
- const validateOrganizationConfig = (data) => {
1230
- if (!isApiOrganizationConfig(data)) return;
1231
- return {
1232
- id: data.id,
1233
- createdAt: data.created_at.toISOString(),
1234
- namespace: data.namespace,
1235
- organizationId: data.organization_id,
1236
- isLatest: data.is_latest,
1237
- version: data.version,
1238
- updatedAt: data.updated_at.toISOString(),
1239
- config: {
1240
- amplitude: data.config.amplitude ? {
1241
- sessionReplayEnabled: data.config.amplitude.session_replay_enabled,
1242
- sessionReplaySampleRate: data.config.amplitude.session_replay_sample_rate,
1243
- trackingEnabled: data.config.amplitude.tracking_enabled
1244
- } : void 0,
1245
- customerService: data.config.customer_service ? { provider: data.config.customer_service.provider } : void 0,
1246
- googleAnalytics: data.config.google_analytics ? { measurementId: data.config.google_analytics.measurement_id } : void 0
1247
- }
1248
- };
1249
- };
1250
-
1251
- //#endregion
1252
- //#region src/application/models/validators/validateOrgConfigResults.ts
1253
- /**
1254
- *
1255
- * @param data
1256
- * @returns
1257
- */
1258
- const validateOrgConfigResults = (data) => {
1259
- if (!isApiOrgConfigResults(data)) return;
1260
- return {
1261
- configs: data.configs.map((config) => validateOrganizationConfig(config)).filter((config) => config != null),
1262
- experiments: data.experiments.map((experiment) => ({
1263
- group: experiment.group,
1264
- groupName: experiment.group_name,
1265
- name: experiment.name,
1266
- ruleId: experiment.rule_id,
1267
- value: experiment.value
1268
- })),
1269
- gates: data.gates.map((gate) => ({
1270
- groupName: gate.group_name,
1271
- name: gate.name,
1272
- ruleId: gate.rule_id,
1273
- value: gate.value
1274
- })),
1275
- org: {
1276
- org: {
1277
- id: data.org.org.id,
1278
- displayName: data.org.org.display_name,
1279
- domain: data.org.org.domain,
1280
- shortName: data.org.org.short_name,
1281
- status: data.org.org.status,
1282
- createdAt: data.org.org.created_at?.toISOString(),
1283
- updatedAt: data.org.org.updated_at?.toISOString()
1284
- },
1285
- settings: {}
1286
- }
1287
- };
1288
- };
1289
-
1290
- //#endregion
1291
- //#region src/application/service/windowDataLayerService.ts
1292
- var WindowDataLayerService = class WindowDataLayerService {
1293
- constructor(gaConfig) {
1294
- this.gaConfig = gaConfig;
1295
- this.dataLayer = window.dataLayer;
1296
- this.originalDataLayerPush = this.dataLayer?.push;
1297
- this.merchantGoogleMeasurementId = this.gaConfig.measurementId || "default";
1298
- }
1299
- /**
1300
- * Pushes data to the dataLayer
1301
- * @param data
1302
- * data has the shape: { event: 'event_name', ... }
1303
- * Example:
1304
- * {
1305
- * "event": "add_to_cart",
1306
- * "currency": "USD",
1307
- * "value": 30.03,
1308
- * "items": [
1309
- * {
1310
- * "item_id": "SKU_12345",
1311
- * "item_name": "Stan and Friends Tee",
1312
- * "affiliation": "Google Merchandise Store",
1313
- * "coupon": "SUMMER_FUN",
1314
- * "discount": 2.22,
1315
- * "index": 0,
1316
- * "item_brand": "Google",
1317
- * "item_category": "Apparel",
1318
- * "item_category2": "Adult",
1319
- * "item_category3": "Shirts",
1320
- * "item_category4": "Crew",
1321
- * "item_category5": "Short sleeve",
1322
- * "item_list_id": "related_products",
1323
- * "item_list_name": "Related Products",
1324
- * "item_variant": "green",
1325
- * "location_id": "ChIJIQBpAG2ahYAR_6128GcTUEo",
1326
- * "price": 10.01,
1327
- * "quantity": 3
1328
- * }
1329
- * ]
1330
- * }
1331
- */
1332
- push(data) {
1333
- this.dataLayer?.push(data);
1334
- }
1335
- static isDataLayerAvailable() {
1336
- const windowDataLayer = window.dataLayer;
1337
- if (windowDataLayer && windowDataLayer.push) return true;
1338
- logger_default.logDebug("[spiffy-ai] DataLayerEventsListener dataLayer not available");
1339
- return false;
1340
- }
1341
- static tryFlattenArguments(args) {
1342
- function isArguments(obj) {
1343
- return obj !== void 0 && Object.prototype.toString.call(obj) === "[object Arguments]";
1344
- }
1345
- try {
1346
- const all_arguments = [];
1347
- if (args.length > 0) for (let i = 0; i < args.length; i++) {
1348
- const arg = args[i];
1349
- if (isArguments(arg)) {
1350
- const flattened = WindowDataLayerService.tryFlattenArguments(arg);
1351
- all_arguments.push(...flattened);
1352
- } else all_arguments.push(arguments[i]);
1353
- }
1354
- return all_arguments;
1355
- } catch {
1356
- return args;
1357
- }
1358
- }
1359
- wrapWithProxyMethod(methodName, callback) {
1360
- if (!this.dataLayer) {
1361
- logger_default.logWarn("DataLayerEventsListener dataLayer not available", void 0);
1362
- return;
1363
- }
1364
- const originalMethod = this.dataLayer[methodName];
1365
- this.dataLayer[methodName] = function() {
1366
- try {
1367
- callback.apply(this, arguments);
1368
- } catch (e) {
1369
- logger_default.logError(`Error in dataLayer.${methodName}: `, e);
1370
- } finally {
1371
- originalMethod.apply(this, arguments);
1372
- }
1373
- };
1374
- }
1375
- static getSingletonInstanceOf(gaConfig) {
1376
- if (!WindowDataLayerService.instance) WindowDataLayerService.instance = new WindowDataLayerService(gaConfig);
1377
- return WindowDataLayerService.instance;
1378
- }
1379
- sendToGoogleAnalyticsCircularEventsSafe(eventName, eventProps) {
1380
- const This = this;
1381
- function doesEventExistInDataLayer(eventName$1) {
1382
- return This.dataLayer?.find((event) => event.event === eventName$1);
1383
- }
1384
- if (doesEventExistInDataLayer(eventName)) {
1385
- logger_default.logDebug(`[spiffy-ai] Event ${eventName} already exists in dataLayer. Skipping Google Analytics event.`);
1386
- return;
1387
- }
1388
- function gtag() {
1389
- if (This.originalDataLayerPush) This.originalDataLayerPush(arguments);
1390
- else logger_default.logDebug("No originalDataLayerPush found - no metrics being logged");
1391
- }
1392
- gtag("event", eventName, {
1393
- event: eventName,
1394
- send_to: this.merchantGoogleMeasurementId,
1395
- ...eventProps
1396
- });
1397
- }
1398
- static {
1399
- this.getGoogleAnalyticsClientId = () => {
1400
- try {
1401
- const gaCookie = document.cookie.split(";").find((c) => c.trim().startsWith("_ga="));
1402
- if (!gaCookie) {
1403
- logger_default.logWarn("[spiffy-ai] No GA cookie found", void 0);
1404
- return;
1405
- }
1406
- return gaCookie.split(".").slice(2).join(".");
1407
- } catch (error) {
1408
- logger_default.logError("Error getting GA client ID:", error);
1409
- return;
1410
- }
1411
- };
1412
- }
1413
- };
1414
-
1415
- //#endregion
1416
- //#region src/application/service/userIdentityService.ts
1417
- const getUserAgentDetails = () => {
1418
- const result = new UAParser().getResult();
1419
- return {
1420
- os: result?.os?.name,
1421
- osVersion: result?.os?.version,
1422
- deviceBrand: result?.device?.vendor,
1423
- deviceManufacturer: result?.device?.vendor,
1424
- deviceModel: result?.device?.model,
1425
- browser: result?.browser?.name,
1426
- browserVersion: result?.browser?.version,
1427
- userAgent: result?.ua
1428
- };
1429
- };
1430
- var UserIdentityService = class UserIdentityService {
1431
- static {
1432
- this.USER_ID_OVERRIDE_KEY = "v1-spiffy-user-id-override";
1433
- }
1434
- static {
1435
- this.USER_ID_DEFAULT_KEY = "v1-spiffy-user-id-default";
1436
- }
1437
- static async identifyUser() {
1438
- try {
1439
- const cdpUserId = WindowDataLayerService.getGoogleAnalyticsClientId();
1440
- const userId = UserIdentityService.getUserIdOrDefault();
1441
- const userAgentDetails = getUserAgentDetails();
1442
- if (!cdpUserId) {
1443
- logger_default.logWarn("[spiffy-ai] No GA Client ID found, skipping identifyUser", void 0);
1444
- return;
1445
- }
1446
- await api_default.identifyUser(userId, cdpUserId, userAgentDetails);
1447
- } catch (error) {
1448
- logger_default.logError("[spiffy-ai] Error identifying user", error);
1449
- }
1450
- }
1451
- static getUserIdOrDefault() {
1452
- const userIdOverride = UserIdentityService.getUserIdOverrideFromLocalStorage();
1453
- if (userIdOverride) return userIdOverride;
1454
- const defaultUserId = UserIdentityService.getUserIdDefaultFromLocalStorage();
1455
- if (defaultUserId) return defaultUserId;
1456
- return this.setUserIdDefaultInLocalStorage(`spiffy-user-id-${v4()}`);
1457
- }
1458
- static getUserIdOverrideFromLocalStorage() {
1459
- return LocalStorageService.getLocalStorage()?.getItem(UserIdentityService.USER_ID_OVERRIDE_KEY) ?? void 0;
1460
- }
1461
- static getUserIdDefaultFromLocalStorage() {
1462
- return LocalStorageService.getLocalStorage()?.getItem(UserIdentityService.USER_ID_DEFAULT_KEY) ?? void 0;
1463
- }
1464
- static setUserIdDefaultInLocalStorage(userId) {
1465
- logger_default.logInfo(`setUserIdDefaultInLocalStorage - Setting user_id=${userId}`);
1466
- LocalStorageService.getLocalStorage()?.setItem(UserIdentityService.USER_ID_DEFAULT_KEY, userId);
1467
- window.dispatchEvent(new StorageEvent("storage", {
1468
- key: UserIdentityService.USER_ID_DEFAULT_KEY,
1469
- newValue: userId
1470
- }));
1471
- return userId;
1472
- }
1473
- static setUserIdOverrideInLocalStorage(userId) {
1474
- logger_default.logInfo(`setUserIdOverrideInLocalStorage - Setting user_id=${userId}`);
1475
- LocalStorageService.getLocalStorage()?.setItem(UserIdentityService.USER_ID_OVERRIDE_KEY, userId);
1476
- window.dispatchEvent(new StorageEvent("storage", {
1477
- key: UserIdentityService.USER_ID_OVERRIDE_KEY,
1478
- newValue: userId
1479
- }));
1480
- return userId;
1481
- }
1482
- static clearUserIdOverrideInLocalStorage() {
1483
- logger_default.logInfo(`clearUserIdOverrideInLocalStorage - Clearing user_id`);
1484
- LocalStorageService.getLocalStorage()?.removeItem(UserIdentityService.USER_ID_OVERRIDE_KEY);
1485
- window.dispatchEvent(new StorageEvent("storage", {
1486
- key: UserIdentityService.USER_ID_OVERRIDE_KEY,
1487
- newValue: void 0
1488
- }));
1489
- }
1490
- };
1491
-
1492
- //#endregion
1493
- //#region src/application/models/graphql/queries/getMerchantFrontendConfigQuery.ts
1494
- const getMerchantFrontendConfigQuery = () => `
1495
- query ($version: "${configVersion()}") {
1496
- me {
1497
- getProductsConfigByVersion(version: $version) {
1498
- frontend {
1499
- values
1500
- }
1501
- }
1502
- }
1503
- }
1504
- `;
1505
-
1506
- //#endregion
1507
- //#region src/application/models/graphql/queries/getMerchantColorsQuery.ts
1508
- const getMerchantColorsQuery = () => `
1509
- query ($version: "${configVersion()}") {
1510
- me {
1511
- getProductsConfigByVersion(version: $version) {
1512
- colors {
1513
- values
1514
- }
1515
- }
1516
- }
1517
- }
1518
- `;
1519
-
1520
- //#endregion
1521
- //#region src/application/models/graphql/queries/getMerchantOrgIdQuery.ts
1522
- const getMerchantOrgIdQuery = `
1523
- query {
1524
- me {
1525
- org {
1526
- id
1527
- }
1528
- }
1529
- }
1530
- `;
1531
-
1532
- //#endregion
1533
- //#region src/application/models/guards/graphQL/isGraphQLColorsConfig.ts
1534
- const REQUIRED_COLOR_FIELDS = [
1535
- "accent_primary",
1536
- "accent_secondary",
1537
- "background_dark",
1538
- "background_light",
1539
- "background_primary",
1540
- "background_saturated",
1541
- "background_secondary",
1542
- "background_secondary_dark",
1543
- "background_tertiary",
1544
- "border_dark",
1545
- "border_light",
1546
- "border_medium",
1547
- "border_outline",
1548
- "text_accent",
1549
- "text_light",
1550
- "text_link",
1551
- "text_primary",
1552
- "text_secondary"
1553
- ];
1554
- const isGraphQLColorsConfig = (data) => {
1555
- if (typeof data !== "object" || data === null) {
1556
- logger_default.logError("Invalid graphql response for colors config", void 0, { data });
1557
- return false;
1558
- }
1559
- const missingFields = REQUIRED_COLOR_FIELDS.filter((field) => !(field in data) || typeof data[field] !== "string");
1560
- if (missingFields.length === REQUIRED_COLOR_FIELDS.length) {
1561
- logger_default.logError("All color fields are missing or null", void 0);
1562
- return false;
1563
- }
1564
- if (missingFields.length > 0) {
1565
- logger_default.logError("Missing or invalid color fields", void 0, {
1566
- data,
1567
- missingFields
1568
- });
1569
- return false;
1570
- }
1571
- return true;
1572
- };
1573
-
1574
- //#endregion
1575
- //#region src/application/models/validators/validateGraphQLColorsConfig.ts
1576
- const validateGraphQLColorsConfig = (data) => {
1577
- if (!isGraphQLColorsConfig(data)) return;
1578
- return {
1579
- [ColorNames.TextPrimary]: data.text_primary,
1580
- [ColorNames.TextSecondary]: data.text_secondary,
1581
- [ColorNames.TextAccent]: data.text_accent,
1582
- [ColorNames.TextLink]: data.text_link,
1583
- [ColorNames.TextLight]: data.text_light,
1584
- [ColorNames.BackgroundPrimary]: data.background_primary,
1585
- [ColorNames.BackgroundSecondary]: data.background_secondary,
1586
- [ColorNames.BackgroundSecondaryDark]: data.background_secondary_dark,
1587
- [ColorNames.BackgroundTertiary]: data.background_tertiary,
1588
- [ColorNames.BackgroundDark]: data.background_dark,
1589
- [ColorNames.BorderLight]: data.border_light,
1590
- [ColorNames.BorderMedium]: data.border_medium,
1591
- [ColorNames.BorderDark]: data.border_dark,
1592
- [ColorNames.BorderOutline]: data.border_outline,
1593
- [ColorNames.AccentPrimary]: data.accent_primary,
1594
- [ColorNames.AccentSecondary]: data.accent_secondary,
1595
- [ColorNames.BackgroundLight]: data.background_light,
1596
- [ColorNames.BackgroundSaturated]: data.background_saturated
1597
- };
1598
- };
1599
-
1600
- //#endregion
1601
- //#region src/application/models/utils/snakeToCamelTransformer.ts
1602
- /**
1603
- * Generic utility to transform snake_case object keys to camelCase at runtime.
1604
- * This is the runtime equivalent of the CamelCasedPropertiesDeep type utility.
1605
- */
1606
- const PRESERVED_ACRONYMS = [
1607
- "PLP",
1608
- "PDP",
1609
- "SVG"
1610
- ];
1611
- /**
1612
- * Converts a snake_case string to camelCase
1613
- * Handles specific acronyms like PLP and PDP correctly
1614
- */
1615
- const toCamelCase = (str) => {
1616
- let processedStr = str;
1617
- for (const acronym of PRESERVED_ACRONYMS) {
1618
- const regex = new RegExp(`_${acronym}_?`, "gi");
1619
- if (processedStr.match(regex)) processedStr = processedStr.replace(regex, (v) => v.endsWith("_") ? `${acronym}_` : `${acronym}`);
1620
- }
1621
- return processedStr.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
1622
- };
1623
- /**
1624
- * Recursively transforms all object keys from snake_case to camelCase
1625
- */
1626
- const transformSnakeToCamel = (obj) => {
1627
- if (obj === null || obj === void 0) return obj;
1628
- if (Array.isArray(obj)) return obj.map((val) => transformSnakeToCamel(val));
1629
- if (typeof obj === "object") {
1630
- const result = {};
1631
- for (const [key, value] of Object.entries(obj)) {
1632
- const camelKey = toCamelCase(key);
1633
- result[camelKey] = transformSnakeToCamel(value);
1634
- }
1635
- return result;
1636
- }
1637
- return obj;
1638
- };
1639
-
1640
- //#endregion
1641
- //#region src/application/models/validators/validateGraphQLFrontendConfig.ts
1642
- const validateAndTransformPageVariants = (config) => {
1643
- const { variantChecks, widgetMounting,...rest } = transformSnakeToCamel(config);
1644
- const variantTests = Array.isArray(variantChecks) ? variantChecks.map(({ checkType,...restCheck }) => ({
1645
- ...restCheck,
1646
- testType: checkType
1647
- })) : [];
1648
- const normalizedWidgetMounting = Array.isArray(widgetMounting) ? widgetMounting.map(({ mountingPointWidgets,...restMounting }) => ({
1649
- ...restMounting,
1650
- ...Array.isArray(mountingPointWidgets) ? { mountingPointWidgets: mountingPointWidgets.map(({ checks,...restWidget }) => ({
1651
- ...restWidget,
1652
- tests: Array.isArray(checks) ? checks.map(({ checkType,...restCheck }) => ({
1653
- ...restCheck,
1654
- testType: checkType
1655
- })) : []
1656
- })) } : {}
1657
- })) : [];
1658
- const normalizedConfig = {
1659
- ...rest,
1660
- ...variantTests ? { variantTests } : {},
1661
- ...normalizedWidgetMounting ? { widgetMounting: normalizedWidgetMounting } : {}
1662
- };
1663
- const variantId = normalizedConfig.variantId;
1664
- const variantType = normalizedConfig.variantType;
1665
- if (typeof variantId !== "string" || !variantId) throw new Error(`Missing or invalid variantId for pageVariant`);
1666
- if (typeof variantType !== "string" || !variantType) throw new Error(`Missing or invalid variantType for pageVariant '${variantId}'`);
1667
- if (!Array.isArray(variantTests)) throw new Error(`Missing or invalid variantTests for pageVariant '${variantId}'. Must be an array`);
1668
- for (const test$1 of variantTests) {
1669
- if (!test$1.testType || typeof test$1.testType !== "string") throw new Error(`Invalid variantTest.testType for pageVariant '${variantId}'`);
1670
- if (!Object.values(PageVariantTestType).includes(test$1.testType)) throw new Error(`Invalid testType '${test$1.testType}' for pageVariant '${variantId}'. Valid types: ${Object.values(PageVariantTestType).join(", ")}`);
1671
- }
1672
- if (!Array.isArray(normalizedWidgetMounting)) throw new Error(`Missing or invalid widgetMounting for pageVariant '${variantId}'. Must be an array`);
1673
- for (const mounting of normalizedWidgetMounting) {
1674
- if (typeof mounting.mountingConfigId !== "string" || !mounting.mountingConfigId) throw new Error(`Invalid mountingConfigId in widgetMounting for pageVariant '${variantId}'`);
1675
- if (mounting.widgetConfigId && typeof mounting.widgetConfigId !== "string") throw new Error(`Invalid widgetConfigId in widgetMounting for pageVariant '${variantId}'`);
1676
- if (mounting.mountingPointWidgets) for (const widget of mounting.mountingPointWidgets) {
1677
- if (typeof widget.widgetConfigId !== "string" || !widget.widgetConfigId) throw new Error(`Invalid widgetConfigId in mountingPointWidgets for pageVariant '${variantId}'`);
1678
- if (!Array.isArray(widget.tests)) throw new Error(`Invalid or missing tests in mountingPointWidgets for pageVariant '${variantId}'`);
1679
- }
1680
- }
1681
- if (variantType === "plp") {
1682
- if (typeof normalizedConfig.plpIdExtractor !== "string" || !normalizedConfig.plpIdExtractor) throw new Error(`Missing or invalid plpIdExtractor for PLP pageVariant '${variantId}'`);
1683
- }
1684
- if (variantType === "pdp") {
1685
- if (typeof normalizedConfig.productIdExtractor !== "string" || !normalizedConfig.productIdExtractor) throw new Error(`Missing or invalid productIdExtractor for PDP pageVariant '${variantId}'`);
1686
- if (normalizedConfig.parentProductIdExtractor && typeof normalizedConfig.parentProductIdExtractor !== "string") throw new Error(`Invalid parentProductIdExtractor for PDP pageVariant '${variantId}'. Must be string if provided`);
1687
- }
1688
- return normalizedConfig;
1689
- };
1690
- const validateAndTransformMountingConfig = (config, configKey) => {
1691
- const normalizedConfig = { ...config };
1692
- if (normalizedConfig.checkId && !normalizedConfig.testId) {
1693
- normalizedConfig.testId = normalizedConfig.checkId;
1694
- delete normalizedConfig.checkId;
1695
- }
1696
- if (typeof normalizedConfig.mountingConfigId !== "string" || !normalizedConfig.mountingConfigId) throw new Error(`Missing or invalid mountingConfigId for config '${configKey}'`);
1697
- if (typeof normalizedConfig.containerId !== "string" || !normalizedConfig.containerId) throw new Error(`Missing or invalid containerId for config '${configKey}'`);
1698
- if (typeof normalizedConfig.testId !== "string" || !normalizedConfig.testId) throw new Error(`Missing or invalid testId for config '${configKey}'`);
1699
- if (!normalizedConfig.insertionPoint || typeof normalizedConfig.insertionPoint !== "object" || Array.isArray(normalizedConfig.insertionPoint)) throw new Error(`Missing or invalid insertionPoint for config '${configKey}'`);
1700
- const insertionPoint = normalizedConfig.insertionPoint;
1701
- if (typeof insertionPoint.selector !== "string" || !insertionPoint.selector) throw new Error(`Missing or invalid insertionPoint.selector for config '${configKey}'`);
1702
- if (typeof insertionPoint.insertionType !== "string" || !insertionPoint.insertionType) throw new Error(`Missing or invalid insertionPoint.insertionType for config '${configKey}'`);
1703
- if (!Object.values(DOMInsertionType).includes(insertionPoint.insertionType)) throw new Error(`Invalid insertionPoint.insertionType '${insertionPoint.insertionType}' for config '${configKey}'. Valid types: ${Object.values(DOMInsertionType).join(", ")}`);
1704
- if (insertionPoint.selectionIndex != null && typeof insertionPoint.selectionIndex !== "number") throw new Error(`Invalid insertionPoint.selectionIndex for config '${configKey}'. Must be a number or null/undefined`);
1705
- let parentInsertionPoint;
1706
- if (normalizedConfig.parentInsertionPoint) {
1707
- if (typeof normalizedConfig.parentInsertionPoint !== "object" || Array.isArray(normalizedConfig.parentInsertionPoint)) throw new Error(`Invalid parentInsertionPoint for config '${configKey}'. Must be an object`);
1708
- const parentPoint = normalizedConfig.parentInsertionPoint;
1709
- if (typeof parentPoint.selector !== "string" || !parentPoint.selector) throw new Error(`Missing or invalid parentInsertionPoint.selector for config '${configKey}'`);
1710
- if (typeof parentPoint.insertionType !== "string" || !parentPoint.insertionType) throw new Error(`Missing or invalid parentInsertionPoint.insertionType for config '${configKey}'`);
1711
- if (!Object.values(DOMInsertionType).includes(parentPoint.insertionType)) throw new Error(`Invalid parentInsertionPoint.insertionType '${parentPoint.insertionType}' for config '${configKey}'. Valid types: ${Object.values(DOMInsertionType).join(", ")}`);
1712
- if (parentPoint.selectionIndex != null && typeof parentPoint.selectionIndex !== "number") throw new Error(`Invalid parentInsertionPoint.selectionIndex for config '${configKey}'. Must be a number or null/undefined`);
1713
- parentInsertionPoint = {
1714
- selector: parentPoint.selector,
1715
- insertionType: parentPoint.insertionType,
1716
- selectionIndex: parentPoint.selectionIndex
1717
- };
1718
- }
1719
- let wrappingElement;
1720
- if (normalizedConfig.wrappingElement) {
1721
- if (typeof normalizedConfig.wrappingElement !== "object" || Array.isArray(normalizedConfig.wrappingElement)) throw new Error(`Invalid wrappingElement for config '${configKey}'. Must be an object`);
1722
- const wrapping = normalizedConfig.wrappingElement;
1723
- if (typeof wrapping.className !== "string" || !wrapping.className) throw new Error(`Missing or invalid wrappingElement.className for config '${configKey}'`);
1724
- if (typeof wrapping.element !== "string" || !wrapping.element) throw new Error(`Missing or invalid wrappingElement.element for config '${configKey}'`);
1725
- if (typeof wrapping.insertionType !== "string" || !wrapping.insertionType) throw new Error(`Missing or invalid wrappingElement.insertionType for config '${configKey}'`);
1726
- if (!Object.values(DOMInsertionType).includes(wrapping.insertionType)) throw new Error(`Invalid wrappingElement.insertionType '${wrapping.insertionType}' for config '${configKey}'. Valid types: ${Object.values(DOMInsertionType).join(", ")}`);
1727
- wrappingElement = {
1728
- className: wrapping.className,
1729
- element: wrapping.element,
1730
- insertionType: wrapping.insertionType
1731
- };
1732
- }
1733
- if (normalizedConfig.divCheckSelector != null && typeof normalizedConfig.divCheckSelector !== "string") throw new Error(`Invalid divCheckSelector for config '${configKey}'. Must be a string or null/undefined`);
1734
- if (normalizedConfig.className != null && typeof normalizedConfig.className !== "string") throw new Error(`Invalid className for config '${configKey}'. Must be a string or null/undefined`);
1735
- if (normalizedConfig.suppressionSelector != null && typeof normalizedConfig.suppressionSelector !== "string") throw new Error(`Invalid suppressionSelector for config '${configKey}'. Must be a string or null/undefined`);
1736
- 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`);
1737
- 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`);
1738
- let gridInsertionType;
1739
- if (normalizedConfig.gridInsertionType) {
1740
- if (typeof normalizedConfig.gridInsertionType !== "string" || !normalizedConfig.gridInsertionType) throw new Error(`Invalid gridInsertionType for config '${configKey}'. Must be a string`);
1741
- if (!Object.values(GridInsertionType).includes(normalizedConfig.gridInsertionType)) throw new Error(`Invalid gridInsertionType '${normalizedConfig.gridInsertionType}' for config '${configKey}'. Valid types: ${Object.values(GridInsertionType).join(", ")}`);
1742
- gridInsertionType = normalizedConfig.gridInsertionType;
1743
- }
1744
- const result = {
1745
- mountingConfigId: normalizedConfig.mountingConfigId,
1746
- containerId: normalizedConfig.containerId,
1747
- testId: normalizedConfig.testId,
1748
- insertionPoint: {
1749
- selector: insertionPoint.selector,
1750
- insertionType: insertionPoint.insertionType,
1751
- ...insertionPoint.selectionIndex != null && { selectionIndex: insertionPoint.selectionIndex }
1752
- }
1753
- };
1754
- if (parentInsertionPoint) result.parentInsertionPoint = parentInsertionPoint;
1755
- if (gridInsertionType) result.gridInsertionType = gridInsertionType;
1756
- if (wrappingElement) result.wrappingElement = wrappingElement;
1757
- if (normalizedConfig.divCheckSelector) result.divCheckSelector = normalizedConfig.divCheckSelector;
1758
- if (normalizedConfig.className) result.className = normalizedConfig.className;
1759
- if (normalizedConfig.suppressionSelector) result.suppressionSelector = normalizedConfig.suppressionSelector;
1760
- if (normalizedConfig.dataAttributes) result.dataAttributes = normalizedConfig.dataAttributes;
1761
- if (normalizedConfig.style) result.style = normalizedConfig.style;
1762
- return result;
1763
- };
1764
- const validateAndTransformWidgetConfig = (config, configKey) => {
1765
- const normalizedConfig = transformSnakeToCamel(config);
1766
- if (typeof normalizedConfig.widgetConfigId !== "string" || !normalizedConfig.widgetConfigId) throw new Error(`Missing or invalid widgetConfigId for widget config '${configKey}'`);
1767
- if (typeof normalizedConfig.type !== "string" || !normalizedConfig.type) throw new Error(`Missing or invalid type for widget config '${configKey}'`);
1768
- if (normalizedConfig.contentId != null && typeof normalizedConfig.contentId !== "string") throw new Error(`Invalid contentId for widget config '${configKey}'. Must be a string or null/undefined`);
1769
- return normalizedConfig;
1770
- };
1771
- const validateGraphQLFrontendConfig = (data) => {
1772
- if (data === null || data === void 0) return;
1773
- if (typeof data !== "object" || Array.isArray(data)) {
1774
- logger_default.logWarn("Invalid GraphQL frontend config data: not an object", void 0, { data });
1775
- return;
1776
- }
1777
- const obj = data;
1778
- if ("merchant_override_css" in obj && typeof obj.merchant_override_css !== "string" && obj.merchant_override_css !== null) {
1779
- logger_default.logWarn("Invalid GraphQL frontend config data: merchant_override_css must be a string or null", void 0, { data });
1780
- return;
1781
- }
1782
- if ("page_variants" in obj) {
1783
- if (obj.page_variants !== void 0 && obj.page_variants !== null && !Array.isArray(obj.page_variants)) {
1784
- logger_default.logWarn("Invalid GraphQL frontend config data: page_variants must be an array or null/undefined", void 0, { data });
1785
- return;
1786
- }
1787
- }
1788
- if ("mounting_configs" in obj) {
1789
- if (obj.mounting_configs !== void 0 && obj.mounting_configs !== null && !Array.isArray(obj.mounting_configs)) {
1790
- logger_default.logWarn("Invalid GraphQL frontend config data: mounting_configs must be an array or null/undefined", void 0, { data });
1791
- return;
1792
- }
1793
- }
1794
- if ("widget_configs" in obj) {
1795
- if (obj.widget_configs !== void 0 && obj.widget_configs !== null && !Array.isArray(obj.widget_configs)) {
1796
- logger_default.logWarn("Invalid GraphQL frontend config data: widget_configs must be an array or null/undefined", void 0, { data });
1797
- return;
1798
- }
1799
- }
1800
- if ("ui_configs" in obj && typeof obj.ui_configs !== "object" && obj.ui_configs !== null) {
1801
- logger_default.logWarn("Invalid GraphQL frontend config data: ui_configs must be an object or null/undefined", void 0, { data });
1802
- return;
1803
- }
1804
- try {
1805
- const transformedData = transformSnakeToCamel(obj);
1806
- if (transformedData.pageVariants && Array.isArray(transformedData.pageVariants)) {
1807
- const pageVariantsArray = transformedData.pageVariants;
1808
- const validatedPageVariants = [];
1809
- for (const variant of pageVariantsArray) if (variant && typeof variant === "object" && typeof variant.variantId === "string") try {
1810
- const validatedVariant = validateAndTransformPageVariants(variant);
1811
- validatedPageVariants.push(validatedVariant);
1812
- } catch (error) {
1813
- logger_default.logWarn("Invalid page variant, skipping", error, {
1814
- variantId: variant.variantId,
1815
- variant
1816
- });
1817
- }
1818
- else logger_default.logWarn("Invalid page variant structure, skipping", void 0, { variant });
1819
- transformedData.pageVariants = validatedPageVariants;
1820
- }
1821
- if (transformedData.mountingConfigs && Array.isArray(transformedData.mountingConfigs)) {
1822
- const mountingConfigsArray = transformedData.mountingConfigs;
1823
- const mountingConfigsRecord = {};
1824
- for (const item of mountingConfigsArray) if (item && typeof item.key === "string" && item.config && typeof item.config === "object") try {
1825
- const config = item.config;
1826
- const validatedConfig = validateAndTransformMountingConfig(config, item.key);
1827
- mountingConfigsRecord[item.key] = validatedConfig;
1828
- } catch (error) {
1829
- logger_default.logWarn("Invalid mounting config, skipping", error, {
1830
- configKey: item.key,
1831
- config: item.config
1832
- });
1833
- }
1834
- else logger_default.logWarn("Invalid mounting config item structure, skipping", void 0, { item });
1835
- transformedData.mountingConfigs = mountingConfigsRecord;
1836
- }
1837
- if (transformedData.widgetConfigs && Array.isArray(transformedData.widgetConfigs)) {
1838
- const widgetConfigsArray = transformedData.widgetConfigs;
1839
- const widgetConfigsRecord = {};
1840
- for (const item of widgetConfigsArray) if (item && typeof item.key === "string" && item.config && typeof item.config === "object") try {
1841
- const config = item.config;
1842
- const validatedConfig = validateAndTransformWidgetConfig(config, item.key);
1843
- widgetConfigsRecord[item.key] = validatedConfig;
1844
- } catch (error) {
1845
- logger_default.logWarn("Invalid widget config, skipping", error, {
1846
- configKey: item.key,
1847
- config: item.config
1848
- });
1849
- }
1850
- else logger_default.logWarn("Invalid widget config item structure, skipping", void 0, { item });
1851
- transformedData.widgetConfigs = widgetConfigsRecord;
1852
- }
1853
- return transformedData;
1854
- } catch (error) {
1855
- logger_default.logWarn("Failed to validate and transform GraphQL frontend config data", error, { data });
1856
- return;
1857
- }
1858
- };
1859
-
1860
- //#endregion
1861
- //#region src/application/models/validators/validateGraphQLOrgId.ts
1862
- const validateGraphQLOrgId = (data) => {
1863
- if (typeof data !== "string" || data === "") return;
1864
- return data;
1865
- };
1866
-
1867
- //#endregion
1868
- //#region src/application/utils/urlsParser.ts
1869
- const parseHref = (href) => {
1870
- try {
1871
- const url = new URL(href);
1872
- const urlSearchParams = new URLSearchParams(url.search);
1873
- return {
1874
- url,
1875
- urlSearchParams
1876
- };
1877
- } catch (e) {
1878
- return {
1879
- url: void 0,
1880
- urlSearchParams: void 0
1881
- };
1882
- }
1883
- };
1884
- const getQueryParam = (key) => {
1885
- return new URL(window.location.href).searchParams.get(key);
1886
- };
1887
- window.history.pushState(null, "");
1888
-
1889
- //#endregion
1890
- //#region src/adapters/spiffy/commerce/graphql.ts
1891
- const configVersion = () => getQueryParam("spiffy_config_version") || getQueryParam("envive_config_version") || "deployed";
1892
- const colorsAndFrontendConfigQuery = () => `
1893
- query ($version: String = "${configVersion()}") {
1894
- me {
1895
- getProductsConfigByVersion(version: $version) {
1896
- frontend { values }
1897
- colors { values }
1898
- }
1899
- }
1900
- }
1901
- `;
1902
- var GraphQLClient = class GraphQLClient {
1903
- static {
1904
- this.setInstance = (apiKey, basePath) => {
1905
- GraphQLClient.instance = new GraphQLClient(apiKey, basePath);
1906
- };
1907
- }
1908
- static {
1909
- this.getInstance = () => {
1910
- if (!GraphQLClient.instance) {
1911
- const apiKey = getAtomStore().get(apiKeyAtom);
1912
- GraphQLClient.instance = new GraphQLClient(apiKey, EnvironmentService.getApiEndpoint());
1913
- }
1914
- return GraphQLClient.instance;
1915
- };
1916
- }
1917
- constructor(apiKey, basePath) {
1918
- this.apiKey = apiKey;
1919
- this.basePath = basePath;
1920
- }
1921
- async executeQuery(query, variables) {
1922
- const response = await fetch(`${this.basePath}/v1/graphql`, {
1923
- method: "POST",
1924
- headers: {
1925
- "Content-Type": "application/json",
1926
- Authorization: `Bearer ${this.apiKey}`
1927
- },
1928
- body: JSON.stringify({
1929
- query,
1930
- variables
1931
- })
1932
- });
1933
- if (!response.ok) throw new Error(`GraphQL request failed: ${response.statusText}`);
1934
- const result = await response.json();
1935
- if (result.errors) throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`);
1936
- return result.data;
1937
- }
1938
- static {
1939
- this.getOrgId = async () => {
1940
- const query = getMerchantOrgIdQuery;
1941
- if (!query) throw new Error("Org id query is not defined");
1942
- const response = await GraphQLClient.getInstance().executeQuery(query);
1943
- return validateGraphQLOrgId(response.me.org?.id);
1944
- };
1945
- }
1946
- static {
1947
- this.getColorsAndFrontendConfig = async () => {
1948
- try {
1949
- const query = colorsAndFrontendConfigQuery();
1950
- if (!query) throw new Error("Colors and frontend config query is not defined");
1951
- const response = await GraphQLClient.getInstance().executeQuery(query);
1952
- return {
1953
- colorsConfig: validateGraphQLColorsConfig(response.me.getProductsConfigByVersion?.colors?.values),
1954
- frontendConfig: validateGraphQLFrontendConfig(response.me.getProductsConfigByVersion?.frontend?.values)
1955
- };
1956
- } catch (err) {
1957
- logger_default.logError("Error fetching graphql colors and frontend config", err);
1958
- return {
1959
- colorsConfig: void 0,
1960
- frontendConfig: void 0
1961
- };
1962
- }
1963
- };
1964
- }
1965
- static {
1966
- this.getFrontendConfig = async () => {
1967
- try {
1968
- const query = getMerchantFrontendConfigQuery();
1969
- if (!query) throw new Error("Frontend config query is not defined");
1970
- const response = await GraphQLClient.getInstance().executeQuery(query);
1971
- if (!response.me.getProductsConfigByVersion?.frontend) throw new Error("No frontend config found");
1972
- return validateGraphQLFrontendConfig(response.me.getProductsConfigByVersion.frontend.values);
1973
- } catch (err) {
1974
- logger_default.logError("Error fetching graphql frontend config", err);
1975
- return;
1976
- }
1977
- };
1978
- }
1979
- static {
1980
- this.getColors = async () => {
1981
- try {
1982
- const query = getMerchantColorsQuery();
1983
- if (!query) throw new Error("Colors query is not defined");
1984
- const response = await GraphQLClient.getInstance().executeQuery(query);
1985
- if (!response.me.getProductsConfigByVersion?.colors) throw new Error("No colors config found");
1986
- return isGraphQLColorsConfig(response.me.getProductsConfigByVersion.colors.values) ? response.me.getProductsConfigByVersion.colors.values : void 0;
1987
- } catch (err) {
1988
- logger_default.logError("Error fetching graphql colors config", err);
1989
- return;
1990
- }
1991
- };
1992
- }
1993
- };
1994
-
1995
- //#endregion
1996
- //#region src/application/service/sessionStorageService.ts
1997
- var SessionStorageService = class {
1998
- static setItem(key, value) {
1999
- sessionStorage.setItem(key, value);
2000
- window.dispatchEvent(new StorageEvent("storage", {
2001
- key,
2002
- newValue: value
2003
- }));
2004
- }
2005
- static getItem(key) {
2006
- return sessionStorage.getItem(key);
2007
- }
2008
- static getSessionStorage() {
2009
- const ls = window?.sessionStorage;
2010
- if (!ls) logger_default.logError("sessionStorage is not available", void 0);
2011
- return ls;
2012
- }
2013
- };
2014
-
2015
- //#endregion
2016
- //#region src/application/service/featureFlagService.ts
2017
- const FEATURE_FLAGS_STORAGE_KEY = "spiffy-feature-flags";
2018
- var FeatureFlagService = class {
2019
- constructor(featureGates) {
2020
- this.featureGates = featureGates;
2021
- this.getQueryParamFeatureGateOverrides = (featureGate) => {
2022
- const urlObj = new URL(window.location.href);
2023
- const params = new URLSearchParams(urlObj.search);
2024
- const value = Object.fromEntries(params.entries())[featureGate];
2025
- if (value != null) return value === "true";
2026
- };
2027
- this.getWindowFeatureGateOverrides = (featureGate) => {
2028
- const value = window._spiffy?.featureOverrides?.[String(featureGate)];
2029
- if (value != null) return value;
2030
- };
2031
- this.getStoredFeatureGateOverrides = (featureGate) => {
2032
- const featureFlags = SessionStorageService.getItem(FEATURE_FLAGS_STORAGE_KEY);
2033
- if (featureFlags) try {
2034
- return JSON.parse(featureFlags)[featureGate];
2035
- } catch (err) {
2036
- logger_default.logError("[spiffy-ai] getStoredFeatureGateOverrides: error parsing feature flags", err);
2037
- }
2038
- };
2039
- }
2040
- persistFeatureGateOverrides() {
2041
- const featureFlags = Object.values(FeatureGates).map((featureGate) => ({ [featureGate]: this.getFeatureFlagOverride(featureGate) })).filter((_, val) => val !== void 0).reduce((acc, curr) => ({
2042
- ...acc,
2043
- ...curr
2044
- }), {});
2045
- SessionStorageService.setItem(FEATURE_FLAGS_STORAGE_KEY, JSON.stringify(featureFlags));
2046
- }
2047
- getFeatureFlagOverride(featureGate) {
2048
- const queryOverride = this.getQueryParamFeatureGateOverrides(featureGate);
2049
- if (queryOverride != null) {
2050
- logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by URL param. New value: ${queryOverride}`);
2051
- return queryOverride;
2052
- }
2053
- const windowOverride = this.getWindowFeatureGateOverrides(featureGate);
2054
- if (windowOverride != null) {
2055
- logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by window param. New value: ${windowOverride}`);
2056
- return windowOverride;
2057
- }
2058
- const storedOverride = this.getStoredFeatureGateOverrides(featureGate);
2059
- if (storedOverride != null) {
2060
- logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} overridden by stored value. New value: ${storedOverride}`);
2061
- return storedOverride;
2062
- }
2063
- }
2064
- isFeatureGateEnabled(featureGate) {
2065
- const gateValue = this.featureGates.find((gate) => gate.name === featureGate);
2066
- const featureFlagOverride = this.getFeatureFlagOverride(featureGate);
2067
- if (featureFlagOverride !== void 0) return featureFlagOverride;
2068
- if (gateValue == null || gateValue.value == null) {
2069
- logger_default.logDebug(`[spiffy-ai] isFeatureGateEnabled featureGate:${featureGate} value is undefined - returning false`);
2070
- return false;
2071
- }
2072
- return gateValue.value;
2073
- }
2074
- isClientSessionEnabled() {
2075
- const gates = this.featureGates;
2076
- return gates == null || gates?.filter((gate) => gate.name === FeatureGates.IsClientSessionEnabled && gate.value === true).length > 0;
2077
- }
2078
- getFeatureFlags() {
2079
- return Object.fromEntries(Object.values(FeatureGates).map((featureGate) => [featureGate, this.isFeatureGateEnabled(featureGate)]));
2080
- }
2081
- };
2082
-
2083
- //#endregion
2084
- //#region src/atoms/org/orgAnalyticsConfig.ts
2085
- const internalOrgAnalyticsConfigAtom = atom(void 0);
2086
- const orgAnalyticsConfigAtom = atom((get) => get(internalOrgAnalyticsConfigAtom), (_, set, value) => {
2087
- set(internalOrgAnalyticsConfigAtom, value);
2088
- });
2089
- const orgAnalyticsAmplitudeConfigAtom = atom((get) => get(orgAnalyticsConfigAtom)?.amplitude);
2090
- const orgAnalyticsCustomerServiceConfigAtom = atom((get) => get(orgAnalyticsConfigAtom)?.customerService);
2091
- const orgAnalyticsGoogleAnalyticsConfigAtom = atom((get) => get(orgAnalyticsConfigAtom)?.googleAnalytics);
2092
-
2093
- //#endregion
2094
- //#region src/enabled-features.ts
2095
- var EnabledFeatures = class {
2096
- static {
2097
- this.values = void 0;
2098
- }
2099
- static async get(orgConfig, featureFlagService) {
2100
- if (this.values !== void 0) return this.values;
2101
- const isSpiffyEnabled = async (orgConfig$1, featureFlagService$1) => {
2102
- if (LocalStorageService.getSpiffyOnFeatureFlag() === "true") {
2103
- logger_default.logDebug(`[spiffy-ai] spiffy enabled by "spiffy_on" override`);
2104
- return true;
2105
- }
2106
- if (LocalStorageService.getSpiffyOnFeatureFlag() === "false") {
2107
- logger_default.logDebug(`[spiffy-ai] envive disabled by "envive_on" override`);
2108
- return false;
2109
- }
2110
- if (window._spiffy?.show != null && !window._spiffy.show) {
2111
- logger_default.logDebug(`[spiffy-ai] spiffy disabled by window._spiffy.show`);
2112
- return false;
2113
- }
2114
- if (!featureFlagService$1.isClientSessionEnabled()) {
2115
- logger_default.logDebug(`[spiffy-ai] spiffy disabled by feature flag`);
2116
- return false;
2117
- }
2118
- if (window._spiffy?.show != null && window._spiffy.show) {
2119
- logger_default.logDebug(`[spiffy-ai] spiffy enabled by window._spiffy.show`);
2120
- return true;
2121
- }
2122
- if ((await getOrgInfo(orgConfig$1.org.org.shortName)).alwaysEnabledMerchants) {
2123
- logger_default.logDebug(`[spiffy-ai] spiffy enabled by org config and feature flag`);
2124
- return true;
2125
- }
2126
- if (featureFlagService$1.isClientSessionEnabled()) {
2127
- logger_default.logDebug(`[spiffy-ai] spiffy is enabled by feature flag`);
2128
- return true;
2129
- }
2130
- logger_default.logDebug(`[spiffy-ai] spiffy is disabled because not all checks have passed`);
2131
- return false;
2132
- };
2133
- const isSalesAgentEnabled = isSpiffyEnabled;
2134
- this.values = {
2135
- envive: await isSpiffyEnabled(orgConfig, featureFlagService),
2136
- salesAgent: await isSalesAgentEnabled(orgConfig, featureFlagService)
2137
- };
2138
- return this.values;
2139
- }
2140
- static reset() {
2141
- this.values = void 0;
2142
- }
2143
- };
2144
-
2145
- //#endregion
2146
- //#region src/events/event-types.ts
2147
- let SpiffyEvent = /* @__PURE__ */ function(SpiffyEvent$1) {
2148
- SpiffyEvent$1["AMPLITUDE_EVENT"] = "SPIFFY_AMPLITUDE_EVENT";
2149
- SpiffyEvent$1["APP_INITIALIZED"] = "SPIFFY_APP_INITIALIZED";
2150
- SpiffyEvent$1["CALL_MERCHANT_APP"] = "SPIFFY_CALL_MERCHANT_APP";
2151
- SpiffyEvent$1["MOUNTING_MERCHANT_APP"] = "SPIFFY_MOUNTING_MERCHANT_APP";
2152
- SpiffyEvent$1["CHAT_FACTORY_INITIALIZED"] = "SPIFFY_CHAT_FACTORY_INITIALIZED";
2153
- SpiffyEvent$1["FLOATING_CHAT_RENDERING"] = "SPIFFY_FLOATING_CHAT_RENDERING";
2154
- SpiffyEvent$1["FLOATING_CHAT_NOT_RENDERING"] = "SPIFFY_FLOATING_CHAT_NOT_RENDERING";
2155
- SpiffyEvent$1["FLOATING_CHAT_BUTTON_RENDERING"] = "SPIFFY_FLOATING_CHAT_BUTTON_RENDERING";
2156
- SpiffyEvent$1["SHADOW_DOM_CONTAINER_READY"] = "SPIFFY_SHADOW_DOM_CONTAINER_READY";
2157
- return SpiffyEvent$1;
2158
- }({});
2159
-
2160
- //#endregion
2161
- //#region src/events/index.ts
2162
- /**
2163
- * A singleton class for dispatching Spiffy events to the document object.
2164
- * Provides functionality for adding default event data, managing listeners,
2165
- * and dispatching events.
2166
- *
2167
- * TODO: could add observability to the listeners, would need to track listeners
2168
- * internally.
2169
- */
2170
- var EventsDispatcher = class {
2171
- static {
2172
- this.eventData = {};
2173
- }
2174
- /**
2175
- * Adds event data to the eventData object, which is included by default for
2176
- * every event dispatched. E.g. could add in userId, variantInfo, etc. But
2177
- * make sure it is JSON serializable.
2178
- */
2179
- static addEventData(data) {
2180
- this.eventData = {
2181
- ...this.eventData,
2182
- ...data
2183
- };
2184
- }
2185
- /**
2186
- * Dispatches an event with the given name and detail. If includeDefault is
2187
- * false, the default event data is excluded.
2188
- * @param eventName - the name of the event to dispatch, should be all caps
2189
- * and start with SPIFFY_, e.g. "SPIFFY_FLOATING_CONTAINER_CREATED"
2190
- * @param detail - optional parameter to include extra event data
2191
- * @param includeDefault - optional parameter to exclude the default event
2192
- * data
2193
- */
2194
- static dispatch(eventName, detail, includeDefault) {
2195
- if (detail === void 0) detail = {};
2196
- if (includeDefault === void 0) includeDefault = true;
2197
- const eventData = includeDefault ? {
2198
- ...this.eventData,
2199
- ...detail
2200
- } : detail;
2201
- const event = new CustomEvent(eventName, {
2202
- detail: eventData,
2203
- bubbles: true,
2204
- composed: true,
2205
- cancelable: false
2206
- });
2207
- window.dispatchEvent(event);
2208
- }
2209
- static addListener(eventName, listener) {
2210
- window.addEventListener(eventName, listener, {
2211
- once: false,
2212
- passive: false,
2213
- capture: false
2214
- });
2215
- }
2216
- static removeListener(eventName, listener) {
2217
- window.removeEventListener(eventName, listener);
2218
- }
2219
- };
2220
-
2221
- //#endregion
2222
- //#region src/adapters/amplitude/amplitudeAdapter.ts
2223
- let SpiffyMetricsEventName = /* @__PURE__ */ function(SpiffyMetricsEventName$1) {
2224
- SpiffyMetricsEventName$1["BundleLoaded"] = "Bundle Loaded";
2225
- SpiffyMetricsEventName$1["ChatLiveAgentBtnClick"] = "Chat Live Agent Btn Click";
2226
- SpiffyMetricsEventName$1["ChatFloatingButtonVisible"] = "Chat Floating Button Visible";
2227
- SpiffyMetricsEventName$1["ChatComponentVisible"] = "Chat Component Visible";
2228
- SpiffyMetricsEventName$1["ChatComponentExpanded"] = "Chat Component Expanded";
2229
- SpiffyMetricsEventName$1["ChatComponentCollapsed"] = "Chat Component Collapsed";
2230
- SpiffyMetricsEventName$1["ChatUserMessageInput"] = "Chat User Message Input";
2231
- SpiffyMetricsEventName$1["ChatSuggestionClicked"] = "Chat Suggestion Clicked";
2232
- SpiffyMetricsEventName$1["ChatAssistantResponse"] = "Chat Assistant Response";
2233
- SpiffyMetricsEventName$1["ProductCardClicked"] = "Product Card Clicked";
2234
- SpiffyMetricsEventName$1["ProductReviewCardClicked"] = "Product Review Card Clicked";
2235
- SpiffyMetricsEventName$1["AddToCartClicked"] = "Add to Cart Clicked";
2236
- SpiffyMetricsEventName$1["PromptCardClicked"] = "Prompt Card Clicked";
2237
- SpiffyMetricsEventName$1["SupportedEvent"] = "Supported Event";
2238
- SpiffyMetricsEventName$1["SearchBackToResponseClicked"] = "Search Back to Response Clicked";
2239
- SpiffyMetricsEventName$1["PerformanceMetrics"] = "Performance Metrics";
2240
- SpiffyMetricsEventName$1["SearchBarClicked"] = "Search Bar Clicked";
2241
- SpiffyMetricsEventName$1["OrderLookupStarted"] = "Order Lookup Started";
2242
- SpiffyMetricsEventName$1["OrderLookupFormSubmitted"] = "Order Lookup Form Submitted";
2243
- SpiffyMetricsEventName$1["SearchComponentVisible"] = "Search Component Visible";
2244
- SpiffyMetricsEventName$1["GlobalSearchPromptClicked"] = "Global Search Prompt Clicked";
2245
- SpiffyMetricsEventName$1["SearchInputStarted"] = "Search Input Started";
2246
- SpiffyMetricsEventName$1["SearchQuerySubmitted"] = "Search Query Submitted";
2247
- SpiffyMetricsEventName$1["SearchResultsViewed"] = "Search Results Viewed";
2248
- SpiffyMetricsEventName$1["SearchTimeToFirstClick"] = "Search Time to First Click";
2249
- SpiffyMetricsEventName$1["SearchZeroResultsRate"] = "Search Zero Results Rate";
2250
- SpiffyMetricsEventName$1["SearchFilterClicked"] = "Search Filter Clicked";
2251
- SpiffyMetricsEventName$1["SearchSortClicked"] = "Search Sort Clicked";
2252
- return SpiffyMetricsEventName$1;
2253
- }({});
2254
- var AmplitudeAdapter = class AmplitudeAdapter {
2255
- constructor(userId, orgConfig, featureFlagService, orgGaConfig) {
2256
- this.userId = userId;
2257
- this.orgConfig = orgConfig;
2258
- this.featureFlagService = featureFlagService;
2259
- this.orgGaConfig = orgGaConfig;
2260
- this.underlyingAmplitudeClient = void 0;
2261
- this.internalEventTrackingEnrichment = void 0;
2262
- this.eventPropsToPrefixedEventProps = (eventName, eventProps) => {
2263
- const prefix = eventName.toLowerCase().replace(/\s+/g, "_");
2264
- return Object.entries(eventProps).reduce((acc, [key, value]) => {
2265
- acc[`${prefix}.${key}`] = value;
2266
- return acc;
2267
- }, {});
2268
- };
2269
- this.supplementalDefaultProps = {};
2270
- }
2271
- init() {
2272
- this.underlyingAmplitudeClient = this.createUnderlyingClient();
2273
- }
2274
- getUnderlyingAmplitudeClient() {
2275
- return this.underlyingAmplitudeClient;
2276
- }
2277
- getSupplementalDefaultProps() {
2278
- return this.supplementalDefaultProps;
2279
- }
2280
- setSupplementalDefaultProps(supplementalDefaultProps) {
2281
- this.supplementalDefaultProps = supplementalDefaultProps;
2282
- }
2283
- getEventTrackingEnrichment() {
2284
- if (this.internalEventTrackingEnrichment !== void 0) return this.internalEventTrackingEnrichment;
2285
- this.internalEventTrackingEnrichment = {
2286
- name: "page-view-tracking-enrichment",
2287
- type: "enrichment",
2288
- setup: async () => void 0,
2289
- execute: async (event) => {
2290
- let enrichedEvent;
2291
- if (["[Amplitude] Page Viewed", `[Spiffy] ${SpiffyMetricsEventName.BundleLoaded}`].includes(event.event_type)) {
2292
- const windowProps = window._spiffy ? { ...window._spiffy } : {};
2293
- if (windowProps.publicKey) delete windowProps.publicKey;
2294
- const globalProperties = Object.entries(windowProps).reduce((acc, [key, value]) => ({
2295
- ...acc,
2296
- [`globalProperties.${key}`]: `${value}`
2297
- }), {});
2298
- const enabledFeatures = await EnabledFeatures.get(this.orgConfig, this.featureFlagService);
2299
- const enabledFeaturesProperties = Object.entries(enabledFeatures).reduce((acc, [key, value]) => ({
2300
- ...acc,
2301
- [`enabledFeatures.${key}`]: `${value}`
2302
- }), {});
2303
- const timingProperties = { "timing.enriched_at_ms": window.performance?.now() };
2304
- enrichedEvent = {
2305
- ...event,
2306
- event_properties: {
2307
- ...event.event_properties,
2308
- ...this.getDefaultTrackingProps(),
2309
- ...globalProperties,
2310
- ...enabledFeaturesProperties,
2311
- ...timingProperties
2312
- }
2313
- };
2314
- } else enrichedEvent = event;
2315
- EventsDispatcher.dispatch(SpiffyEvent.AMPLITUDE_EVENT, enrichedEvent);
2316
- return enrichedEvent;
2317
- }
2318
- };
2319
- return this.internalEventTrackingEnrichment;
2320
- }
2321
- amplitudeSessionReplayInit() {
2322
- const isEnabled = this.orgConfig.org.org.shortName === OrgShortName.UniqueVintage && this.featureFlagService.isClientSessionEnabled() && this.featureFlagService.isFeatureGateEnabled(FeatureGates.IsNewFeatureEnabled);
2323
- const sampleRate = 1;
2324
- try {
2325
- logger_default.logDebug(`[spiffy-ai] amplitude session-replay initializing isEnabled=${isEnabled} sampleRate=${sampleRate}`);
2326
- if (!isEnabled) return isEnabled;
2327
- return isEnabled;
2328
- } catch (e) {
2329
- logger_default.logError("[spiffy-ai] Error initializing amplitude session-replay", e);
2330
- return false;
2331
- }
2332
- }
2333
- createUnderlyingClient() {
2334
- const { amplitudeApiKey, dataResidency } = useEnviveConfig();
2335
- const currentAmplitudeInstance = createInstance();
2336
- const isSessionsEnabled = this.amplitudeSessionReplayInit();
2337
- currentAmplitudeInstance.add(this.getEventTrackingEnrichment());
2338
- currentAmplitudeInstance.init(amplitudeApiKey, this.userId, {
2339
- serverZone: dataResidency,
2340
- trackingOptions: { ipAddress: true },
2341
- autocapture: {
2342
- attribution: true,
2343
- pageViews: { trackHistoryChanges: "pathOnly" },
2344
- sessions: isSessionsEnabled,
2345
- formInteractions: false,
2346
- fileDownloads: false
2347
- }
2348
- });
2349
- return currentAmplitudeInstance;
2350
- }
2351
- getDefaultTrackingProps() {
2352
- const { env } = useEnviveConfig();
2353
- const gatesProps = this.orgConfig.gates ? this.orgConfig.gates.reduce((acc, curr) => {
2354
- if (curr.name && curr.value != null) return {
2355
- ...acc,
2356
- [`feature_gate.${curr.name}`]: curr.value
2357
- };
2358
- return acc;
2359
- }, {}) : {};
2360
- const experimentProps = this.orgConfig.experiments ? this.orgConfig.experiments.reduce((acc, curr) => {
2361
- if (curr.name && curr.value != null) return {
2362
- ...acc,
2363
- [`product_experiment.${curr.name}`]: curr.value
2364
- };
2365
- return acc;
2366
- }, {}) : {};
2367
- return {
2368
- ...gatesProps,
2369
- ...experimentProps,
2370
- ...this.supplementalDefaultProps,
2371
- org_id: this.orgConfig.org?.org.id,
2372
- app_id: "commerce-chat-react-component",
2373
- chat_id: LocalStorageService.getItem(LocalStorageKeys.ChatId),
2374
- env: env || "unknown",
2375
- app_source: EnvironmentService.getContextSource(),
2376
- "org.short_name": this.orgConfig.org?.org.shortName,
2377
- "user.id": this.userId,
2378
- "cdp.user_id": null,
2379
- "cdp.provider": null,
2380
- "event.source": "web-browser",
2381
- "event.type": "user-activity",
2382
- "event.id": null,
2383
- "event.channel": "web",
2384
- "event.timestamp": null
2385
- };
2386
- }
2387
- static {
2388
- this.trackEvent = async ({ eventName, eventProps, eventGroups, alsoSendToGoogleAnalytics = false }) => {
2389
- try {
2390
- const decoratedEventName = `[Spiffy] ${eventName}`;
2391
- const amplitudeInstance = AmplitudeAdapter.getSingletonInstanceOf();
2392
- const amplitudeClient = amplitudeInstance.getUnderlyingAmplitudeClient();
2393
- if (!amplitudeClient) {
2394
- logger_default.logWarn("amplitude instance undefined", void 0, { event_name: decoratedEventName });
2395
- return;
2396
- }
2397
- const eventData = JSON.stringify({
2398
- eventName,
2399
- eventProps,
2400
- created_at: (/* @__PURE__ */ new Date()).toISOString()
2401
- });
2402
- const data = new TextEncoder().encode(eventData);
2403
- const hashBuffer = await crypto.subtle.digest("SHA-256", data);
2404
- const currentInsertId = Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
2405
- logger_default.logDebug(`amplitude tracking ${decoratedEventName}`, null, {
2406
- event_name: decoratedEventName,
2407
- props: eventProps
2408
- });
2409
- amplitudeClient.track(decoratedEventName, {
2410
- ...amplitudeInstance.getDefaultTrackingProps(),
2411
- ...eventProps,
2412
- ...eventProps ? AmplitudeAdapter.getSingletonInstanceOf().eventPropsToPrefixedEventProps(eventName, eventProps) : {}
2413
- }, {
2414
- ...eventGroups,
2415
- insert_id: currentInsertId
2416
- });
2417
- if (alsoSendToGoogleAnalytics && amplitudeInstance.orgGaConfig) {
2418
- const dataLayer = WindowDataLayerService.getSingletonInstanceOf(amplitudeInstance.orgGaConfig);
2419
- logger_default.logDebug("[spiffy-ai] GA tracking", decoratedEventName);
2420
- dataLayer.sendToGoogleAnalyticsCircularEventsSafe(decoratedEventName, eventProps);
2421
- }
2422
- } catch (err) {
2423
- logger_default.logError("[spiffy-ai] Error tracking event", err, {
2424
- eventName,
2425
- eventProps
2426
- });
2427
- }
2428
- };
2429
- }
2430
- static amplitudeSafeString(input) {
2431
- if (!input) return null;
2432
- if (input.length > 1024) return input.slice(0, 1024);
2433
- return input;
2434
- }
2435
- static getSingletonInstanceOf() {
2436
- if (EnvironmentService.getContextSource() === ContextSourceEnum.Test) return new StubAmplitudeAdapter();
2437
- const identifyingPrefix = EnvironmentService.getIdentifyingPrefix();
2438
- if (!window[identifyingPrefix]) window[identifyingPrefix] = {};
2439
- if (!window[identifyingPrefix]._amplitudeAdapter) {
2440
- const atomStore$1 = getAtomStore();
2441
- const userId = atomStore$1.get(userIdAtom);
2442
- const orgConfig = atomStore$1.get(orgConfigAtom);
2443
- const orgGaConfig = atomStore$1.get(orgAnalyticsGoogleAnalyticsConfigAtom);
2444
- const featureFlagService = atomStore$1.get(featureFlagServiceAtom);
2445
- window[identifyingPrefix]._amplitudeAdapter = new AmplitudeAdapter(userId, orgConfig, featureFlagService, orgGaConfig);
2446
- window[identifyingPrefix]._amplitudeAdapter?.init();
2447
- }
2448
- return window[identifyingPrefix]._amplitudeAdapter;
2449
- }
2450
- };
2451
-
2452
- //#endregion
2453
- //#region src/adapters/amplitude/stubAmplitudeAdapter.ts
2454
- var StubAmplitudeAdapter = class extends AmplitudeAdapter {
2455
- constructor() {
2456
- super("test", {}, {});
2457
- this.init = () => {};
2458
- this.getUnderlyingAmplitudeClient = () => void 0;
2459
- this.getSupplementalDefaultProps = () => ({});
2460
- this.setSupplementalDefaultProps = () => {};
2461
- this.getEventTrackingEnrichment = () => ({
2462
- name: "stub-enrichment",
2463
- type: "enrichment",
2464
- setup: async () => void 0,
2465
- execute: async (event) => event
2466
- });
2467
- this.amplitudeSessionReplayInit = () => false;
2468
- this.createUnderlyingClient = () => ({});
2469
- this.getDefaultTrackingProps = () => ({});
2470
- this.trackEvent = () => Promise.resolve();
2471
- }
2472
- };
2473
-
2474
- //#endregion
2475
- //#region src/application/models/events.ts
2476
- let SpiffyEventName = /* @__PURE__ */ function(SpiffyEventName$1) {
2477
- SpiffyEventName$1["WidgetOpen"] = "spiffy:widgetopen";
2478
- SpiffyEventName$1["WidgetClose"] = "spiffy:widgetclose";
2479
- return SpiffyEventName$1;
2480
- }({});
2481
-
2482
- //#endregion
2483
- //#region src/atoms/chat/chatState.ts
2484
- const userHasRepliedAtom = atom(false);
2485
- const replyEventCategoryAtom = atom(UserEventCategory$1.AppLoaded);
2486
- const userQueryAtom = atom();
2487
- const suggestionAtom = atom(void 0);
2488
- const askQuestionBtnClickedAtom = atom(false);
2489
- const messagesAtom = atom([]);
2490
- const userEventsAtom = atom([]);
2491
- const suggestionsAtom = atom([]);
2492
- const suggestionsLoadingAtom = atom(false);
2493
- const responseStreamingAtom = atom(false);
2494
- const chatIsOpenAtom = atom(false);
2495
- const requestFailureAtom = atom(false);
2496
- const formSubmitAtom = atom();
2497
- const chatOnToggleAtom = atom(null, (get, set, triggerLocation) => {
2498
- const isOpen = get(chatIsOpenAtom);
2499
- set(chatIsOpenAtom, !isOpen);
2500
- if (!isOpen) {
2501
- window.dispatchEvent(new CustomEvent(SpiffyEventName.WidgetOpen));
2502
- AmplitudeAdapter.trackEvent({
2503
- eventName: SpiffyMetricsEventName.ChatComponentExpanded,
2504
- eventProps: { message_metadata: { trigger_location: triggerLocation } }
2505
- });
2506
- } else {
2507
- window.dispatchEvent(new CustomEvent(SpiffyEventName.WidgetClose));
2508
- AmplitudeAdapter.trackEvent({ eventName: SpiffyMetricsEventName.ChatComponentCollapsed });
2509
- }
2510
- });
2511
-
2512
- //#endregion
2513
- //#region src/atoms/chat/messageQueue.ts
2514
- const internalUserEventQueueAtom = atom([]);
2515
- const userEventQueueAtom = atom((get) => {
2516
- const queue = get(internalUserEventQueueAtom);
2517
- return queue === void 0 ? [] : queue.filter((v) => v !== void 0);
2518
- });
2519
- /**
2520
- * This atom is used to queue a new message for processing on `next_responses`
2521
- * It receives a single `userEvent` that is added to the processing queue.
2522
- * If the event has the same eventId as an existing message in the queue the NEW
2523
- * event is ignored
2524
- */
2525
- const queueUserEventAtom = atom(null, (get, set, userEvent) => {
2526
- if (userEvent === void 0) return;
2527
- set(internalUserEventQueueAtom, [...get(internalUserEventQueueAtom), userEvent]);
2528
- });
2529
- /**
2530
- * This atom exposes a function to reset the entire queue. All messages in the queue will be purged
2531
- */
2532
- const clearUserEventAtom = atom(null, (_, set) => {
2533
- set(internalUserEventQueueAtom, []);
2534
- });
2535
- /**
2536
- * This atom is used to mark events as processed and remove them from the queue
2537
- * It accepts a list of eventId values and will remove all events with those eventIds from the queue.
2538
- */
2539
- const processUserEventAtom = atom(null, (get, set, eventIds) => {
2540
- const remaining = get(internalUserEventQueueAtom)?.filter((event) => !eventIds.includes(event.eventId));
2541
- set(internalUserEventQueueAtom, remaining);
2542
- });
2543
- const userQueueEventCountAtom = atom((get) => get(userEventQueueAtom).length);
2544
- const createResponsePayload = ({ userEvents, generationParams }) => {
2545
- const atomStore$1 = getAtomStore();
2546
- const context = atomStore$1.get(appDetailsAtom);
2547
- const featureFlags = atomStore$1.get(featureFlagServiceAtom).getFeatureFlags();
2548
- return {
2549
- id: v4(),
2550
- context,
2551
- userEvents,
2552
- featureFlags,
2553
- generationParams
2554
- };
2555
- };
2556
-
2557
- //#endregion
2558
- //#region src/atoms/chat/replies.ts
2559
- const handleReplyAtom = atom(null, (get, set, { message, userTyped }) => {
2560
- if (message.type !== MessageType.QueryTyped) return;
2561
- const queryTyped = message.metadata.content;
2562
- set(replyEventCategoryAtom, UserEventCategory.QueryTyped);
2563
- set(userQueryAtom, queryTyped);
2564
- set(messagesAtom, [...get(messagesAtom), [message]]);
2565
- set(userHasRepliedAtom, true);
2566
- set(queueUserEventAtom, {
2567
- eventId: message.id,
2568
- createdAt: message.createdAt,
2569
- category: UserEventCategory.QueryTyped,
2570
- attributes: { query: queryTyped }
2571
- });
2572
- AmplitudeAdapter.trackEvent({
2573
- eventName: SpiffyMetricsEventName.ChatUserMessageInput,
2574
- eventProps: {
2575
- message_id: message.id,
2576
- message_role: message.role,
2577
- message_type: message.type,
2578
- message_metadata: {
2579
- content: AmplitudeAdapter.amplitudeSafeString(message?.metadata?.content),
2580
- created_at: message.createdAt,
2581
- user_typed: userTyped
2582
- }
2583
- },
2584
- alsoSendToGoogleAnalytics: true
2585
- });
2586
- });
2587
-
2588
- //#endregion
2589
- //#region src/atoms/chat/performanceMetrics.ts
2590
- const APP_INITIAL_START_TIME_KEY = "spiffy-app-initial-start-time";
2591
- const PAGE_LOAD_OFFSET_TIME_KEY = "spiffy-page-load-offset-time";
2592
- /**
2593
- * The different performance metrics that can be logged. All times are relative to the
2594
- * initial start time of the app and are stored in milliseconds.
2595
- */
2596
- let PerfMetricsEvents = /* @__PURE__ */ function(PerfMetricsEvents$1) {
2597
- PerfMetricsEvents$1["PageLoadOffset"] = "page_load_offset_ms";
2598
- PerfMetricsEvents$1["MainBundleLoaded"] = "main_bundle_loaded_ms";
2599
- PerfMetricsEvents$1["OrgConfigLoadStarted"] = "org_config_load_started_ms";
2600
- PerfMetricsEvents$1["OrgConfigLoadEnded"] = "org_config_load_ended_ms";
2601
- PerfMetricsEvents$1["FirstResponseStarted"] = "first_response_started_ms";
2602
- PerfMetricsEvents$1["FirstResponseCompleted"] = "first_response_completed_ms";
2603
- PerfMetricsEvents$1["FirstSuggestionsStarted"] = "first_suggestions_started_ms";
2604
- PerfMetricsEvents$1["FirstSuggestionsCompleted"] = "first_suggestions_completed_ms";
2605
- PerfMetricsEvents$1["EmbeddedWidgetRendered"] = "embedded_widget_rendered_ms";
2606
- PerfMetricsEvents$1["FloatingButtonRendered"] = "floating_button_rendered_ms";
2607
- PerfMetricsEvents$1["TopSuggestionsBarRendered"] = "top_suggestions_bar_rendered_ms";
2608
- PerfMetricsEvents$1["BottomSuggestionsBarRendered"] = "bottom_suggestions_bar_rendered_ms";
2609
- PerfMetricsEvents$1["SearchPromptRendered"] = "search_prompt_rendered_ms";
2610
- return PerfMetricsEvents$1;
2611
- }({});
2612
- const internalPerfMetricsAtom = atom(/* @__PURE__ */ new Map());
2613
- const appInitialStartTimeMsAtom = atomWithStorage(APP_INITIAL_START_TIME_KEY, sessionStorage.getItem(APP_INITIAL_START_TIME_KEY) ?? void 0, sessionStorageUtil, { getOnInit: true });
2614
- const pageLoadOffsetTimeAtom = atomWithStorage(PAGE_LOAD_OFFSET_TIME_KEY, sessionStorage.getItem(PAGE_LOAD_OFFSET_TIME_KEY) ?? void 0, sessionStorageUtil, { getOnInit: true });
2615
- const performanceMetricsAtom = atom((get) => get(internalPerfMetricsAtom));
2616
- const hasReportedPerformanceMetricsAtom = atom(false);
2617
- /**
2618
- * Logs a performance metric by capturing the delta between the initial app start time
2619
- * and the current time. If the metric has already been logged, it will not be logged again.
2620
- *
2621
- * @param value The performance metric name to log.
2622
- */
2623
- const logPerfMetricAtom = atom(null, (get, set, value) => {
2624
- const initialTimeStorageValue = get(appInitialStartTimeMsAtom);
2625
- const initialTimeMs = initialTimeStorageValue ? parseInt(initialTimeStorageValue, 10) : void 0;
2626
- if (initialTimeMs == null) {
2627
- logger_default.logWarn(`[spiffy-ai] No initial app start time found. Skipping...`, void 0);
2628
- return;
2629
- }
2630
- const currentPerfMetrics = get(internalPerfMetricsAtom);
2631
- if (currentPerfMetrics.has(value)) return;
2632
- const deltaMs = Date.now() - initialTimeMs;
2633
- currentPerfMetrics.set(value, deltaMs);
2634
- set(internalPerfMetricsAtom, currentPerfMetrics);
2635
- });
2636
-
2637
- //#endregion
2638
- //#region src/atoms/chat/form.ts
2639
- const handleFormSubmittedAtom = atom(null, (_, set, form) => {
2640
- set(replyEventCategoryAtom, UserEventCategory.FormSubmitted);
2641
- set(formSubmitAtom, form);
2642
- const formUserEvent = {
2643
- eventId: v4(),
2644
- category: UserEventCategory.FormSubmitted,
2645
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2646
- attributes: form
2647
- };
2648
- set(queueUserEventAtom, formUserEvent);
2649
- });
2650
-
2651
- //#endregion
2652
- //#region src/atoms/chat/suggestions.ts
2653
- const handleSuggestionAtom = atom(null, (get, set, suggestion) => {
2654
- const newMessage = {
2655
- id: suggestion.id,
2656
- role: MessageRole.User,
2657
- type: MessageType.SuggestionClicked,
2658
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2659
- metadata: {
2660
- suggestionId: suggestion.id,
2661
- suggestionContent: suggestion.content
2662
- }
2663
- };
2664
- set(replyEventCategoryAtom, UserEventCategory.SuggestionClicked);
2665
- set(suggestionAtom, suggestion);
2666
- set(messagesAtom, [...get(messagesAtom), [newMessage]]);
2667
- set(userHasRepliedAtom, true);
2668
- set(queueUserEventAtom, {
2669
- eventId: suggestion.id,
2670
- category: UserEventCategory.SuggestionClicked,
2671
- createdAt: newMessage.createdAt,
2672
- attributes: { suggestionId: suggestion.id }
2673
- });
2674
- });
2675
-
2676
- //#endregion
2677
- //#region src/atoms/chat/lastMessage.ts
2678
- const lastAssistantMessageAtom = atom((get) => {
2679
- const messages = get(messagesAtom);
2680
- const userHasReplied = get(userHasRepliedAtom);
2681
- if (messages.length > 0 && !userHasReplied) return messages[messages.length - 1];
2682
- return null;
2683
- });
2684
-
2685
- //#endregion
2686
- //#region src/atoms/chat/renderedWidgetRefs.ts
2687
- const internalWidgetArrayAtom = atom([]);
2688
- const widgetArrayAtom = atom((get) => get(internalWidgetArrayAtom));
2689
-
2690
- //#endregion
2691
- //#region src/atoms/chat/index.ts
2692
- const chatAtom = atom((get) => ({
2693
- userHasReplied: get(userHasRepliedAtom),
2694
- replyEventCategory: get(replyEventCategoryAtom),
2695
- userQuery: get(userQueryAtom),
2696
- suggestion: get(suggestionAtom),
2697
- askQuestionBtnClicked: get(askQuestionBtnClickedAtom),
2698
- messages: get(messagesAtom),
2699
- userEvents: get(userEventsAtom),
2700
- suggestions: get(suggestionsAtom),
2701
- suggestionsLoading: get(suggestionsLoadingAtom),
2702
- responseStreaming: get(responseStreamingAtom),
2703
- isOpen: get(chatIsOpenAtom),
2704
- onToggle: get(chatOnToggleAtom)
2705
- }));
2706
-
2707
- //#endregion
2708
- //#region src/atoms/org/graphqlConfig.ts
2709
- const internalGraphQLColorsConfigAtom = atom(void 0);
2710
- const internalGraphQLFrontendConfigAtom = atom(void 0);
2711
- const colorsConfigAtom = atom(async (get) => {
2712
- const colors = get(internalGraphQLColorsConfigAtom);
2713
- return {
2714
- ...(await getOrgInfo(get(orgShortNameAtom))).orgColors(),
2715
- ...colors
2716
- };
2717
- }, (_, set, value) => {
2718
- set(internalGraphQLColorsConfigAtom, value);
2719
- });
2720
- const frontendConfigAtom = atom((get) => get(internalGraphQLFrontendConfigAtom), (_, set, value) => {
2721
- set(internalGraphQLFrontendConfigAtom, value);
2722
- });
2723
-
2724
- //#endregion
2725
- //#region src/application/service/customerService/providers/UnsupportedCustomerService.ts
2726
- const UnsupportedCustomerService = {
2727
- provider: CustomerServiceProvider.Unsupported,
2728
- supportedIntegrationModes: [],
2729
- isEnabled: () => false,
2730
- onSwitchToAgent: () => {
2731
- logger_default.logInfo("Spiffy: Switch to Agent - Unsupported");
2732
- },
2733
- isBusinessHours: () => Promise.resolve(false)
2734
- };
2735
-
2736
- //#endregion
2737
- //#region src/application/service/customerService/index.ts
2738
- const findCustomerServiceImpl = (_provider) => {
2739
- return UnsupportedCustomerService;
2740
- };
2741
-
2742
- //#endregion
2743
- //#region src/atoms/org/orgUIConfig.ts
2744
- const internalOrgUIConfigAtom = atom(void 0);
2745
- const orgUIConfigAtom = atom((get) => {
2746
- const orgUIConfig = get(internalOrgUIConfigAtom);
2747
- if (orgUIConfig) return orgUIConfig;
2748
- throw new Error("OrgUIConfig is referenced before it is set");
2749
- }, (_, set, value) => {
2750
- set(internalOrgUIConfigAtom, value);
2751
- });
2752
- const orgCustomerServiceConfig = atom((get) => get(orgUIConfigAtom).customerServiceIntegration);
2753
- const orgCustomerServiceService = atom((get) => {
2754
- const { provider } = get(orgCustomerServiceConfig);
2755
- return findCustomerServiceImpl(provider);
2756
- });
2757
-
2758
- //#endregion
2759
- //#region src/atoms/org/org.ts
2760
- const internalApiKeyAtom = atom(void 0);
2761
- const internalEndpointURLAtom = atom(void 0);
2762
- const internalSourceAtom = atom(EnvironmentService.getContextSource());
2763
- const apiKeyAtom = atom((get) => {
2764
- const apiKey = get(internalApiKeyAtom);
2765
- if (apiKey) return apiKey;
2766
- const { orgLevelApiKey, orgShortName } = useEnviveConfig();
2767
- if (orgLevelApiKey) return orgLevelApiKey;
2768
- if (window._spiffy?.publicKey && typeof window._spiffy.publicKey === "string") return window._spiffy.publicKey;
2769
- if (!orgShortName) throw new Error("[spiffy-ai] orgShortName is required but is not set");
2770
- throw new Error(`[spiffy-ai]: apiKey is missing`);
2771
- }, (_, set, newVal) => {
2772
- set(internalApiKeyAtom, newVal);
2773
- });
2774
- const endpointURLAtom = atom((get) => get(internalEndpointURLAtom) ?? EnvironmentService.getApiEndpoint(), (_, set, newVal) => {
2775
- set(internalEndpointURLAtom, newVal);
2776
- });
2777
- const sourceAtom = atom((get) => get(internalSourceAtom), (_, set, newVal) => {
2778
- set(internalSourceAtom, newVal);
2779
- });
2780
- const orgConfigStorageUtil = createJSONStorage(() => sessionStorage);
2781
- const storedOrgConfigAtom = atomWithStorage("spiffy-org-config", void 0, orgConfigStorageUtil, { getOnInit: true });
2782
- const internalFeatureFlagServiceAtom = atom(void 0);
2783
- const internalOrgConfigAtom = atom(void 0);
2784
- const internalOrgDomainAtom = atom(void 0);
2785
- const internalOrgIdAtom = atom(void 0);
2786
- const internalOrgShortNameAtom = atom(void 0);
2787
- const featureFlagServiceAtom = atom((get) => {
2788
- const featureFlagService = get(internalFeatureFlagServiceAtom);
2789
- if (featureFlagService) return featureFlagService;
2790
- const orgConfig = get(internalOrgConfigAtom);
2791
- if (orgConfig) return new FeatureFlagService(orgConfig.gates);
2792
- throw new Error("FeatureFlagService is referenced before it is set");
2793
- }, (_, set, value) => {
2794
- set(internalFeatureFlagServiceAtom, value);
2795
- });
2796
- const orgConfigAtom = atom((get) => {
2797
- const orgConfig = get(internalOrgConfigAtom);
2798
- if (orgConfig) return orgConfig;
2799
- throw new Error("OrgConfig is referenced before it is set");
2800
- }, (_, set, value) => {
2801
- set(internalOrgConfigAtom, value);
2802
- });
2803
- const orgShortNameAtom = atom((get) => {
2804
- const orgShortName = get(internalOrgShortNameAtom);
2805
- if (orgShortName) return orgShortName;
2806
- throw new Error("Org short name is referenced before it is set");
2807
- }, (_, set, value) => {
2808
- set(internalOrgShortNameAtom, value);
2809
- });
2810
- const orgDomainAtom = atom((get) => {
2811
- const orgDomain = get(internalOrgDomainAtom);
2812
- if (orgDomain) return orgDomain;
2813
- throw new Error("Org domain is referenced before it is set");
2814
- }, (_, set, value) => {
2815
- set(internalOrgDomainAtom, value);
2816
- });
2817
- const orgIdAtom = atom((get) => {
2818
- const orgId = get(internalOrgIdAtom);
2819
- if (orgId) return orgId;
2820
- throw new Error("Org id is referenced before it is set");
2821
- }, (_, set, value) => {
2822
- set(internalOrgIdAtom, value);
2823
- });
2824
-
2825
- //#endregion
2826
- //#region src/atoms/app/variant.ts
2827
- const internalStorageUrlResolverAtom = atomWithStorage("spiffy-url-resolver", void 0, sessionStorageUtil, { getOnInit: true });
2828
- const urlResolverAtom = atom((get) => {
2829
- const maybeUrlResolver = get(internalStorageUrlResolverAtom);
2830
- if (maybeUrlResolver == null) return {};
2831
- return JSON.parse(maybeUrlResolver);
2832
- }, (get, set, value) => {
2833
- const newCache = {
2834
- ...get(urlResolverAtom),
2835
- [value.url]: value.response
2836
- };
2837
- set(internalStorageUrlResolverAtom, JSON.stringify(newCache));
2838
- });
2839
- const internalStorageSupportedEventAtom = atomWithStorage("spiffy-supported-event", void 0, sessionStorageUtil, { getOnInit: true });
2840
- const internalSupportedEventAtom = atom(void 0);
2841
- const supportedEventAtom = atom((get) => {
2842
- const maybeSupportedEvent = get(internalStorageSupportedEventAtom);
2843
- if (maybeSupportedEvent == null) return;
2844
- return JSON.parse(maybeSupportedEvent);
2845
- }, (get, set, value) => {
2846
- if (value == null) {
2847
- set(internalStorageSupportedEventAtom, void 0);
2848
- set(internalSupportedEventAtom, void 0);
2849
- return;
2850
- }
2851
- const featureFlagService = get(featureFlagServiceAtom);
2852
- const variantCategory = get(internalSupportedEventAtom)?.category;
2853
- const shortName = get(orgShortNameAtom);
2854
- if (!featureFlagService.isFeatureGateEnabled(FeatureGates.IsNonShapewearEnabled) && variantCategory && variantCategory !== SupportedEventProductCategory.Shapewear && (shortName === OrgShortName.Spanx || shortName === OrgShortName.SpanxStaging)) {
2855
- const modifiedSupportedEvent = {
2856
- supported: false,
2857
- ready: value.ready,
2858
- category: value.category,
2859
- numberOfReviews: value.numberOfReviews,
2860
- collections: value.collections,
2861
- top_category: value.top_category,
2862
- merchant_tags: value.merchant_tags
2863
- };
2864
- set(internalSupportedEventAtom, modifiedSupportedEvent);
2865
- set(internalStorageSupportedEventAtom, JSON.stringify(modifiedSupportedEvent));
2866
- return;
2867
- }
2868
- set(internalSupportedEventAtom, value);
2869
- set(internalStorageSupportedEventAtom, JSON.stringify(value));
2870
- });
2871
- const internalVariantIdAtom = atom();
2872
- const internalProductIdAtom = atom();
2873
- const internalParentProductIdAtom = atom();
2874
- const internalProductUrlAtom = atom();
2875
- const internalPlpIdAtom = atom();
2876
- const internalUrlAtom = atom();
2877
- const internalPageVisitCategoryAtom = atom();
2878
- const internalVariantAtom = atom("pdp");
2879
- const variantIdAtom = atom((get) => get(internalVariantIdAtom));
2880
- const productIdAtom = atom((get) => get(internalProductIdAtom));
2881
- const parentProductIdAtom = atom((get) => get(internalParentProductIdAtom));
2882
- const productUrlAtom = atom((get) => get(internalProductUrlAtom));
2883
- const plpIdAtom = atom((get) => get(internalPlpIdAtom));
2884
- const urlAtom = atom((get) => get(internalUrlAtom));
2885
- const pageVisitCategoryAtom = atom((get) => get(internalPageVisitCategoryAtom));
2886
- const variantAtom = atom((get) => get(internalVariantAtom));
2887
- const hasParsedVariantInfoAtom = atom(false);
2888
- const variantInfoAtom = atom((get) => {
2889
- const variant = get(variantAtom);
2890
- if (variant === "pdp") return {
2891
- variantId: get(variantIdAtom),
2892
- variant,
2893
- productId: get(productIdAtom),
2894
- parentProductId: get(parentProductIdAtom),
2895
- url: get(urlAtom)
2896
- };
2897
- if (variant === "plp") return {
2898
- variantId: get(variantIdAtom),
2899
- variant,
2900
- plpId: get(plpIdAtom),
2901
- url: get(urlAtom)
2902
- };
2903
- if (variant === "page_visit") return {
2904
- variantId: get(variantIdAtom),
2905
- variant,
2906
- url: get(urlAtom),
2907
- pageVisitCategory: get(pageVisitCategoryAtom)
2908
- };
2909
- throw new Error("Invalid variantInfo details");
2910
- }, (_, set, newVariant) => {
2911
- set(internalVariantAtom, newVariant.variant);
2912
- set(internalVariantIdAtom, newVariant.variantId);
2913
- if (newVariant.variant === "pdp") {
2914
- set(internalProductIdAtom, newVariant.productId);
2915
- set(internalParentProductIdAtom, newVariant.parentProductId);
2916
- set(internalUrlAtom, newVariant.url);
2917
- }
2918
- if (newVariant.variant === "plp") {
2919
- set(internalPlpIdAtom, newVariant.plpId);
2920
- set(internalUrlAtom, newVariant.url);
2921
- }
2922
- if (newVariant.variant === "page_visit") {
2923
- set(internalUrlAtom, newVariant.url);
2924
- set(internalPageVisitCategoryAtom, newVariant.pageVisitCategory);
2925
- }
2926
- });
2927
-
2928
- //#endregion
2929
- //#region src/atoms/app/index.ts
2930
- const internalUserIdAtom = atom(void 0);
2931
- const userIdAtom = atom((get) => {
2932
- const maybeUserId = get(internalUserIdAtom);
2933
- if (maybeUserId) return maybeUserId;
2934
- return UserIdentityService.getUserIdOrDefault();
2935
- }, (_, set, value) => {
2936
- set(internalUserIdAtom, value);
2937
- });
2938
- const appSourceAtom = atom((get) => get(sourceAtom) ?? ContextSourceEnum.App);
2939
- const envAtom = atom(ContextEnvEnum.Dev);
2940
- const chatIdAtom = atomWithStorage("v1-spiffy-chat-session-id", v4(), void 0, { getOnInit: true });
2941
- const appDetailsAtom = atom((get) => ({
2942
- orgId: get(orgIdAtom),
2943
- orgShortName: get(orgShortNameAtom) ?? "spiffy-ai",
2944
- chatId: get(chatIdAtom),
2945
- userId: get(userIdAtom),
2946
- source: get(appSourceAtom),
2947
- env: get(envAtom),
2948
- variantInfo: get(variantInfoAtom)
2949
- }));
2950
-
2951
- //#endregion
2952
- //#region src/application/utils/messageFromFormSubmittedEvent.ts
2953
- const messageFromFormSubmittedEvent = (event, formResponseAttributes) => {
2954
- if (event.category !== UserEventCategory.FormSubmitted) return;
2955
- const formStringContents = Object.entries(formResponseAttributes.schema.properties).map(([key, value]) => `${value.title}: ${event.attributes.filledSchema[key]}`).join("\n");
2956
- return {
2957
- id: event.eventId,
2958
- role: MessageRole.User,
2959
- type: MessageType.QueryTyped,
2960
- createdAt: event.createdAt,
2961
- metadata: { content: formStringContents }
2962
- };
2963
- };
2964
-
2965
- //#endregion
2966
- //#region src/adapters/spiffy/commerce/api.ts
2967
- async function errorResponseBody$1(error) {
2968
- try {
2969
- return await error.response.json();
2970
- } catch {
2971
- return {};
2972
- }
2973
- }
2974
- async function throwSessionRestartRequiredIf$1(errorMsg, error) {
2975
- if (!(error instanceof ResponseError)) {
2976
- logger_default.logInfo(errorMsg, error);
2977
- throw error;
2978
- }
2979
- const errorResponse = await errorResponseBody$1(error);
2980
- if (errorResponse?.message?.toLowerCase() === "unsupported product" || errorResponse?.app_code?.toUpperCase() === "PRODUCT_NOT_FOUND") throw new UnsupportedProductException();
2981
- else if (errorResponse?.app_code?.toUpperCase() === "RESTART_SESSION" || errorResponse?.sub_code?.toUpperCase() === "NOT_FOUND") {
2982
- logger_default.logInfo("Session does not exist. Re-start session", error, error.response, errorResponse);
2983
- throw new SessionRestartRequired();
2984
- }
2985
- logger_default.logInfo(errorMsg, error);
2986
- throw error;
2987
- }
2988
- var CommerceApiClient = class CommerceApiClient {
2989
- static {
2990
- this.getInstance = () => {
2991
- if (!CommerceApiClient.instance) {
2992
- const apiKey = getAtomStore().get(apiKeyAtom);
2993
- CommerceApiClient.instance = new CommerceApiClient(apiKey);
2994
- }
2995
- return CommerceApiClient.instance;
2996
- };
2997
- }
2998
- constructor(apiKey, basePath) {
2999
- this.suggestionsAbortController = new AbortController();
3000
- this.responsesAbortController = new AbortController();
3001
- const { baseUrl } = useEnviveConfig();
3002
- const config = new Configuration({
3003
- accessToken: apiKey,
3004
- basePath: basePath || baseUrl,
3005
- headers: {
3006
- "Content-Type": "application/json",
3007
- Accept: "application/json"
3008
- }
3009
- });
3010
- this.defaultApi = new DefaultApi(config);
3011
- this.inferenceApi = new InferenceApi(config);
3012
- this.customerServiceApi = new CustomerServiceApi(config);
3013
- }
3014
- static {
3015
- this.resolveUrl = async (url) => {
3016
- const atomStore$1 = getAtomStore();
3017
- const appDetails = atomStore$1.get(appDetailsAtom);
3018
- const featureFlagService = atomStore$1.get(featureFlagServiceAtom);
3019
- const context = {
3020
- user_id: appDetails.userId,
3021
- org_id: appDetails.orgId,
3022
- org_short_name: appDetails.orgShortName,
3023
- chat_id: appDetails.chatId,
3024
- source: appDetails.source,
3025
- env: appDetails.env
3026
- };
3027
- const featureGates = featureFlagService.getFeatureFlags();
3028
- const urlResolvingRequest = {
3029
- url,
3030
- context,
3031
- feature_gates: featureGates
3032
- };
3033
- return await (await CommerceApiClient.getInstance().inferenceApi.v1UrlResolvingPostRaw({ UrlResolvingRequest: urlResolvingRequest })).raw.json();
3034
- };
3035
- }
3036
- static {
3037
- this.reportSession = async (reportRequest) => {
3038
- await CommerceApiClient.getInstance().defaultApi.v1ChatsReportSessionIdPost({ ReportSessionRequest: reportRequest });
3039
- };
3040
- }
3041
- static {
3042
- this.getNextResponses = async (payload) => {
3043
- try {
3044
- return (await CommerceApiClient.getInstance().inferenceApi.v1NextResponsesPost({ NextMessageRequest: messageRequestToCommerceMessageRequest(payload) })).map((resp) => validateResponse(resp)).map((resp) => messageFromResponse(resp)).filter((m) => m != null);
3045
- } catch (err) {
3046
- logger_default.logInfo("Failed to get next responses", err, {
3047
- payloadContext: payload?.context,
3048
- userEvents: payload?.userEvents
3049
- });
3050
- await throwSessionRestartRequiredIf$1("Failed to get next responses", err);
3051
- return [];
3052
- }
3053
- };
3054
- }
3055
- static {
3056
- this.getNextResponseStreaming = (payload) => {
3057
- async function* generate(inferenceApi, abortController) {
3058
- try {
3059
- const response = await inferenceApi.v1NextResponsesPostRaw({ NextMessageRequest: messageRequestToCommerceMessageRequest(payload) }, { signal: abortController.signal });
3060
- if (!response.raw.body) {
3061
- logger_default.logError("[spiffy-ai] No body in the streamed response", void 0, { response: response.raw });
3062
- return;
3063
- }
3064
- const reader = response.raw.body.getReader();
3065
- const decoder = new TextDecoder("utf-8");
3066
- let partial = "";
3067
- const safeParse = (line) => {
3068
- try {
3069
- return JSON.parse(line);
3070
- } catch (err) {
3071
- logger_default.logError("[spiffy-ai] Error parsing streamed line", err, {
3072
- line,
3073
- partial
3074
- });
3075
- partial = line;
3076
- return partial;
3077
- }
3078
- };
3079
- const processChunk = (chunk) => {
3080
- return `${partial}${chunk}`.split("\n").map((line) => line.replace(/^data: /, "").trim()).filter((line) => line !== "" && line !== "[DONE]").map(safeParse).filter((v) => v);
3081
- };
3082
- while (true) {
3083
- const { done, value } = await reader.read();
3084
- if (done) break;
3085
- const chunk = decoder.decode(value);
3086
- const parsedLines = processChunk(chunk);
3087
- for (const parsedLine of parsedLines) {
3088
- const validatedResponse = validateResponse(parsedLine);
3089
- if (validatedResponse) yield validatedResponse;
3090
- }
3091
- }
3092
- } catch (error) {
3093
- logger_default.logError("[spiffy-ai] Failed to get next streaming responses", error, {
3094
- payloadContext: payload?.context,
3095
- userEvents: payload?.userEvents
3096
- });
3097
- await throwSessionRestartRequiredIf$1("Failed to get next streaming responses", error);
3098
- }
3099
- }
3100
- CommerceApiClient.getInstance().responsesAbortController.abort();
3101
- CommerceApiClient.getInstance().responsesAbortController = new AbortController();
3102
- return generate(CommerceApiClient.getInstance().inferenceApi, CommerceApiClient.getInstance().responsesAbortController);
3103
- };
3104
- }
3105
- static {
3106
- this.getNextSuggestions = async (payload) => {
3107
- try {
3108
- CommerceApiClient.getInstance().suggestionsAbortController.abort();
3109
- CommerceApiClient.getInstance().suggestionsAbortController = new AbortController();
3110
- return (await CommerceApiClient.getInstance().inferenceApi.v1NextSuggestionsPost({ NextMessageRequest: messageRequestToCommerceMessageRequest(payload) }, { signal: CommerceApiClient.getInstance().suggestionsAbortController.signal })).map((resp) => validateSuggestion(resp)).filter((suggestion) => suggestion != null);
3111
- } catch (error) {
3112
- logger_default.logInfo("Failed to get suggestions", error, {
3113
- payloadContext: payload?.context,
3114
- userEvents: payload?.userEvents
3115
- });
3116
- await throwSessionRestartRequiredIf$1("Failed to get suggestions", error);
3117
- return [];
3118
- }
3119
- };
3120
- }
3121
- static {
3122
- this.getResponses = async (orgId, chatId, userId) => {
3123
- let data = {
3124
- responses: [],
3125
- suggestions: [],
3126
- user_events: []
3127
- };
3128
- const request = {
3129
- org_id: orgId,
3130
- chat_id: chatId,
3131
- user_id: userId
3132
- };
3133
- try {
3134
- data = await CommerceApiClient.getInstance().defaultApi.v1GetSessionMessages(request);
3135
- } catch (error) {
3136
- await throwSessionRestartRequiredIf$1("Failed to get chat responses", error);
3137
- }
3138
- const responses = data?.responses?.map((turn) => turn.map((response) => validateResponse(response)).filter((response) => response != null));
3139
- const suggestions = data?.suggestions.map((suggestion) => validateSuggestion(suggestion)).filter((suggestion) => suggestion != null);
3140
- const userEvents = data?.user_events.map((event) => validateUserEvent(event)).filter((event) => event != null);
3141
- const formSubmittedUserEventsFormIds = userEvents.filter((event) => event.category === UserEventCategory.FormSubmitted).map((event) => event.attributes.formResponseId);
3142
- 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);
3143
- const userMessages = userEvents.map((event) => {
3144
- if ([UserEventCategory.QueryTyped, UserEventCategory.Search].includes(event.category)) return [messageFromQueryEvent(event)];
3145
- if (event.category === UserEventCategory.SuggestionClicked) return [messageFromSuggestionEvent(event, suggestions)];
3146
- if (event.category === UserEventCategory.FormSubmitted) {
3147
- const formResponse = responses.flat().find((response) => response.id === event.attributes.formResponseId && event.attributes.formType !== FormType.Escalation);
3148
- if (formResponse && formResponse.category === ResponseCategory.Form) return [messageFromFormSubmittedEvent(event, formResponse.attributes)];
3149
- }
3150
- return [];
3151
- }).filter((message) => message.length > 0);
3152
- const sortedMessages = [...assistantMessages, ...userMessages].sort((a, b) => new Date(a[0].createdAt).getTime() - new Date(b[0].createdAt).getTime());
3153
- return {
3154
- responses,
3155
- userEvents,
3156
- suggestions,
3157
- messages: sortedMessages
3158
- };
3159
- };
3160
- }
3161
- static {
3162
- this.isSupportedEvent = async (payload) => {
3163
- try {
3164
- const httpResponseText = await (await CommerceApiClient.getInstance().inferenceApi.v1SupportedEventPostRaw({ SupportedEventRequest: coreSupportedEventRequestToApiRequest(payload) })).raw.text();
3165
- const httpResponseJson = JSON.parse(httpResponseText);
3166
- return {
3167
- ...httpResponseJson,
3168
- numberOfReviews: httpResponseJson.num_of_reviews,
3169
- merchant_tags: httpResponseJson.merchant_tags || []
3170
- };
3171
- } catch (err) {
3172
- logger_default.logError("Failed to get response for v1SupportedEventPost", { err });
3173
- return {
3174
- supported: false,
3175
- ready: false,
3176
- category: void 0,
3177
- collections: [],
3178
- numberOfReviews: void 0,
3179
- top_category: void 0,
3180
- merchant_tags: []
3181
- };
3182
- }
3183
- };
3184
- }
3185
- static {
3186
- this.identifyUser = async (spiffyUserId, merchantUserId, uaDetails) => {
3187
- try {
3188
- await CommerceApiClient.getInstance().defaultApi.v1AnalyticsIdentifyPost({ AnalyticsIdentifyRequest: {
3189
- user_id: spiffyUserId,
3190
- os_name: uaDetails.os,
3191
- os_version: uaDetails.osVersion,
3192
- platform: uaDetails.os,
3193
- device_id: uaDetails.deviceModel,
3194
- device_brand: uaDetails.deviceBrand,
3195
- device_manufacturer: uaDetails.deviceManufacturer,
3196
- device_model: uaDetails.deviceModel,
3197
- user_properties: {
3198
- cdp_user_id: merchantUserId,
3199
- browser: uaDetails.browser,
3200
- browser_version: uaDetails.browserVersion,
3201
- user_agent: uaDetails.userAgent
3202
- }
3203
- } });
3204
- } catch (err) {
3205
- logger_default.logError("Failed to identify user", err);
3206
- }
3207
- };
3208
- }
3209
- static {
3210
- this.mapContextSourceToV1OrgConfigGetSource = (source) => {
3211
- if (source === void 0) return void 0;
3212
- switch (source) {
3213
- case ContextSourceEnum.Fork: return V1OrgConfigGetSourceEnum.Fork;
3214
- case ContextSourceEnum.Playground: return V1OrgConfigGetSourceEnum.Playground;
3215
- case ContextSourceEnum.App: return V1OrgConfigGetSourceEnum.App;
3216
- case ContextSourceEnum.Test: return V1OrgConfigGetSourceEnum.Test;
3217
- default: return source;
3218
- }
3219
- };
3220
- }
3221
- static {
3222
- this.getOrgConfig = async (user_id) => {
3223
- try {
3224
- const { reactAppName } = useEnviveConfig();
3225
- const request = {
3226
- namespace: reactAppName,
3227
- user_id,
3228
- source: this.mapContextSourceToV1OrgConfigGetSource(EnvironmentService.getContextSource()),
3229
- include_experiments: Object.values(ProductExperiment),
3230
- include_feature_gates: Object.values(FeatureGates)
3231
- };
3232
- const response = await CommerceApiClient.getInstance().defaultApi.v1OrgConfigGet(request);
3233
- return validateOrgConfigResults(response);
3234
- } catch (err) {
3235
- logger_default.logError(`Failed to get org config`, err, { err });
3236
- return;
3237
- }
3238
- };
3239
- }
3240
- static {
3241
- this.addNoteToLatestConversation = async (spiffyUserId, email, customerServiceProvider) => {
3242
- logger_default.logInfo(`addNoteToLatestConversation - user_id=${spiffyUserId} email=${email} customer_service_provider=${customerServiceProvider}`);
3243
- try {
3244
- await CommerceApiClient.getInstance().customerServiceApi.v1CustserviceAddNoteToLatestConversationPost({ AddNoteToLatestConversationRequest: {
3245
- spiffy_user_id: spiffyUserId,
3246
- email,
3247
- customer_service_provider: customerServiceProvider
3248
- } });
3249
- } catch (err) {
3250
- logger_default.logError("Failed to add note to latest conversation", { err });
3251
- }
3252
- };
3253
- }
3254
- static {
3255
- this.getCustomerServiceApi = () => CommerceApiClient.getInstance().customerServiceApi;
3256
- }
3257
- };
3258
- var api_default = CommerceApiClient;
3259
-
3260
- //#endregion
3261
- //#region src/atoms/org/customerService.ts
3262
- const isBusinessHoursAtom = atom(true);
3263
- const isCustomerServiceOpenAtom = atom(false);
3264
- const customerServiceResponseAtom = atom();
3265
- const customerServiceChatStateAtom = atom();
3266
- const customerServiceAttachment = atom();
3267
-
3268
- //#endregion
3269
- //#region src/atoms/org/merchantCss.ts
3270
- const orgMerchantCssAtom = atom(async (get) => {
3271
- const orgUIConfig = get(orgUIConfigAtom);
3272
- const colors = await get(colorsConfigAtom);
3273
- const merchantThemeCss = colors ? `
3274
-
3275
- * {
3276
- --spiffy-colors-text-primary: ${colors[ColorNames.TextPrimary]};
3277
- --spiffy-colors-text-secondary: ${colors[ColorNames.TextSecondary]};
3278
- --spiffy-colors-text-accent: ${colors[ColorNames.TextAccent]};
3279
- --spiffy-colors-text-link: ${colors[ColorNames.TextLink]};
3280
- --spiffy-colors-text-light: ${colors[ColorNames.TextLight]};
3281
- --spiffy-colors-background-primary: ${colors[ColorNames.BackgroundPrimary]};
3282
- --spiffy-colors-background-secondary: ${colors[ColorNames.BackgroundSecondary]};
3283
- --spiffy-colors-background-secondary-dark: ${colors[ColorNames.BackgroundSecondaryDark]};
3284
- --spiffy-colors-background-tertiary: ${colors[ColorNames.BackgroundTertiary]};
3285
- --spiffy-colors-background-dark: ${colors[ColorNames.BackgroundDark]};
3286
- --spiffy-colors-background-light: ${colors[ColorNames.BackgroundLight]};
3287
- --spiffy-colors-background-saturated: ${colors[ColorNames.BackgroundSaturated]};
3288
- --spiffy-colors-border-light: ${colors[ColorNames.BorderLight]};
3289
- --spiffy-colors-border-medium: ${colors[ColorNames.BorderMedium]};
3290
- --spiffy-colors-border-dark: ${colors[ColorNames.BorderDark]};
3291
- --spiffy-colors-border-outline: ${colors[ColorNames.BorderOutline]};
3292
- --spiffy-colors-accent-primary: ${colors[ColorNames.AccentPrimary]};
3293
- --spiffy-colors-accent-secondary: ${colors[ColorNames.AccentSecondary]};
3294
- }` : `
3295
- * {}`;
3296
- const merchantOverrideCss = orgUIConfig?.merchantOverrideCss;
3297
- return `${merchantThemeCss} ${merchantOverrideCss}`;
3298
- });
3299
-
3300
- //#endregion
3301
- //#region src/atoms/org/orgPageConfig.ts
3302
- const internalInjectedPageVariantsAtom = atom([]);
3303
- const orgPageConfigAtom = atom(async (get) => {
3304
- const orgConfig = get(orgConfigAtom);
3305
- const orgInfo = await getOrgInfo(orgConfig.org.org.shortName);
3306
- const frontendConfig = get(frontendConfigAtom);
3307
- const injectedPageVariants = get(internalInjectedPageVariantsAtom);
3308
- const OverridenOrgPageConfig = { ...orgInfo.orgPageConfig() };
3309
- if (frontendConfig?.mountingConfigs) OverridenOrgPageConfig.mountingConfigs = frontendConfig.mountingConfigs;
3310
- if (frontendConfig?.widgetConfigs) OverridenOrgPageConfig.widgetConfigs = frontendConfig.widgetConfigs;
3311
- if (frontendConfig?.pageVariants) OverridenOrgPageConfig.pageVariants = frontendConfig.pageVariants;
3312
- if (injectedPageVariants.length > 0) OverridenOrgPageConfig.pageVariants = [...injectedPageVariants];
3313
- return OverridenOrgPageConfig;
3314
- }, (_, set, pageVariants) => {
3315
- set(internalInjectedPageVariantsAtom, pageVariants);
3316
- });
3317
-
3318
- //#endregion
3319
- //#region src/atoms/search/utils.ts
3320
- const formatFilterDisplayName = (displayName) => {
3321
- const sizes = [
3322
- "xxxs",
3323
- "xxs",
3324
- "xs",
3325
- "s",
3326
- "m",
3327
- "l",
3328
- "xl",
3329
- "xxl",
3330
- "xxxl",
3331
- "xxxxl"
3332
- ];
3333
- return displayName.toLowerCase().split(" ").map((word) => {
3334
- if (sizes.includes(word)) return word.toUpperCase();
3335
- return word.charAt(0).toUpperCase() + word.slice(1);
3336
- }).join(" ").replace(/Iphone/g, "iPhone");
3337
- };
3338
-
3339
- //#endregion
3340
- //#region src/atoms/search/productFilters.ts
3341
- const getPriceBucket = (price, bucketSize) => {
3342
- return Math.floor(price / bucketSize) * bucketSize;
3343
- };
3344
- const isStringArray = (value) => {
3345
- if (!Array.isArray(value)) return false;
3346
- return value.every((item) => typeof item === "string");
3347
- };
3348
- const sortFilter = (filterConfig) => {
3349
- if (filterConfig.type === "price") return (a, b) => Number(a.filterItemId) - Number(b.filterItemId);
3350
- if (filterConfig.type === "dynamic") {
3351
- if (filterConfig.sorting.type === "alphabetic") return (a, b) => a.displayName.localeCompare(b.displayName);
3352
- if (filterConfig.sorting.type === "productCount") return (a, b) => a.productCount === b.productCount ? a.displayName.localeCompare(b.displayName) : b.productCount - a.productCount;
3353
- if (filterConfig.sorting.type === "custom") {
3354
- const sortedKeys = filterConfig.sorting.map;
3355
- return (a, b) => {
3356
- if (sortedKeys[a.displayName] && sortedKeys[b.displayName]) return sortedKeys[a.displayName] - sortedKeys[b.displayName];
3357
- if (sortedKeys[a.displayName]) return -1;
3358
- if (sortedKeys[b.displayName]) return 1;
3359
- return b.productCount - a.productCount;
3360
- };
3361
- }
3362
- }
3363
- throw new Error("Invaalid search filter configuration");
3364
- };
3365
- var ProductFilters = class {
3366
- static getFiltersForProducts(products, filterConfigs, selectedFilterOptions) {
3367
- if (!products || products.length === 0) return [];
3368
- return [...filterConfigs.map((filterConfig) => products.reduce((acc, product) => {
3369
- if (filterConfig.type === "price") {
3370
- const priceBucket = getPriceBucket(product.salePrice ?? product.originalPrice ?? 0, filterConfig.bucketSize);
3371
- const current = acc.map[priceBucket] ?? {
3372
- filterItemId: priceBucket,
3373
- displayName: `$${priceBucket}-$${priceBucket + filterConfig.bucketSize}`,
3374
- productCount: 0
3375
- };
3376
- acc.map[priceBucket] = {
3377
- ...current,
3378
- productCount: current.productCount + 1
3379
- };
3380
- return acc;
3381
- }
3382
- const attributeValues = (product.filters && product.filters?.[filterConfig.attribute]) ?? [];
3383
- if (isStringArray(attributeValues)) attributeValues.forEach((val) => {
3384
- const normalizedVal = val.toLowerCase();
3385
- const current = acc.map[normalizedVal] ?? {
3386
- filterItemId: normalizedVal,
3387
- displayName: formatFilterDisplayName(val),
3388
- productCount: 0
3389
- };
3390
- acc.map[normalizedVal] = {
3391
- ...current,
3392
- productCount: current.productCount + 1
3393
- };
3394
- });
3395
- return acc;
3396
- }, {
3397
- filterConfig,
3398
- map: {}
3399
- })).map(({ filterConfig, map }) => ({
3400
- filterId: filterConfig.filterId,
3401
- displayName: filterConfig.displayName,
3402
- items: Object.values(map).map((filter$1) => ({
3403
- filterItemId: filter$1.filterItemId,
3404
- displayName: filter$1.displayName,
3405
- productCount: filter$1.productCount,
3406
- isSelected: selectedFilterOptions.some((option) => option.id === `${filterConfig.filterId}:${filter$1.filterItemId}`) ?? false
3407
- })).sort(sortFilter(filterConfig))
3408
- }))];
3409
- }
3410
- static filterProducts(products, filterConfigs, selectedFilterOptions, additiveDynamicFilters = false) {
3411
- const selectedFilters = filterConfigs.map((filterConfig) => ({
3412
- filterConfig,
3413
- hasSelectedOptions: selectedFilterOptions.some((option) => option.filterId === filterConfig.filterId)
3414
- })).filter(({ hasSelectedOptions }) => hasSelectedOptions);
3415
- return selectedFilterOptions.length === 0 ? products : products.filter((product) => selectedFilters.reduce((acc, selectedFilter) => {
3416
- if (!acc) return acc;
3417
- if (selectedFilter.filterConfig.type === "price") {
3418
- const priceBucket = getPriceBucket(product.salePrice ?? product.originalPrice ?? 0, selectedFilter.filterConfig.bucketSize);
3419
- if (!selectedFilterOptions.some((option) => option.id === `price:${priceBucket}`)) return false;
3420
- }
3421
- if (selectedFilter.filterConfig.type === "dynamic") {
3422
- const { filterId, attribute } = selectedFilter.filterConfig;
3423
- const attributeValues = product.filters?.[attribute];
3424
- if (!isStringArray(attributeValues)) return false;
3425
- if (selectedFilter.filterConfig.attribute === "dynamic" && !additiveDynamicFilters) {
3426
- if (!selectedFilterOptions.filter((option) => option.filterId === filterId).map((option) => option.filterItemId.toLowerCase()).every((selectedValue) => attributeValues.some((val) => val.toLowerCase() === selectedValue))) return false;
3427
- } else if (!attributeValues.some((val) => selectedFilterOptions.some((option) => option.id === `${filterId}:${val.toLowerCase()}`))) return false;
3428
- }
3429
- return true;
3430
- }, true));
3431
- }
3432
- };
3433
-
3434
- //#endregion
3435
- //#region src/atoms/search/types.ts
3436
- let ProductSorting = /* @__PURE__ */ function(ProductSorting$1) {
3437
- ProductSorting$1["FEATURED"] = "featured";
3438
- ProductSorting$1["PRICE_ASC"] = "price_asc";
3439
- ProductSorting$1["PRICE_DESC"] = "price_desc";
3440
- return ProductSorting$1;
3441
- }({});
3442
- const ProductSortingNames = {
3443
- [ProductSorting.FEATURED]: "Featured",
3444
- [ProductSorting.PRICE_ASC]: "Price Low to High",
3445
- [ProductSorting.PRICE_DESC]: "Price High to Low"
3446
- };
3447
-
3448
- //#endregion
3449
- //#region src/atoms/search/productSorter.ts
3450
- var ProductSorter = class {
3451
- static sort(products, sorting) {
3452
- switch (sorting) {
3453
- case ProductSorting.PRICE_ASC: return [...products].sort((p1, p2) => (p1.salePrice ?? p1.originalPrice ?? 0) - (p2.salePrice ?? p2.originalPrice ?? 0));
3454
- case ProductSorting.PRICE_DESC: return [...products].sort((p1, p2) => (p2.salePrice ?? p2.originalPrice ?? 0) - (p1.salePrice ?? p1.originalPrice ?? 0));
3455
- default: return products;
3456
- }
3457
- }
3458
- };
3459
-
3460
- //#endregion
3461
- //#region src/atoms/search/chatSearch.ts
3462
- const chatSearchStateAtom = atom("entrypoint");
3463
- const chatSearchHasProductsAtom = atom(false);
3464
- const chatSearchProductSortingAtom = atom(ProductSorting.FEATURED);
3465
- const filterProductList = (message) => message.type === MessageType.Product && message.metadata.isForGrid === true;
3466
- const filterFilterList = (message) => message.type === MessageType.ProductSearchFilter;
3467
- const chatSearchIsLoadingAtom = atom(false);
3468
- const buildChatSearchTurn = (messages) => {
3469
- const queryMessage = messages.find((message) => message.type === MessageType.ProductSearch);
3470
- if (!queryMessage) return null;
3471
- const { generatedQuery, productCount } = queryMessage.metadata ?? {};
3472
- const productList = messages.filter(filterProductList).map((message) => message.metadata);
3473
- const filterList = messages.filter(filterFilterList).map((message) => message.metadata.filterName);
3474
- return [queryMessage.id, {
3475
- id: queryMessage.id,
3476
- generatedQuery,
3477
- productCount: productCount || productList.length,
3478
- productList,
3479
- filterList,
3480
- messages
3481
- }];
3482
- };
3483
- const chatSearchFilterConfigAtom = atom((get) => {
3484
- const { searchConfig } = get(orgUIConfigAtom);
3485
- return searchConfig.searchFilterConfig;
3486
- });
3487
- const searchMapAtom = atom((get) => {
3488
- const messages = get(messagesAtom);
3489
- return Object.fromEntries(messages.map(buildChatSearchTurn).filter((v) => v !== null));
3490
- });
3491
- const internalChatSearchParamsAtom = atom({
3492
- id: null,
3493
- query: null
3494
- });
3495
- const selectedFilterOptionsAtom = atom([]);
3496
- const additiveDynamicFiltersAtom = atom((get) => {
3497
- const { searchConfig } = get(orgUIConfigAtom);
3498
- return searchConfig.additiveDynamicFilters ?? false;
3499
- });
3500
- const handleSearchAtom = atom(null, (get, set, message) => {
3501
- if (message.type !== MessageType.Search) return;
3502
- const querySearch = message.metadata.searchTerm;
3503
- set(replyEventCategoryAtom, UserEventCategory.Search);
3504
- set(userQueryAtom, querySearch);
3505
- set(messagesAtom, [...get(messagesAtom), [message]]);
3506
- set(userHasRepliedAtom, true);
3507
- set(queueUserEventAtom, {
3508
- eventId: message.id,
3509
- category: UserEventCategory.Search,
3510
- createdAt: message.createdAt,
3511
- attributes: {
3512
- searchTerm: message.metadata.searchTerm,
3513
- selectedFilters: message.metadata.selectedFilters
3514
- }
3515
- });
3516
- });
3517
- const chatSearchParamsAtom = atom((get) => get(internalChatSearchParamsAtom), (_, set, value) => {
3518
- set(internalChatSearchParamsAtom, value);
3519
- });
3520
- const chatSearchQueryAtom = atom((get) => get(chatSearchParamsAtom)?.query ?? null, (get, set, value) => {
3521
- const searchParams = get(chatSearchParamsAtom);
3522
- set(chatSearchParamsAtom, {
3523
- id: searchParams.id,
3524
- query: value
3525
- });
3526
- });
3527
- const chatSearchIdAtom = atom((get) => get(chatSearchParamsAtom)?.id ?? null, (get, set, value) => {
3528
- const searchParams = get(chatSearchParamsAtom);
3529
- set(chatSearchParamsAtom, {
3530
- id: value,
3531
- query: searchParams.query
3532
- });
3533
- });
3534
- const ChatSearchTurnAtom = atom((get) => {
3535
- const searchFilterConfig = get(chatSearchFilterConfigAtom);
3536
- const searchMap = get(searchMapAtom);
3537
- const chatSearchId = get(chatSearchIdAtom);
3538
- if (!chatSearchId) return null;
3539
- const ChatSearchTurn = searchMap[chatSearchId];
3540
- if (!ChatSearchTurn) return null;
3541
- const productSorting = get(chatSearchProductSortingAtom);
3542
- const selectedFilterOptions = get(selectedFilterOptionsAtom);
3543
- const additiveDynamicFilters = get(additiveDynamicFiltersAtom);
3544
- const filteredProducts = ProductFilters.filterProducts(ChatSearchTurn.productList, searchFilterConfig, selectedFilterOptions, additiveDynamicFilters);
3545
- const filteredAndSortedProducts = ProductSorter.sort(filteredProducts, productSorting);
3546
- return {
3547
- ...searchMap[chatSearchId],
3548
- productList: filteredAndSortedProducts,
3549
- productCount: filteredAndSortedProducts.length
3550
- };
3551
- });
3552
- const chatSearchProducts = atom((get) => {
3553
- return get(ChatSearchTurnAtom)?.productList ?? [];
3554
- });
3555
- const chatSearchFiltersAtom = atom((get) => {
3556
- const searchFilterConfig = get(chatSearchFilterConfigAtom);
3557
- const searchMap = get(searchMapAtom);
3558
- const chatSearchId = get(chatSearchIdAtom);
3559
- if (chatSearchId && searchMap[chatSearchId]) {
3560
- const products = searchMap[chatSearchId].productList;
3561
- const selectedFilterOptions = get(selectedFilterOptionsAtom);
3562
- return ProductFilters.getFiltersForProducts(products, searchFilterConfig, selectedFilterOptions);
3563
- }
3564
- return [];
3565
- });
3566
- const getSearchParamsAtom = atom(() => {
3567
- const params = new URLSearchParams(window.location.search);
3568
- return {
3569
- es: params.get("es"),
3570
- esq: params.get("esq")
3571
- };
3572
- });
3573
- const initiateChatSearchAtom = atom(null, (_, set, query) => {
3574
- set(chatSearchIsLoadingAtom, true);
3575
- const url = new URL(window.location.href);
3576
- url.searchParams.set("es", "true");
3577
- url.searchParams.set("esq", query);
3578
- window.history.pushState({}, "", url);
3579
- window.dispatchEvent(new PopStateEvent("popstate", { state: {} }));
3580
- set(chatSearchParamsAtom, {
3581
- id: null,
3582
- query
3583
- });
3584
- set(handleSearchAtom, {
3585
- id: v4(),
3586
- role: MessageRole.User,
3587
- type: MessageType.Search,
3588
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3589
- metadata: {
3590
- searchTerm: query,
3591
- selectedFilters: []
3592
- }
3593
- });
3594
- });
3595
- const handleSearchResultsAtom = atom(null, (get, set, message) => {
3596
- if (!message || message.type !== MessageType.ProductSearch) return;
3597
- const { productCount, generatedQuery } = message.metadata;
3598
- if (productCount !== 0) {
3599
- set(selectedFilterOptionsAtom, []);
3600
- set(chatSearchStateAtom, "product-page");
3601
- const currentSearchParams = get(chatSearchParamsAtom);
3602
- const url = new URL(window.location.href);
3603
- url.searchParams.set("es", "true");
3604
- url.searchParams.set("esq", generatedQuery);
3605
- url.searchParams.set("esi", message.id);
3606
- window.history.pushState({}, "", url);
3607
- if (currentSearchParams.id === null) window.history.replaceState(null, "", url);
3608
- else window.history.pushState(null, "", url);
3609
- set(chatSearchParamsAtom, {
3610
- id: message.id,
3611
- query: generatedQuery
3612
- });
3613
- }
3614
- });
3615
- const setChatSearchParamsAtom = atom(null, (_, set, query) => {
3616
- const url = new URL(window.location.href);
3617
- url.searchParams.set("es", "true");
3618
- url.searchParams.set("esq", query);
3619
- window.history.pushState({}, "", url);
3620
- set(chatSearchParamsAtom, {
3621
- id: null,
3622
- query
3623
- });
3624
- });
3625
14
 
3626
- //#endregion
3627
15
  //#region src/hooks/useBlockBackButton.ts
3628
16
  const useBlockBackButton = (enabled, callback) => {
3629
17
  useEffect(() => {
@@ -3840,38 +228,6 @@ const tellExtensionAboutInjectionError = (error) => {
3840
228
  });
3841
229
  };
3842
230
 
3843
- //#endregion
3844
- //#region src/application/utils/stringUtils.ts
3845
- var StringUtils = class StringUtils {
3846
- static isNullOrEmpty(value) {
3847
- const valueTrimmed = value?.trim();
3848
- return value === void 0 || valueTrimmed === "";
3849
- }
3850
- static trimToNull(value) {
3851
- const valueTrimmed = value?.trim();
3852
- return StringUtils.isNullOrEmpty(valueTrimmed) ? void 0 : valueTrimmed;
3853
- }
3854
- static capitalize(type) {
3855
- if (type === void 0) return "";
3856
- return type.charAt(0).toUpperCase() + type.substring(1);
3857
- }
3858
- /**
3859
- * Finds the first pattern in an array that matches a given URL.
3860
- * Patterns can include a single wildcard '*' which matches any sequence of characters.
3861
- *
3862
- * @param patterns
3863
- * @param urlToTest
3864
- * @returns
3865
- */
3866
- static findMatchingPattern(patterns, urlToTest) {
3867
- if (!urlToTest) return;
3868
- for (const pattern of patterns) if (urlToTest.pathname !== "/") {
3869
- const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
3870
- if ((/* @__PURE__ */ new RegExp(`^${regexPattern}$`)).test(urlToTest.pathname)) return pattern;
3871
- } else if (pattern.startsWith(urlToTest.hostname)) return pattern;
3872
- }
3873
- };
3874
-
3875
231
  //#endregion
3876
232
  //#region src/application/service/pageVariantService.ts
3877
233
  /**
@@ -3922,11 +278,11 @@ var PageVariantService = class PageVariantService {
3922
278
  }
3923
279
  static {
3924
280
  this.getCachedUrlResolver = async (url) => {
3925
- const atomStore$1 = getAtomStore();
3926
- const cachedUrlResolver = atomStore$1.get(urlResolverAtom)?.[url];
281
+ const atomStore = getAtomStore();
282
+ const cachedUrlResolver = atomStore.get(urlResolverAtom)?.[url];
3927
283
  if (cachedUrlResolver) return cachedUrlResolver;
3928
284
  const response = await api_default.resolveUrl(url);
3929
- atomStore$1.set(urlResolverAtom, {
285
+ atomStore.set(urlResolverAtom, {
3930
286
  url,
3931
287
  response
3932
288
  });
@@ -4298,287 +654,6 @@ const useDynamicVariants = () => {
4298
654
  }, []);
4299
655
  };
4300
656
 
4301
- //#endregion
4302
- //#region src/application/utils/mutationHelper.ts
4303
- const compareTokens = (original, comparison) => {
4304
- const originalTokens = new Set(original.split(" "));
4305
- const comparisonTokens = new Set(comparison.split(" "));
4306
- return [...originalTokens].filter((token) => !comparisonTokens.has(token));
4307
- };
4308
- var MutationHelper = class {
4309
- static fireClassChange(record, node, fn) {
4310
- if (node && record.oldValue !== node?.classList.value) fn(node?.classList);
4311
- }
4312
- static fireClassAdded(record, node, classMap) {
4313
- if (node && record.oldValue) compareTokens(node?.classList.value, record.oldValue).forEach((className) => classMap.get(className)?.());
4314
- }
4315
- static fireClassRemoved(record, node, classMap) {
4316
- if (node && record.oldValue) compareTokens(record.oldValue, node?.classList.value).forEach((className) => classMap.get(className)?.());
4317
- }
4318
- static fireSubtreeChange(nodes, fn) {
4319
- nodes.length && fn?.(nodes);
4320
- }
4321
- static isClass(mutation) {
4322
- return mutation.type === "attributes" && mutation.attributeName === "class";
4323
- }
4324
- static isChildList(mutation) {
4325
- return mutation.type === "childList";
4326
- }
4327
- };
4328
-
4329
- //#endregion
4330
- //#region src/application/utils/elementObserver.ts
4331
- /**
4332
- * The `ElementObserver` class monitors all changes related to the specific element it is responsible for.
4333
- * It is automatically instantiated by the `useElementObserver` hook, which manages all instances of this class.
4334
- *
4335
- * How it works:
4336
- *
4337
- * Each instance of `ElementObserver` holds several pieces of information related to the node it is monitoring,
4338
- * such as the node's selector and its `MutationObserver`. This class is responsible for translating raw node
4339
- * changes into a more user-friendly format. For example, when the node is added to the DOM, the `ElementObserver`
4340
- * is notified by the `DOMObserver`, which triggers the `onAdd` callback function on the respective `useElementObserver`
4341
- * instance.
4342
- *
4343
- * Instances of `ElementObserver` are fully managed by the `useElementObserver` hook, requiring no additional configuration.
4344
- * When the hook is destroyed, its corresponding `ElementObserver` instance is automatically removed.
4345
- *
4346
- */
4347
- var ElementObserver = class {
4348
- constructor(selector) {
4349
- this.selector = selector;
4350
- this.mutation = null;
4351
- this.node = null;
4352
- this.eventListeners = /* @__PURE__ */ new Map();
4353
- this.classAdded = /* @__PURE__ */ new Map();
4354
- this.classRemoved = /* @__PURE__ */ new Map();
4355
- this.nodeDisplay = "block";
4356
- this.addFn = () => {};
4357
- this.removeFn = () => {};
4358
- this.changeFn = () => {};
4359
- this.classChangeFn = () => {};
4360
- this.addChildFn = void 0;
4361
- this.removeChildFn = void 0;
4362
- this.resetFn = () => {};
4363
- }
4364
- handleAttributes(mutationRecord) {
4365
- mutationRecord.filter(MutationHelper.isClass).forEach((mutation) => {
4366
- MutationHelper.fireClassChange(mutation, this.node, this.classChangeFn);
4367
- MutationHelper.fireClassAdded(mutation, this.node, this.classAdded);
4368
- MutationHelper.fireClassRemoved(mutation, this.node, this.classRemoved);
4369
- });
4370
- }
4371
- handleChildList(mutationRecord) {
4372
- if (!this.addChildFn && !this.removeChildFn) return;
4373
- mutationRecord.filter(MutationHelper.isChildList).forEach((mutation) => {
4374
- MutationHelper.fireSubtreeChange(mutation.addedNodes, this.addChildFn);
4375
- MutationHelper.fireSubtreeChange(mutation.removedNodes, this.removeChildFn);
4376
- });
4377
- }
4378
- addInitialListeners() {
4379
- this.eventListeners.forEach((v, k) => this.node?.addEventListener(k, v));
4380
- }
4381
- clearEventListeners() {
4382
- this.eventListeners.forEach((v, k) => this.node?.removeEventListener(k, v));
4383
- this.eventListeners.clear();
4384
- }
4385
- renew(newNode) {
4386
- if (newNode) {
4387
- this.destroy();
4388
- this.watch(newNode);
4389
- }
4390
- }
4391
- getSelector() {
4392
- return this.selector;
4393
- }
4394
- getNode() {
4395
- return this.node;
4396
- }
4397
- synchronize() {
4398
- const parsedNode = this.getSelector().parse();
4399
- if (this.getNode() !== parsedNode) {
4400
- this.renew(parsedNode);
4401
- return;
4402
- }
4403
- if (!this.getNode() && parsedNode) {
4404
- this.watch(parsedNode);
4405
- return;
4406
- }
4407
- if (this.getNode() && !parsedNode) this.destroy();
4408
- }
4409
- init() {
4410
- const node = this.getSelector().parse();
4411
- if (node) this.watch(node);
4412
- }
4413
- watch(node) {
4414
- if (!this.mutation) {
4415
- this.mutation = new MutationObserver((mutationRecord) => {
4416
- this.handleAttributes(mutationRecord);
4417
- this.handleChildList(mutationRecord);
4418
- this.changeFn(this.node);
4419
- });
4420
- this.mutation.observe(node, {
4421
- childList: true,
4422
- subtree: true,
4423
- attributes: true,
4424
- attributeOldValue: true
4425
- });
4426
- this.node = node;
4427
- this.addFn(this.node);
4428
- this.addInitialListeners();
4429
- }
4430
- }
4431
- destroy() {
4432
- this.resetFn();
4433
- this.removeFn(this.node);
4434
- this.mutation?.disconnect();
4435
- this.clearEventListeners();
4436
- this.classAdded.clear();
4437
- this.classRemoved.clear();
4438
- this.mutation = null;
4439
- this.node = null;
4440
- }
4441
- render(fn) {
4442
- if (this.node) return createPortal(fn(), this.node);
4443
- }
4444
- fire(event) {
4445
- if (this.node) this.node.dispatchEvent(new MouseEvent(event, {
4446
- bubbles: true,
4447
- cancelable: true,
4448
- view: window
4449
- }));
4450
- }
4451
- show() {
4452
- const display = this.node?.style.display;
4453
- if (this.node && display === "none") this.node.style.display = this.nodeDisplay || "block";
4454
- }
4455
- hide() {
4456
- const display = this.node?.style.display;
4457
- if (this.node && display !== "none") {
4458
- this.nodeDisplay = display || "block";
4459
- this.node.style.display = "none";
4460
- }
4461
- }
4462
- registerEvent(event, fn) {
4463
- if (this.node) {
4464
- const previousFn = this.eventListeners.get(event);
4465
- if (previousFn) this.node.removeEventListener(event, previousFn);
4466
- this.node.addEventListener(event, fn);
4467
- }
4468
- this.eventListeners.set(event, fn);
4469
- }
4470
- registerOnReset(fn) {
4471
- this.resetFn = fn;
4472
- }
4473
- registerOnChange(fn) {
4474
- this.changeFn = fn;
4475
- }
4476
- registerOnAdd(fn) {
4477
- this.addFn = fn;
4478
- }
4479
- registerOnRemove(fn) {
4480
- this.removeFn = fn;
4481
- }
4482
- registerOnclassChange(fn) {
4483
- this.classChangeFn = fn;
4484
- }
4485
- registerOnAddChild(fn) {
4486
- this.addChildFn = fn;
4487
- }
4488
- registerOnRemoveChild(fn) {
4489
- this.removeChildFn = fn;
4490
- }
4491
- registerOnClassAdded(className, fn) {
4492
- this.classAdded.set(className, fn);
4493
- }
4494
- registerOnClassRemoved(className, fn) {
4495
- this.classRemoved.set(className, fn);
4496
- }
4497
- };
4498
-
4499
- //#endregion
4500
- //#region src/application/utils/domObserver.ts
4501
- /**
4502
- * This class manages a `MutationObserver` for the `document.body`. It monitors nodes that are
4503
- * added or removed from the DOM and notifies the observers for each observable element
4504
- * when they are ready to be watched.
4505
- *
4506
- * How that works:
4507
- *
4508
- * When the `observe` function is called, it attaches a `MutationObserver` to the `document.body` element.
4509
- * All changes to `document.body` are tracked by this observer. When changes are detected, the `MutationObserver`
4510
- * iterates through all added and removed nodes and checks if each node exists in the main map of observable elements.
4511
- *
4512
- * If a match is found, it notifies the corresponding `ElementObserver` instance to start monitoring changes for that element.
4513
- *
4514
- * The primary `MutationObserver` remains active until the `destroy` function is called. Calling `destroy` will disconnect all
4515
- * individual element observers and release any associated resources.
4516
- *
4517
- * There is no need to explicitly call the `observe` function. It is automatically invoked when a `useElementObserver` hook is instantiated.
4518
- *
4519
- */
4520
- var DOMObserver = class {
4521
- static {
4522
- this.listeners = /* @__PURE__ */ new Map();
4523
- }
4524
- static notifyAdition(records, nodeMapping) {
4525
- records.forEach((record) => record.addedNodes.forEach((node) => {
4526
- nodeMapping.get(node)?.watch(node);
4527
- nodeMapping.delete(node);
4528
- }));
4529
- }
4530
- static notifyRemoval(records, nodeMapping) {
4531
- records.forEach((record) => record.removedNodes.forEach((node) => {
4532
- nodeMapping.get(node)?.destroy();
4533
- nodeMapping.delete(node);
4534
- }));
4535
- }
4536
- static notifyChildrenChanges(nodeMapping) {
4537
- Array.from(nodeMapping.values()).forEach((observer) => observer.synchronize());
4538
- }
4539
- static mapNodeInstancesToListeners() {
4540
- const nodeMapping = /* @__PURE__ */ new Map();
4541
- this.listeners.forEach((observer) => {
4542
- const node = observer.getNode() || observer.getSelector()?.parse();
4543
- if (node) nodeMapping.set(node, observer);
4544
- });
4545
- return nodeMapping;
4546
- }
4547
- static add(selector) {
4548
- const node = selector.getPattern();
4549
- let elementObserver = this.listeners.get(node);
4550
- if (elementObserver) return elementObserver;
4551
- elementObserver = new ElementObserver(selector);
4552
- this.listeners.set(node, elementObserver);
4553
- return elementObserver;
4554
- }
4555
- static remove(selector) {
4556
- const node = selector.getPattern();
4557
- this.listeners.get(node)?.destroy();
4558
- this.listeners.delete(node);
4559
- }
4560
- static observe() {
4561
- if (!this.documentObserver) {
4562
- this.documentObserver = new MutationObserver((mutations) => {
4563
- const nodeMapping = this.mapNodeInstancesToListeners();
4564
- this.notifyAdition(mutations, nodeMapping);
4565
- this.notifyRemoval(mutations, nodeMapping);
4566
- this.notifyChildrenChanges(nodeMapping);
4567
- });
4568
- this.documentObserver.observe(document.body, {
4569
- childList: true,
4570
- subtree: true
4571
- });
4572
- }
4573
- }
4574
- static destroy() {
4575
- this.documentObserver?.disconnect();
4576
- this.listeners.forEach((listener) => listener.destroy());
4577
- this.listeners.clear();
4578
- this.documentObserver = null;
4579
- }
4580
- };
4581
-
4582
657
  //#endregion
4583
658
  //#region src/hooks/useElementObserver.ts
4584
659
  const useElementObserver = (selector) => {
@@ -4751,219 +826,6 @@ const useElementObserver = (selector) => {
4751
826
  };
4752
827
  };
4753
828
 
4754
- //#endregion
4755
- //#region src/application/service/searchService.ts
4756
- const transformProductResponses = (products) => products.map((data) => ({
4757
- id: data.id,
4758
- responseId: data.response_id,
4759
- category: ResponseCategory.Product,
4760
- description: data.description,
4761
- imageUrl: data.image_url,
4762
- imageUrls: data.image_urls,
4763
- title: data.title,
4764
- url: data.url,
4765
- originalPrice: data.original_price,
4766
- salePrice: data.sale_price,
4767
- averageRating: data.average_rating,
4768
- numberReviews: data.number_reviews,
4769
- metadata: data.metadata,
4770
- isForGrid: data.is_for_grid,
4771
- colors: data.colors,
4772
- sizes: data.sizes,
4773
- filters: data.filters
4774
- }));
4775
- async function errorResponseBody(error) {
4776
- try {
4777
- return await error.response.json();
4778
- } catch {
4779
- return {};
4780
- }
4781
- }
4782
- async function throwSessionRestartRequiredIf(errorMsg, error) {
4783
- if (!(error instanceof ResponseError)) {
4784
- logger_default.logInfo(errorMsg, error);
4785
- throw error;
4786
- }
4787
- const errorResponse = await errorResponseBody(error);
4788
- if (errorResponse?.message?.toLowerCase() === "unsupported product" || errorResponse?.app_code?.toUpperCase() === "PRODUCT_NOT_FOUND") throw new UnsupportedProductException();
4789
- else if (errorResponse?.app_code?.toUpperCase() === "RESTART_SESSION" || errorResponse?.sub_code?.toUpperCase() === "NOT_FOUND") {
4790
- logger_default.logInfo("Session does not exist. Re-start session", error, error.response, errorResponse);
4791
- throw new SessionRestartRequired();
4792
- }
4793
- logger_default.logInfo(errorMsg, error);
4794
- throw error;
4795
- }
4796
- var SearchService = class SearchService {
4797
- static {
4798
- this.getInstance = () => {
4799
- if (!SearchService.instance) {
4800
- const apiKey = getAtomStore().get(apiKeyAtom);
4801
- SearchService.instance = new SearchService(apiKey);
4802
- }
4803
- return SearchService.instance;
4804
- };
4805
- }
4806
- constructor(apiKey, basePath) {
4807
- const { baseUrl } = useEnviveConfig();
4808
- const config = new Configuration({
4809
- accessToken: apiKey,
4810
- basePath: basePath || baseUrl,
4811
- headers: {
4812
- "Content-Type": "application/json",
4813
- Accept: "application/json"
4814
- }
4815
- });
4816
- this.searchApi = new SearchApi(config);
4817
- }
4818
- async _searchProducts(params) {
4819
- const appDetails = getAtomStore().get(appDetailsAtom);
4820
- try {
4821
- const { products, filters, search_response_id: searchResponseId } = await this.searchApi.v1SearchQueryGet({
4822
- query: params.query,
4823
- limit: params.limit,
4824
- org_id: appDetails.orgId,
4825
- user_id: appDetails.userId
4826
- });
4827
- return {
4828
- products: transformProductResponses(products) || [],
4829
- filters: filters || [],
4830
- totalProductCount: products?.length || 0,
4831
- searchResponseId: searchResponseId || ""
4832
- };
4833
- } catch (error) {
4834
- await throwSessionRestartRequiredIf("Failed to search products", error);
4835
- return {
4836
- products: [],
4837
- filters: [],
4838
- totalProductCount: 0,
4839
- searchResponseId: ""
4840
- };
4841
- }
4842
- }
4843
- static {
4844
- this.searchProducts = (params) => SearchService.getInstance()._searchProducts(params);
4845
- }
4846
- };
4847
- var searchService_default = SearchService;
4848
-
4849
- //#endregion
4850
- //#region src/atoms/search/searchAPI.ts
4851
- const searchAtom = atom({
4852
- data: null,
4853
- loading: false,
4854
- error: null,
4855
- lastQuery: null
4856
- });
4857
- const searchProductSortingAtom = atom(ProductSorting.FEATURED);
4858
- const searchSelectedFiltersAtom = atom([]);
4859
- const createFilterOption = (filterId, filterItemId, displayName) => ({
4860
- id: `${filterId}:${filterItemId}`,
4861
- displayName,
4862
- filterId,
4863
- filterItemId
4864
- });
4865
- const internalSearchParamsAtom = atom({
4866
- id: null,
4867
- query: null
4868
- });
4869
- const searchParamsAtom = atom((get) => get(internalSearchParamsAtom), (_, set, value) => {
4870
- set(internalSearchParamsAtom, value);
4871
- });
4872
- const internalSearchSystemStateAtom = atom(false);
4873
- const searchSystemAtom = atom((get) => get(internalSearchSystemStateAtom), (get, set, value) => {
4874
- if (value === get(internalSearchSystemStateAtom)) return;
4875
- const stateChangeHandler = () => {
4876
- const params = new URLSearchParams(window.location.search);
4877
- if (params.get("es") === "true") {
4878
- const id = params.get("esi");
4879
- const query = params.get("esq");
4880
- set(searchParamsAtom, {
4881
- id,
4882
- query
4883
- });
4884
- } else set(searchParamsAtom, {
4885
- id: null,
4886
- query: null
4887
- });
4888
- };
4889
- if (value) {
4890
- set(internalSearchSystemStateAtom, true);
4891
- window.addEventListener("popstate", stateChangeHandler);
4892
- stateChangeHandler();
4893
- } else {
4894
- set(internalSearchSystemStateAtom, false);
4895
- window.removeEventListener("popstate", stateChangeHandler);
4896
- }
4897
- });
4898
- const filteredSearchProductsAtom = atom((get) => {
4899
- const searchData = get(searchAtom).data;
4900
- const sorting = get(searchProductSortingAtom);
4901
- const selectedFilters = get(searchSelectedFiltersAtom);
4902
- const orgConfig = get(orgUIConfigAtom);
4903
- if (!searchData?.products) return [];
4904
- const filteredProducts = ProductFilters.filterProducts(searchData.products, orgConfig.searchConfig.searchFilterConfig, selectedFilters, orgConfig.searchConfig.additiveDynamicFilters);
4905
- return ProductSorter.sort(filteredProducts, sorting);
4906
- });
4907
- const searchFiltersAtom = atom((get) => {
4908
- const searchData = get(searchAtom).data;
4909
- const selectedFilters = get(searchSelectedFiltersAtom);
4910
- const orgConfig = get(orgUIConfigAtom);
4911
- if (!searchData?.products) return [];
4912
- return ProductFilters.getFiltersForProducts(searchData.products, orgConfig.searchConfig.searchFilterConfig, selectedFilters);
4913
- });
4914
- const addSearchFilterAtom = atom(null, (get, set, filter$1) => {
4915
- const current = get(searchSelectedFiltersAtom);
4916
- if (!current.some((f) => f.id === filter$1.id)) set(searchSelectedFiltersAtom, [...current, filter$1]);
4917
- });
4918
- const removeSearchFilterAtom = atom(null, (get, set, filterId) => {
4919
- const current = get(searchSelectedFiltersAtom);
4920
- set(searchSelectedFiltersAtom, current.filter((f) => f.id !== filterId));
4921
- });
4922
- const clearSearchFiltersAtom = atom(null, (_, set) => {
4923
- set(searchSelectedFiltersAtom, []);
4924
- });
4925
- const performSearchAtom = atom(null, async (get, set, params, allowRedirect = false) => {
4926
- const currentState = get(searchAtom);
4927
- const redirectSearchResultsUrl = get(orgUIConfigAtom).searchConfig?.redirectSearchResultsUrl;
4928
- if (allowRedirect && redirectSearchResultsUrl) {
4929
- const redirectUrl = new URL(redirectSearchResultsUrl);
4930
- redirectUrl.searchParams.set("es", "true");
4931
- redirectUrl.searchParams.set("esq", params.query);
4932
- window.location.href = redirectUrl.toString();
4933
- } else {
4934
- const url = new URL(window.location.href);
4935
- url.searchParams.set("es", "true");
4936
- url.searchParams.set("esq", params.query);
4937
- window.history.pushState({}, "", url);
4938
- window.dispatchEvent(new PopStateEvent("popstate", { state: {} }));
4939
- }
4940
- window.dispatchEvent(new PopStateEvent("popstate", { state: {} }));
4941
- if (currentState.loading) return;
4942
- set(searchAtom, {
4943
- data: null,
4944
- loading: true,
4945
- error: null,
4946
- lastQuery: params.query
4947
- });
4948
- try {
4949
- const result = await searchService_default.searchProducts(params);
4950
- set(searchAtom, {
4951
- data: result,
4952
- loading: false,
4953
- error: null,
4954
- lastQuery: params.query
4955
- });
4956
- } catch (error) {
4957
- const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
4958
- set(searchAtom, {
4959
- data: null,
4960
- loading: false,
4961
- error: errorMessage,
4962
- lastQuery: params.query
4963
- });
4964
- }
4965
- });
4966
-
4967
829
  //#endregion
4968
830
  //#region src/hooks/useFileUpload.ts
4969
831
  const useFileUpload = () => {
@@ -5107,94 +969,6 @@ const useGrabAndScroll = (enabled, chunkWidth, speed = 400, offset = 0) => {
5107
969
  };
5108
970
  };
5109
971
 
5110
- //#endregion
5111
- //#region src/application/utils/nodeSelector.ts
5112
- var NodeSelector = class {
5113
- constructor(pattern) {
5114
- this.pattern = pattern;
5115
- this.root = document;
5116
- }
5117
- getPattern() {
5118
- return this.pattern;
5119
- }
5120
- setRoot(root) {
5121
- this.root = root;
5122
- }
5123
- getRoot() {
5124
- return this.root;
5125
- }
5126
- };
5127
- var QuerySelector = class extends NodeSelector {
5128
- parse() {
5129
- return this.getRoot().querySelector(this.getPattern());
5130
- }
5131
- };
5132
- var IDSelector = class extends NodeSelector {
5133
- parse() {
5134
- return this.getRoot().getElementById(this.getPattern());
5135
- }
5136
- };
5137
- var XpathSelector = class extends NodeSelector {
5138
- parse() {
5139
- return this.getRoot()?.evaluate(this.getPattern(), this.getRoot(), null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)?.singleNodeValue;
5140
- }
5141
- };
5142
- var ChainSelector = class extends NodeSelector {
5143
- parse() {
5144
- let selectorIndex = 0;
5145
- const selectors = this.getPattern().split("@");
5146
- const lastIndex = selectors.length - 1;
5147
- const parseChain = (pattern, prevNode) => {
5148
- const selector = SelectorFactory.parse(pattern);
5149
- if (prevNode) selector.setRoot(prevNode);
5150
- const currentNode = selector.parse();
5151
- if (selectorIndex === lastIndex) return currentNode;
5152
- let node = currentNode || document;
5153
- if (currentNode?.shadowRoot) node = currentNode.shadowRoot;
5154
- if (currentNode?.contentWindow) node = currentNode.contentWindow?.document;
5155
- return parseChain(selectors[++selectorIndex].trim(), node);
5156
- };
5157
- return parseChain(selectors[selectorIndex].trim());
5158
- }
5159
- };
5160
- var Empty = class extends NodeSelector {
5161
- constructor() {
5162
- super("");
5163
- }
5164
- parse() {
5165
- return null;
5166
- }
5167
- };
5168
- var SelectorFactory = class {
5169
- static parse(composedSelector) {
5170
- if (!composedSelector) return new Empty();
5171
- const split = composedSelector.split("|");
5172
- const type = split[0];
5173
- const selector = split[1];
5174
- switch (type) {
5175
- case "id": return this.id(selector);
5176
- case "query": return this.query(selector);
5177
- case "xpath": return this.xpath(selector);
5178
- default: return new Empty();
5179
- }
5180
- }
5181
- static check(selector) {
5182
- return selector ?? new Empty();
5183
- }
5184
- static chain(pattern) {
5185
- return pattern ? new ChainSelector(pattern) : new Empty();
5186
- }
5187
- static id(pattern) {
5188
- return pattern ? new IDSelector(pattern) : new Empty();
5189
- }
5190
- static query(pattern) {
5191
- return pattern ? new QuerySelector(pattern) : new Empty();
5192
- }
5193
- static xpath(pattern) {
5194
- return pattern ? new XpathSelector(pattern) : new Empty();
5195
- }
5196
- };
5197
-
5198
972
  //#endregion
5199
973
  //#region src/hooks/useHideElements.ts
5200
974
  /**
@@ -10606,36 +6380,6 @@ const useMessageScrollObserver = (boxRef, scrollRef, onScrollChange) => {
10606
6380
  }, []);
10607
6381
  };
10608
6382
 
10609
- //#endregion
10610
- //#region src/atoms/globalSearch.ts
10611
- const autocompleteStateAtom = atom({
10612
- results: [],
10613
- isLoading: false
10614
- });
10615
- const isFilterOpenAtom = atom(false);
10616
- const isGlobalSearchOpenAtom = atom(false);
10617
- const isSearchResultsOpenAtom = atom(false);
10618
-
10619
- //#endregion
10620
- //#region src/application/models/spiffyWidgets.ts
10621
- /**
10622
- * Enum of all widget names. These are widgets that are rendered and integrated into
10623
- * a merchant's website.
10624
- */
10625
- let SpiffyWidgets = /* @__PURE__ */ function(SpiffyWidgets$1) {
10626
- SpiffyWidgets$1["ImageBanner"] = "image_banner";
10627
- SpiffyWidgets$1["ImagePromptCard"] = "image_prompt_card";
10628
- SpiffyWidgets$1["SingleImagePrompt"] = "single_image_prompt";
10629
- SpiffyWidgets$1["EmbeddedWidget"] = "embedded_widget";
10630
- SpiffyWidgets$1["FloatingButton"] = "floating_button";
10631
- SpiffyWidgets$1["SuggestionBar"] = "suggestion_bar";
10632
- SpiffyWidgets$1["SearchPrompt"] = "search_prompt";
10633
- SpiffyWidgets$1["GlobalSearch"] = "global_search";
10634
- SpiffyWidgets$1["SearchResults"] = "search_results";
10635
- SpiffyWidgets$1["GlobalSearchEntryPoint"] = "global_search_entry_point";
10636
- return SpiffyWidgets$1;
10637
- }({});
10638
-
10639
6383
  //#endregion
10640
6384
  //#region src/hooks/useSearch.tsx
10641
6385
  const useSearch = () => {
@@ -11091,57 +6835,6 @@ const useUpdateAnalyticsProps = () => {
11091
6835
  }, [variantInfo, hasParsedVariantInfo]);
11092
6836
  };
11093
6837
 
11094
- //#endregion
11095
- //#region src/interceptors/useFormEscalation.ts
11096
- const useFormEscalation = () => {
11097
- const handleFormSubmitted = useSetAtom(handleFormSubmittedAtom);
11098
- const customerServiceIntegration = useAtomValue(orgCustomerServiceService);
11099
- const apiKey = useAtomValue(apiKeyAtom);
11100
- const apiEndpoint = useAtomValue(endpointURLAtom);
11101
- const blockExecution = () => true;
11102
- const execute = async (response) => {
11103
- if (response.category === ResponseCategory.Form && response.attributes.formCategory?.formType === FormType.Escalation) {
11104
- const isEnabled = customerServiceIntegration.isEnabled();
11105
- const isBusinessHours = await customerServiceIntegration.isBusinessHours(apiKey, apiEndpoint);
11106
- handleFormSubmitted({
11107
- formResponseId: response.id,
11108
- formType: FormType.Escalation,
11109
- filledSchema: {
11110
- is_in_business_hours: isBusinessHours,
11111
- is_integration_enabled: isEnabled
11112
- }
11113
- });
11114
- }
11115
- };
11116
- return {
11117
- execute,
11118
- blockExecution
11119
- };
11120
- };
11121
-
11122
- //#endregion
11123
- //#region src/interceptors/useMessageInterceptor.ts
11124
- const useMessageInterceptor = () => {
11125
- const formEscalation = useFormEscalation();
11126
- const interceptorMap = useMemo(() => {
11127
- const interceptors = /* @__PURE__ */ new Map();
11128
- interceptors.set(FormType.Escalation, formEscalation);
11129
- return interceptors;
11130
- }, []);
11131
- const intercept = (response) => {
11132
- if (response?.category === ResponseCategory.Form) {
11133
- const formType = response.attributes.formCategory?.formType;
11134
- if (formType) {
11135
- const interceptor = interceptorMap.get(formType);
11136
- interceptor?.execute(response);
11137
- return interceptor?.blockExecution();
11138
- }
11139
- }
11140
- return false;
11141
- };
11142
- return { intercept };
11143
- };
11144
-
11145
6838
  //#endregion
11146
6839
  //#region src/contexts/chatContext.tsx
11147
6840
  /**
@@ -11151,11 +6844,11 @@ const useMessageInterceptor = () => {
11151
6844
  * @param payload The payload used to generate the response
11152
6845
  */
11153
6846
  const recordAssistantResponse = (startTimeMs, payload) => {
11154
- const atomStore$1 = getAtomStore();
11155
- const chatState = atomStore$1.get(chatAtom);
11156
- const chatSearchState = atomStore$1.get(chatSearchStateAtom);
11157
- const searchProducts = atomStore$1.get(chatSearchProducts);
11158
- const searchProductsSort = atomStore$1.get(chatSearchProductSortingAtom);
6847
+ const atomStore = getAtomStore();
6848
+ const chatState = atomStore.get(chatAtom);
6849
+ const chatSearchState = atomStore.get(chatSearchStateAtom);
6850
+ const searchProducts = atomStore.get(chatSearchProducts);
6851
+ const searchProductsSort = atomStore.get(chatSearchProductSortingAtom);
11159
6852
  const assistantResponseTimeMs = {
11160
6853
  start: startTimeMs,
11161
6854
  end: Date.now()
@@ -11456,4 +7149,4 @@ const SystemSettingsContextProvider = ({ children, generationParams, showDebugBa
11456
7149
  };
11457
7150
 
11458
7151
  //#endregion
11459
- export { ChatContext, ChatContextProvider, SystemSettingsContext, SystemSettingsContextProvider, defaultGenerationParams, useBlockBackButton, useChatToggle, useCustomerSupportHandoff, useDebounce, useDynamicVariants, useElementObserver, useFileUpload, useGrabAndScroll, useHideElements, useHorizontalScrollAnimation, useImageResolver, useIntersection, useIsSmallScreen, useMessageFilter, useMessageScrollObserver, useReducedMotionWithOverride, useSearch, useSnapCalculator, useSnapControl, useSystemSettingsContext, useTrackComponentVisibleEvent, useUpdateAnalyticsProps };
7152
+ export { ChatContext, ChatContextProvider, PageVariantService, ShopifyUrlService, SystemSettingsContext, SystemSettingsContextProvider, defaultGenerationParams, useBlockBackButton, useChatToggle, useCustomerSupportHandoff, useDebounce, useDynamicVariants, useElementObserver, useFileUpload, useGrabAndScroll, useHideElements, useHorizontalScrollAnimation, useImageResolver, useIntersection, useIsSmallScreen, useMessageFilter, useMessageScrollObserver, useReducedMotionWithOverride, useSearch, useSnapCalculator, useSnapControl, useSystemSettingsContext, useTrackComponentVisibleEvent, useUpdateAnalyticsProps };