@qualified-salesforce/web 0.0.1-oidc-bootstrap

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 (560) hide show
  1. package/41842993ec71d6628e4949e9a22b146b.svg +3 -0
  2. package/7271f3433ed82fc7f56adcd9e30275f4.svg +17 -0
  3. package/LICENSE.txt +82 -0
  4. package/components/helpers/entriesStringValidations.js +69 -0
  5. package/components/helpers/languages.js +32 -0
  6. package/components/shared/assertUnreachable.js +5 -0
  7. package/components/shared/controls/imageCropperHelpers.js +43 -0
  8. package/components/shared/meetingLoadingProgressSpec.js +116 -0
  9. package/constants.generated.js +9883 -0
  10. package/css/widget/multimodal_v2/host.split-css.css +162 -0
  11. package/css/widget/multimodal_v2/index.split-css.panda.css +5240 -0
  12. package/css/widget/widget.split-css.css +100 -0
  13. package/fonts/inter/Inter-Black.woff +0 -0
  14. package/fonts/inter/Inter-Black.woff2 +0 -0
  15. package/fonts/inter/Inter-BlackItalic.woff +0 -0
  16. package/fonts/inter/Inter-BlackItalic.woff2 +0 -0
  17. package/fonts/inter/Inter-Bold.woff +0 -0
  18. package/fonts/inter/Inter-Bold.woff2 +0 -0
  19. package/fonts/inter/Inter-BoldItalic.woff +0 -0
  20. package/fonts/inter/Inter-BoldItalic.woff2 +0 -0
  21. package/fonts/inter/Inter-ExtraBold.woff +0 -0
  22. package/fonts/inter/Inter-ExtraBold.woff2 +0 -0
  23. package/fonts/inter/Inter-ExtraBoldItalic.woff +0 -0
  24. package/fonts/inter/Inter-ExtraBoldItalic.woff2 +0 -0
  25. package/fonts/inter/Inter-ExtraLight.woff +0 -0
  26. package/fonts/inter/Inter-ExtraLight.woff2 +0 -0
  27. package/fonts/inter/Inter-ExtraLightItalic.woff +0 -0
  28. package/fonts/inter/Inter-ExtraLightItalic.woff2 +0 -0
  29. package/fonts/inter/Inter-Italic.woff +0 -0
  30. package/fonts/inter/Inter-Italic.woff2 +0 -0
  31. package/fonts/inter/Inter-Light.woff +0 -0
  32. package/fonts/inter/Inter-Light.woff2 +0 -0
  33. package/fonts/inter/Inter-LightItalic.woff +0 -0
  34. package/fonts/inter/Inter-LightItalic.woff2 +0 -0
  35. package/fonts/inter/Inter-Medium.woff +0 -0
  36. package/fonts/inter/Inter-Medium.woff2 +0 -0
  37. package/fonts/inter/Inter-MediumItalic.woff +0 -0
  38. package/fonts/inter/Inter-MediumItalic.woff2 +0 -0
  39. package/fonts/inter/Inter-Regular.woff +0 -0
  40. package/fonts/inter/Inter-Regular.woff2 +0 -0
  41. package/fonts/inter/Inter-SemiBold.woff +0 -0
  42. package/fonts/inter/Inter-SemiBold.woff2 +0 -0
  43. package/fonts/inter/Inter-SemiBoldItalic.woff +0 -0
  44. package/fonts/inter/Inter-SemiBoldItalic.woff2 +0 -0
  45. package/fonts/inter/Inter-Thin.woff +0 -0
  46. package/fonts/inter/Inter-Thin.woff2 +0 -0
  47. package/fonts/inter/Inter-ThinItalic.woff +0 -0
  48. package/fonts/inter/Inter-ThinItalic.woff2 +0 -0
  49. package/fonts/inter/Inter-italic.var.woff2 +0 -0
  50. package/fonts/inter/Inter-roman.var.woff2 +0 -0
  51. package/images/close.js +63 -0
  52. package/images/logo.js +22 -0
  53. package/js/4101.js +19721 -0
  54. package/js/daily-esm.js +9948 -0
  55. package/js/date-fns.js +427 -0
  56. package/js/multimodal_v2.js +1653 -0
  57. package/js/runtime.js +109 -0
  58. package/media/Inter-Black.796be8d8bf.woff2 +0 -0
  59. package/media/Inter-Black.b254104c56.woff +0 -0
  60. package/media/Inter-BlackItalic.70306b0eae.woff +0 -0
  61. package/media/Inter-BlackItalic.752f1e0aaa.woff2 +0 -0
  62. package/media/Inter-Bold.579e0f95ca.woff2 +0 -0
  63. package/media/Inter-Bold.b1234477a5.woff +0 -0
  64. package/media/Inter-BoldItalic.3d0d804323.woff +0 -0
  65. package/media/Inter-BoldItalic.828a494e04.woff2 +0 -0
  66. package/media/Inter-ExtraBold.208a9e6c99.woff +0 -0
  67. package/media/Inter-ExtraBold.d65f028165.woff2 +0 -0
  68. package/media/Inter-ExtraBoldItalic.30429962ec.woff +0 -0
  69. package/media/Inter-ExtraBoldItalic.8c7eac5ce3.woff2 +0 -0
  70. package/media/Inter-ExtraLight.15c082a57d.woff +0 -0
  71. package/media/Inter-ExtraLight.6824177d1e.woff2 +0 -0
  72. package/media/Inter-ExtraLightItalic.05138dddf3.woff2 +0 -0
  73. package/media/Inter-ExtraLightItalic.3beee54f59.woff +0 -0
  74. package/media/Inter-Italic.9beab78452.woff +0 -0
  75. package/media/Inter-Italic.d593a8df79.woff2 +0 -0
  76. package/media/Inter-Light.27083fa637.woff2 +0 -0
  77. package/media/Inter-Light.91dfddd842.woff +0 -0
  78. package/media/Inter-LightItalic.0a783b89b3.woff2 +0 -0
  79. package/media/Inter-LightItalic.f8ccf2813f.woff +0 -0
  80. package/media/Inter-Medium.dc792b508e.woff2 +0 -0
  81. package/media/Inter-Medium.ec7dd2d9d8.woff +0 -0
  82. package/media/Inter-MediumItalic.17301e5b40.woff +0 -0
  83. package/media/Inter-MediumItalic.84d3493a9f.woff2 +0 -0
  84. package/media/Inter-Regular.f1f0c35b32.woff2 +0 -0
  85. package/media/Inter-Regular.f356e84aa0.woff +0 -0
  86. package/media/Inter-SemiBold.55027e4724.woff +0 -0
  87. package/media/Inter-SemiBold.fcb100c760.woff2 +0 -0
  88. package/media/Inter-SemiBoldItalic.ab9105ed3b.woff +0 -0
  89. package/media/Inter-SemiBoldItalic.d90f295d0c.woff2 +0 -0
  90. package/media/Inter-Thin.16325d9b0f.woff +0 -0
  91. package/media/Inter-Thin.dafaa44d99.woff2 +0 -0
  92. package/media/Inter-ThinItalic.4fc662b3cf.woff2 +0 -0
  93. package/media/Inter-ThinItalic.d3d8994788.woff +0 -0
  94. package/media/Inter-italic.var.958a0b9742.woff2 +0 -0
  95. package/media/Inter-roman.var.b2129c009c.woff2 +0 -0
  96. package/package.json +20 -0
  97. package/packs/widget/api/docking/docking_host.js +97 -0
  98. package/packs/widget/api/docking/index.js +294 -0
  99. package/packs/widget/api/docking/shared.js +164 -0
  100. package/packs/widget/api/docking/viewport_lock.js +488 -0
  101. package/packs/widget/api/docking/viewport_resize.js +1203 -0
  102. package/packs/widget/esm/fonts/Inter-Black.796be8d8bf.woff2 +0 -0
  103. package/packs/widget/esm/fonts/Inter-Black.b254104c56.woff +0 -0
  104. package/packs/widget/esm/fonts/Inter-BlackItalic.70306b0eae.woff +0 -0
  105. package/packs/widget/esm/fonts/Inter-BlackItalic.752f1e0aaa.woff2 +0 -0
  106. package/packs/widget/esm/fonts/Inter-Bold.579e0f95ca.woff2 +0 -0
  107. package/packs/widget/esm/fonts/Inter-Bold.b1234477a5.woff +0 -0
  108. package/packs/widget/esm/fonts/Inter-BoldItalic.3d0d804323.woff +0 -0
  109. package/packs/widget/esm/fonts/Inter-BoldItalic.828a494e04.woff2 +0 -0
  110. package/packs/widget/esm/fonts/Inter-ExtraBold.208a9e6c99.woff +0 -0
  111. package/packs/widget/esm/fonts/Inter-ExtraBold.d65f028165.woff2 +0 -0
  112. package/packs/widget/esm/fonts/Inter-ExtraBoldItalic.30429962ec.woff +0 -0
  113. package/packs/widget/esm/fonts/Inter-ExtraBoldItalic.8c7eac5ce3.woff2 +0 -0
  114. package/packs/widget/esm/fonts/Inter-ExtraLight.15c082a57d.woff +0 -0
  115. package/packs/widget/esm/fonts/Inter-ExtraLight.6824177d1e.woff2 +0 -0
  116. package/packs/widget/esm/fonts/Inter-ExtraLightItalic.05138dddf3.woff2 +0 -0
  117. package/packs/widget/esm/fonts/Inter-ExtraLightItalic.3beee54f59.woff +0 -0
  118. package/packs/widget/esm/fonts/Inter-Italic.9beab78452.woff +0 -0
  119. package/packs/widget/esm/fonts/Inter-Italic.d593a8df79.woff2 +0 -0
  120. package/packs/widget/esm/fonts/Inter-Light.27083fa637.woff2 +0 -0
  121. package/packs/widget/esm/fonts/Inter-Light.91dfddd842.woff +0 -0
  122. package/packs/widget/esm/fonts/Inter-LightItalic.0a783b89b3.woff2 +0 -0
  123. package/packs/widget/esm/fonts/Inter-LightItalic.f8ccf2813f.woff +0 -0
  124. package/packs/widget/esm/fonts/Inter-Medium.dc792b508e.woff2 +0 -0
  125. package/packs/widget/esm/fonts/Inter-Medium.ec7dd2d9d8.woff +0 -0
  126. package/packs/widget/esm/fonts/Inter-MediumItalic.17301e5b40.woff +0 -0
  127. package/packs/widget/esm/fonts/Inter-MediumItalic.84d3493a9f.woff2 +0 -0
  128. package/packs/widget/esm/fonts/Inter-Regular.f1f0c35b32.woff2 +0 -0
  129. package/packs/widget/esm/fonts/Inter-Regular.f356e84aa0.woff +0 -0
  130. package/packs/widget/esm/fonts/Inter-SemiBold.55027e4724.woff +0 -0
  131. package/packs/widget/esm/fonts/Inter-SemiBold.fcb100c760.woff2 +0 -0
  132. package/packs/widget/esm/fonts/Inter-SemiBoldItalic.ab9105ed3b.woff +0 -0
  133. package/packs/widget/esm/fonts/Inter-SemiBoldItalic.d90f295d0c.woff2 +0 -0
  134. package/packs/widget/esm/fonts/Inter-Thin.16325d9b0f.woff +0 -0
  135. package/packs/widget/esm/fonts/Inter-Thin.dafaa44d99.woff2 +0 -0
  136. package/packs/widget/esm/fonts/Inter-ThinItalic.4fc662b3cf.woff2 +0 -0
  137. package/packs/widget/esm/fonts/Inter-ThinItalic.d3d8994788.woff +0 -0
  138. package/packs/widget/esm/fonts/Inter-italic.var.958a0b9742.woff2 +0 -0
  139. package/packs/widget/esm/fonts/Inter-roman.var.b2129c009c.woff2 +0 -0
  140. package/packs/widget/esm/index.js +183 -0
  141. package/packs/widget/esm/qualified.css +5502 -0
  142. package/routes/app/offers/scripts/OfferMainScript.js +154 -0
  143. package/routes/app/offers/scripts/constants.js +71 -0
  144. package/routes/app/offers/scripts/main/ButtonManager.js +65 -0
  145. package/routes/app/offers/scripts/main/FormManager.js +325 -0
  146. package/routes/app/offers/scripts/main/MainContext.js +19 -0
  147. package/routes/app/offers/scripts/main/OfferManager.js +91 -0
  148. package/routes/app/offers/scripts/main/TriggerManager.js +125 -0
  149. package/routes/app/offers/scripts/rendering/ContentManager.js +53 -0
  150. package/routes/app/offers/scripts/rendering/LocationManager.js +83 -0
  151. package/routes/app/offers/scripts/rendering/RenderedOffer.js +188 -0
  152. package/routes/app/offers/scripts/rendering/Renderer.js +69 -0
  153. package/routes/app/offers/scripts/rendering/RenderingInitializer.js +62 -0
  154. package/routes/app/offers/scripts/rendering/animations/AnimationManager.js +31 -0
  155. package/routes/app/offers/scripts/rendering/animations/AnimationManagerFooter.js +81 -0
  156. package/routes/app/offers/scripts/rendering/animations/AnimationManagerHeader.js +81 -0
  157. package/routes/app/offers/scripts/rendering/animations/AnimationManagerModal.js +117 -0
  158. package/routes/app/offers/scripts/rendering/animations/AnimationManagerSidebar.js +75 -0
  159. package/routes/app/offers/scripts/rendering/animations/AnimationResult.js +43 -0
  160. package/routes/app/offers/scripts/rendering/animations/Animator.js +78 -0
  161. package/routes/app/offers/scripts/rendering/animations/BaseAnimationManager.js +25 -0
  162. package/routes/app/offers/scripts/rendering/lib/BaseComponent.js +106 -0
  163. package/routes/app/offers/scripts/rendering/lib/FormComponent.js +134 -0
  164. package/routes/app/offers/scripts/rendering/lib/OfferComponent.js +144 -0
  165. package/routes/app/offers/scripts/rendering/lib/ScrollbarWidth.js +27 -0
  166. package/routes/app/offers/scripts/rendering/lib/decorators.js +20 -0
  167. package/routes/app/offers/scripts/rendering/locations/CSSVarsManager.js +66 -0
  168. package/routes/app/offers/scripts/rendering/locations/ElementResizeObserver.js +49 -0
  169. package/routes/app/offers/scripts/rendering/locations/footer.js +53 -0
  170. package/routes/app/offers/scripts/rendering/locations/header/AsyncBatchProcessor.js +70 -0
  171. package/routes/app/offers/scripts/rendering/locations/header/CSSTransitionObserver.js +182 -0
  172. package/routes/app/offers/scripts/rendering/locations/header/ElementStyleChangeObserver.js +138 -0
  173. package/routes/app/offers/scripts/rendering/locations/header/ExternalStyleManager.js +110 -0
  174. package/routes/app/offers/scripts/rendering/locations/header/Header.js +353 -0
  175. package/routes/app/offers/scripts/rendering/locations/header/InlineStyleManager.js +105 -0
  176. package/routes/app/offers/scripts/rendering/locations/header/MatchingElementsObserver.js +107 -0
  177. package/routes/app/offers/scripts/rendering/locations/header/NewElementsObserver.js +129 -0
  178. package/routes/app/offers/scripts/rendering/locations/header/RuleWrapper.js +46 -0
  179. package/routes/app/offers/scripts/rendering/locations/header/SelectorObservable.js +23 -0
  180. package/routes/app/offers/scripts/rendering/locations/header/SelectorObserver.js +61 -0
  181. package/routes/app/offers/scripts/rendering/locations/header/ShiftedElementsManager.js +45 -0
  182. package/routes/app/offers/scripts/rendering/locations/header/StyleElementManager.js +37 -0
  183. package/routes/app/offers/scripts/rendering/locations/header/StyleElementWrapper.js +62 -0
  184. package/routes/app/offers/scripts/rendering/locations/header/StyleSelectorObserver/ObservedSelectorValue.js +45 -0
  185. package/routes/app/offers/scripts/rendering/locations/header/StyleSelectorObserver/ObservedSelectors.js +62 -0
  186. package/routes/app/offers/scripts/rendering/locations/header/StyleSelectorObserver/StyleSelectorObserver.js +294 -0
  187. package/routes/app/offers/scripts/rendering/locations/header/StyleSelectorObserver/constants.js +21 -0
  188. package/routes/app/offers/scripts/rendering/locations/header/WindowResizeObserver.js +43 -0
  189. package/routes/app/offers/scripts/rendering/locations/header/utils.js +25 -0
  190. package/routes/app/offers/scripts/rendering/locations/popup.js +66 -0
  191. package/routes/app/offers/scripts/rendering/locations/sidebar.js +21 -0
  192. package/routes/app/offers/scripts/rendering/variations/ButtonBanner.js +105 -0
  193. package/routes/app/offers/scripts/rendering/variations/ButtonModal.js +114 -0
  194. package/routes/app/offers/scripts/rendering/variations/FormBanner.js +214 -0
  195. package/routes/app/offers/scripts/rendering/variations/FormModal.js +325 -0
  196. package/routes/app/offers/scripts/rendering/variations/LinkBanner.js +105 -0
  197. package/routes/app/offers/scripts/rendering/variations/components/Body.js +29 -0
  198. package/routes/app/offers/scripts/rendering/variations/components/Button.js +128 -0
  199. package/routes/app/offers/scripts/rendering/variations/components/DismissButton.js +39 -0
  200. package/routes/app/offers/scripts/rendering/variations/components/ForegroundImageBanner.js +110 -0
  201. package/routes/app/offers/scripts/rendering/variations/components/ForegroundImageModal.js +128 -0
  202. package/routes/app/offers/scripts/rendering/variations/components/Headline.js +94 -0
  203. package/routes/app/offers/scripts/rendering/variations/components/MultiFieldForm.js +302 -0
  204. package/routes/app/offers/scripts/rendering/variations/components/Tooltip.js +74 -0
  205. package/routes/app/offers/scripts/rendering/variations/icons.js +15 -0
  206. package/routes/app/offers/scripts/utils.js +115 -0
  207. package/routes/app/offers/utils/HTMLUtils.js +10 -0
  208. package/routes/app/offers/utils/createTypeGuard.js +32 -0
  209. package/routes/app/offers/utils/promise-utils.js +22 -0
  210. package/routes/app/websiteBuilder/stores/storeHelpers.js +18 -0
  211. package/sounds/message-initial.mp3 +0 -0
  212. package/sounds/message-received.mp3 +0 -0
  213. package/sounds/message-sent.mp3 +0 -0
  214. package/src/arrays.js +15 -0
  215. package/src/audio.js +106 -0
  216. package/src/bounded-set.js +16 -0
  217. package/src/bounding_box_observer.js +129 -0
  218. package/src/decorators.js +29 -0
  219. package/src/dom.js +128 -0
  220. package/src/dom_roots.js +26 -0
  221. package/src/embedded_forms/EmbeddedForm.js +638 -0
  222. package/src/embedded_forms/QualifiedEmbeddedForm.js +51 -0
  223. package/src/embedded_forms/QualifiedFormField.js +137 -0
  224. package/src/embedded_forms/utils.js +17 -0
  225. package/src/graphql-types.js +1686 -0
  226. package/src/iframes.js +86 -0
  227. package/src/localstorage.js +43 -0
  228. package/src/mirror/Shipper.js +133 -0
  229. package/src/mirror/constants.generated.js +13 -0
  230. package/src/mirror/constants.js +238 -0
  231. package/src/mirror/shipper/ChangeQueue.js +155 -0
  232. package/src/mirror/shipper/DOMSerializer.js +392 -0
  233. package/src/mirror/shipper/observers.js +441 -0
  234. package/src/mirror/shipper/utils.js +98 -0
  235. package/src/mixins/disposable.js +125 -0
  236. package/src/mixins/injectable.js +37 -0
  237. package/src/personalizations/personalization-manager.js +110 -0
  238. package/src/personalizations/strategies/node-freezing-strategy.js +174 -0
  239. package/src/personalizations/utils.js +187 -0
  240. package/src/promises.js +107 -0
  241. package/src/proxy.js +144 -0
  242. package/src/qualified_root.js +35 -0
  243. package/src/query_params.js +55 -0
  244. package/src/shadow-dom-helper.js +63 -0
  245. package/src/singleton_host.js +39 -0
  246. package/src/smart_website/trigger.js +49 -0
  247. package/src/smart_website/utils.js +149 -0
  248. package/src/string.js +53 -0
  249. package/src/timezone.js +57 -0
  250. package/src/timing.js +49 -0
  251. package/src/type-utils.js +76 -0
  252. package/src/url-utils.js +102 -0
  253. package/src/url.js +50 -0
  254. package/src/utils.js +72 -0
  255. package/src/validation.js.js +29 -0
  256. package/src/validation_ts.js +6 -0
  257. package/vendor/actioncable/adapters.js +6 -0
  258. package/vendor/actioncable/connection.js +204 -0
  259. package/vendor/actioncable/connection_monitor.js +129 -0
  260. package/vendor/actioncable/consumer.js +91 -0
  261. package/vendor/actioncable/index.js +34 -0
  262. package/vendor/actioncable/internal.js +22 -0
  263. package/vendor/actioncable/logger.js +28 -0
  264. package/vendor/actioncable/subscription.js +93 -0
  265. package/vendor/actioncable/subscriptions.js +89 -0
  266. package/vendor/open-telemetry-idgenerator.js +43 -0
  267. package/widget/analytics/facebook_tracker.js +8 -0
  268. package/widget/analytics/google_analytics_tracker.js +83 -0
  269. package/widget/analytics/google_tag_manager_tracker.js +22 -0
  270. package/widget/analytics.js +58 -0
  271. package/widget/api_handler/api_handler.js +730 -0
  272. package/widget/api_handler/base_api_handler.js +249 -0
  273. package/widget/booker_intent_tracker.js +391 -0
  274. package/widget/booker_outcome_tracker.js +329 -0
  275. package/widget/capture_widget_exceptions.js +150 -0
  276. package/widget/channel.js +282 -0
  277. package/widget/composite_experience_adapter.js +101 -0
  278. package/widget/constants.generated.js +350 -0
  279. package/widget/constants.js +21 -0
  280. package/widget/container.js +193 -0
  281. package/widget/content_activity_emitter.js +36 -0
  282. package/widget/data360_visitor.js +67 -0
  283. package/widget/date_provider.js +11 -0
  284. package/widget/debug_mode_state.js +175 -0
  285. package/widget/dummy_module.js +9 -0
  286. package/widget/eloqua_visitor.js +17 -0
  287. package/widget/form_cta_booker_intent.js +246 -0
  288. package/widget/hubspot_visitor.js +39 -0
  289. package/widget/inline_meeting_booker_page.js +90 -0
  290. package/widget/local_state/abstract_local_state.js +38 -0
  291. package/widget/local_state/debug_state/abstract_debug_flow.js +29 -0
  292. package/widget/local_state/debug_state/custom_form_flow.js +14 -0
  293. package/widget/local_state/debug_state/hubspot_form_flow.js +19 -0
  294. package/widget/local_state/debug_state/hubspot_v4_form_flow.js +19 -0
  295. package/widget/local_state/debug_state/marketo_form_flow.js +20 -0
  296. package/widget/local_state/debug_state/pardot_form_flow.js +18 -0
  297. package/widget/local_state/debug_state.js +362 -0
  298. package/widget/local_state/trace_state.js +20 -0
  299. package/widget/location_provider.js +9 -0
  300. package/widget/marketo_visitor.js +39 -0
  301. package/widget/meetings/tracing/buttons_forms_triggering_tracer.js +124 -0
  302. package/widget/meetings/tracing/spans/button_spans.js +18 -0
  303. package/widget/meetings/tracing/spans/form_spans.js +11 -0
  304. package/widget/multimodal_v2/assets_preloader.js +97 -0
  305. package/widget/multimodal_v2/components/AppLayout.js +93 -0
  306. package/widget/multimodal_v2/components/CursorOverlay.js +93 -0
  307. package/widget/multimodal_v2/components/PointerRectOverlay.js +74 -0
  308. package/widget/multimodal_v2/components/app/Artifact.js +109 -0
  309. package/widget/multimodal_v2/components/app/Background.js +27 -0
  310. package/widget/multimodal_v2/components/app/CalendarLoadingContent.js +255 -0
  311. package/widget/multimodal_v2/components/app/Chat.js +39 -0
  312. package/widget/multimodal_v2/components/app/CookieConsentModal.js +149 -0
  313. package/widget/multimodal_v2/components/app/Foreground.js +48 -0
  314. package/widget/multimodal_v2/components/app/HiddenInput.js +41 -0
  315. package/widget/multimodal_v2/components/app/Input.js +72 -0
  316. package/widget/multimodal_v2/components/app/LightboxExperience.js +769 -0
  317. package/widget/multimodal_v2/components/app/LoadingOverlay.js +97 -0
  318. package/widget/multimodal_v2/components/app/Main.js +985 -0
  319. package/widget/multimodal_v2/components/app/MessengerButton.js +160 -0
  320. package/widget/multimodal_v2/components/app/Multimodal.js +17 -0
  321. package/widget/multimodal_v2/components/app/OverlayControls.js +79 -0
  322. package/widget/multimodal_v2/components/app/Preview.js +32 -0
  323. package/widget/multimodal_v2/components/app/PrivacyDisclosure.js +57 -0
  324. package/widget/multimodal_v2/components/app/RotateDeviceOverlay.js +70 -0
  325. package/widget/multimodal_v2/components/app/Toolbar.js +156 -0
  326. package/widget/multimodal_v2/components/chat/ChatComposer.js +129 -0
  327. package/widget/multimodal_v2/components/chat/ChatInputForm.js +398 -0
  328. package/widget/multimodal_v2/components/chat/ColdStartQuestions.js +354 -0
  329. package/widget/multimodal_v2/components/chat/ComposerErrorBanner.js +62 -0
  330. package/widget/multimodal_v2/components/chat/PostCallSurvey.js +359 -0
  331. package/widget/multimodal_v2/components/chat/preview/FieldRequestRenderer.js +41 -0
  332. package/widget/multimodal_v2/components/chat/preview/PreviewMessageRenderer.js +60 -0
  333. package/widget/multimodal_v2/components/chat/preview/SharedOfferRenderer.js +143 -0
  334. package/widget/multimodal_v2/components/chat/preview/TextRenderer.js +27 -0
  335. package/widget/multimodal_v2/components/chat/preview/TimelinePreview.js +254 -0
  336. package/widget/multimodal_v2/components/chat/timeline/CalendarEventOfferRenderer.js +103 -0
  337. package/widget/multimodal_v2/components/chat/timeline/CalendarEventPickRenderer.js +148 -0
  338. package/widget/multimodal_v2/components/chat/timeline/FieldEntryRenderer.js +84 -0
  339. package/widget/multimodal_v2/components/chat/timeline/FieldRequestRenderer.js +56 -0
  340. package/widget/multimodal_v2/components/chat/timeline/InlinePrivacyDisclosure.js +66 -0
  341. package/widget/multimodal_v2/components/chat/timeline/LinkPreviewCard.js +70 -0
  342. package/widget/multimodal_v2/components/chat/timeline/MessageEntry.js +88 -0
  343. package/widget/multimodal_v2/components/chat/timeline/PresentContentRenderer.js +30 -0
  344. package/widget/multimodal_v2/components/chat/timeline/PresentDeckRenderer.js +279 -0
  345. package/widget/multimodal_v2/components/chat/timeline/PresentVideoRenderer.js +131 -0
  346. package/widget/multimodal_v2/components/chat/timeline/ShareContentRenderer.js +59 -0
  347. package/widget/multimodal_v2/components/chat/timeline/SharedOfferRenderer.js +131 -0
  348. package/widget/multimodal_v2/components/chat/timeline/SystemRenderer.js +82 -0
  349. package/widget/multimodal_v2/components/chat/timeline/TextRenderer.js +66 -0
  350. package/widget/multimodal_v2/components/chat/timeline/Timeline.js +158 -0
  351. package/widget/multimodal_v2/components/debug/DebugMultimodalPanel.js +327 -0
  352. package/widget/multimodal_v2/components/decks/index.js +160 -0
  353. package/widget/multimodal_v2/components/field_request/BooleanField.js +77 -0
  354. package/widget/multimodal_v2/components/field_request/FieldComponents.js +69 -0
  355. package/widget/multimodal_v2/components/field_request/Form.js +87 -0
  356. package/widget/multimodal_v2/components/field_request/MultiPicklistField.js +240 -0
  357. package/widget/multimodal_v2/components/field_request/PicklistField.js +166 -0
  358. package/widget/multimodal_v2/components/field_request/SingleLineInputField.js +69 -0
  359. package/widget/multimodal_v2/components/field_request/TextField.js +37 -0
  360. package/widget/multimodal_v2/components/field_request/index.js +170 -0
  361. package/widget/multimodal_v2/components/helpers/AutoScroll.js +37 -0
  362. package/widget/multimodal_v2/components/helpers/ErrorBoundary.js +53 -0
  363. package/widget/multimodal_v2/components/helpers/FocusTrapDialog.js +26 -0
  364. package/widget/multimodal_v2/components/helpers/ImpressionTracker.js +94 -0
  365. package/widget/multimodal_v2/components/helpers/ListRenderer.js +37 -0
  366. package/widget/multimodal_v2/components/helpers/Localization.js +76 -0
  367. package/widget/multimodal_v2/components/helpers/Persisted.js +166 -0
  368. package/widget/multimodal_v2/components/helpers/RichText.js +358 -0
  369. package/widget/multimodal_v2/components/helpers/ScreenReaderHeading.js +17 -0
  370. package/widget/multimodal_v2/components/helpers/Thumbnail.js +190 -0
  371. package/widget/multimodal_v2/components/helpers/VisuallyHidden.js +41 -0
  372. package/widget/multimodal_v2/components/helpers/content_click_payloads.js +58 -0
  373. package/widget/multimodal_v2/components/helpers/useDraggable.js +103 -0
  374. package/widget/multimodal_v2/components/helpers/useTextOverflow.js +44 -0
  375. package/widget/multimodal_v2/components/lightbox_gather/index.js +741 -0
  376. package/widget/multimodal_v2/components/meetings/ArtifactEntryPoint.js +252 -0
  377. package/widget/multimodal_v2/components/meetings/MeetingAdditionalAttendees.js +325 -0
  378. package/widget/multimodal_v2/components/meetings/MeetingBookerEntry.js +100 -0
  379. package/widget/multimodal_v2/components/meetings/MeetingDetailsCard.js +99 -0
  380. package/widget/multimodal_v2/components/meetings/MeetingErrorBanner.js +62 -0
  381. package/widget/multimodal_v2/components/meetings/MeetingOfferEmailStep.js +239 -0
  382. package/widget/multimodal_v2/components/meetings/MeetingOfferFooter.js +104 -0
  383. package/widget/multimodal_v2/components/meetings/MeetingOfferSelectionStep.js +60 -0
  384. package/widget/multimodal_v2/components/meetings/MeetingRepHeader.js +222 -0
  385. package/widget/multimodal_v2/components/meetings/MeetingStepShell.js +92 -0
  386. package/widget/multimodal_v2/components/meetings/MeetingSummaryRail.js +515 -0
  387. package/widget/multimodal_v2/components/meetings/MeetingTimeSelector.js +603 -0
  388. package/widget/multimodal_v2/components/meetings/MonthDatePicker.js +422 -0
  389. package/widget/multimodal_v2/components/meetings/NavigationButtons.js +76 -0
  390. package/widget/multimodal_v2/components/meetings/TimeSlotHeader.js +357 -0
  391. package/widget/multimodal_v2/components/meetings/WeekViewHeader.js +20 -0
  392. package/widget/multimodal_v2/components/meetings/constants.js +7 -0
  393. package/widget/multimodal_v2/components/meetings/index.js +47 -0
  394. package/widget/multimodal_v2/components/meetings/utils.js +328 -0
  395. package/widget/multimodal_v2/components/multimodal/Audio.js +28 -0
  396. package/widget/multimodal_v2/components/multimodal/Controls.js +188 -0
  397. package/widget/multimodal_v2/components/multimodal/LiveVideo.js +63 -0
  398. package/widget/multimodal_v2/components/multimodal/MultiModalComponent.js +424 -0
  399. package/widget/multimodal_v2/components/multimodal/MultimodalAvatar.js +36 -0
  400. package/widget/multimodal_v2/components/multimodal/OrbAvatar.js +326 -0
  401. package/widget/multimodal_v2/components/multimodal/Status.js +220 -0
  402. package/widget/multimodal_v2/components/multimodal/VideoAvatar.js +24 -0
  403. package/widget/multimodal_v2/components/multimodal/VideoPreview.js +114 -0
  404. package/widget/multimodal_v2/components/multimodal/useAudioLevelMonitoring.js +96 -0
  405. package/widget/multimodal_v2/components/multimodal/useMultimodal.js +434 -0
  406. package/widget/multimodal_v2/components/presentations/index.js +372 -0
  407. package/widget/multimodal_v2/components/shared/Avatar.js +92 -0
  408. package/widget/multimodal_v2/components/shared/AvatarGroup.js +135 -0
  409. package/widget/multimodal_v2/components/shared/Button.js +245 -0
  410. package/widget/multimodal_v2/components/shared/ButtonGroup.js +133 -0
  411. package/widget/multimodal_v2/components/shared/ComposerForm.js +98 -0
  412. package/widget/multimodal_v2/components/shared/SpeakingIndicator.js +239 -0
  413. package/widget/multimodal_v2/components/shared/ThinkingAnimation.js +165 -0
  414. package/widget/multimodal_v2/components/shared/Tooltip.js +266 -0
  415. package/widget/multimodal_v2/components/shared/controls/Dropdown.js +79 -0
  416. package/widget/multimodal_v2/components/shared/controls/PillToggle.js +142 -0
  417. package/widget/multimodal_v2/components/shared/controls/TextArea.js +114 -0
  418. package/widget/multimodal_v2/components/shared/toolCallLabels.js +12 -0
  419. package/widget/multimodal_v2/components/slides/SlidesThumbnail.js +47 -0
  420. package/widget/multimodal_v2/components/slides/index.js +61 -0
  421. package/widget/multimodal_v2/constants.js +88 -0
  422. package/widget/multimodal_v2/host.split-css.js +2 -0
  423. package/widget/multimodal_v2/host.string.js +96 -0
  424. package/widget/multimodal_v2/images/icons.js +582 -0
  425. package/widget/multimodal_v2/images/posters/piper_low_res.jpg +0 -0
  426. package/widget/multimodal_v2/index.js +23 -0
  427. package/widget/multimodal_v2/index.panda.js +28 -0
  428. package/widget/multimodal_v2/index.split-css.panda.js +2 -0
  429. package/widget/multimodal_v2/inline_meeting_booker.js +182 -0
  430. package/widget/multimodal_v2/locales/cs.js +196 -0
  431. package/widget/multimodal_v2/locales/da.js +196 -0
  432. package/widget/multimodal_v2/locales/de.js +196 -0
  433. package/widget/multimodal_v2/locales/en.js +196 -0
  434. package/widget/multimodal_v2/locales/en_AU.js +197 -0
  435. package/widget/multimodal_v2/locales/en_GB.js +197 -0
  436. package/widget/multimodal_v2/locales/es.js +197 -0
  437. package/widget/multimodal_v2/locales/es_LA.js +196 -0
  438. package/widget/multimodal_v2/locales/fi.js +196 -0
  439. package/widget/multimodal_v2/locales/fr.js +197 -0
  440. package/widget/multimodal_v2/locales/fr_CA.js +196 -0
  441. package/widget/multimodal_v2/locales/id.js +196 -0
  442. package/widget/multimodal_v2/locales/index.js +48 -0
  443. package/widget/multimodal_v2/locales/it.js +196 -0
  444. package/widget/multimodal_v2/locales/ja.js +196 -0
  445. package/widget/multimodal_v2/locales/ko.js +196 -0
  446. package/widget/multimodal_v2/locales/nb.js +196 -0
  447. package/widget/multimodal_v2/locales/nl.js +196 -0
  448. package/widget/multimodal_v2/locales/pl.js +196 -0
  449. package/widget/multimodal_v2/locales/pt_BR.js +196 -0
  450. package/widget/multimodal_v2/locales/ru.js +196 -0
  451. package/widget/multimodal_v2/locales/sv.js +196 -0
  452. package/widget/multimodal_v2/locales/th.js +196 -0
  453. package/widget/multimodal_v2/locales/tr.js +196 -0
  454. package/widget/multimodal_v2/locales/vi.js +196 -0
  455. package/widget/multimodal_v2/locales/zh_CN.js +196 -0
  456. package/widget/multimodal_v2/locales/zh_TW.js +196 -0
  457. package/widget/multimodal_v2/multimodal.js +633 -0
  458. package/widget/multimodal_v2/multimodal_channel.js +195 -0
  459. package/widget/multimodal_v2/signals/active_conversation_signal.js +33 -0
  460. package/widget/multimodal_v2/signals/allowed_conversation_mode_signal.js +38 -0
  461. package/widget/multimodal_v2/signals/artifact_signal.js +22 -0
  462. package/widget/multimodal_v2/signals/layout_signal.js +98 -0
  463. package/widget/multimodal_v2/signals/messages_signal.js +207 -0
  464. package/widget/multimodal_v2/signals/ui_state_signal.js +128 -0
  465. package/widget/multimodal_v2/stable_bundle_src.js +44 -0
  466. package/widget/multimodal_v2/stores/ai_conversation_store.js +221 -0
  467. package/widget/multimodal_v2/stores/artifact_store.js +205 -0
  468. package/widget/multimodal_v2/stores/base_store.js +16 -0
  469. package/widget/multimodal_v2/stores/call_store.js +770 -0
  470. package/widget/multimodal_v2/stores/call_ui_adapter.js +225 -0
  471. package/widget/multimodal_v2/stores/debug_multimodal_scenario_store.js +471 -0
  472. package/widget/multimodal_v2/stores/decks_store.js +285 -0
  473. package/widget/multimodal_v2/stores/device_store.js +63 -0
  474. package/widget/multimodal_v2/stores/docking_store.js +62 -0
  475. package/widget/multimodal_v2/stores/field_request_store.js +326 -0
  476. package/widget/multimodal_v2/stores/meeting_store.js +477 -0
  477. package/widget/multimodal_v2/stores/participant_store.js +73 -0
  478. package/widget/multimodal_v2/stores/post_call_survey_store.js +160 -0
  479. package/widget/multimodal_v2/stores/pounce_tracking_store.js +163 -0
  480. package/widget/multimodal_v2/stores/pounce_tracking_store_v2.js +511 -0
  481. package/widget/multimodal_v2/stores/presentations_store.js +111 -0
  482. package/widget/multimodal_v2/stores/root_store.js +1919 -0
  483. package/widget/multimodal_v2/stores/screen_share_store.js +217 -0
  484. package/widget/multimodal_v2/stores/slides_store.js +21 -0
  485. package/widget/multimodal_v2/stores/translation_store.js +185 -0
  486. package/widget/multimodal_v2/stores/ui_store.js +496 -0
  487. package/widget/multimodal_v2/stores/waiting_store.js +159 -0
  488. package/widget/multimodal_v2/stores/website_navigation_store.js +767 -0
  489. package/widget/multimodal_v2/styled-system/css/conditions.js +34 -0
  490. package/widget/multimodal_v2/styled-system/css/css.js +48 -0
  491. package/widget/multimodal_v2/styled-system/css/cva.js +96 -0
  492. package/widget/multimodal_v2/styled-system/css/cx.js +13 -0
  493. package/widget/multimodal_v2/styled-system/css/index.js +15 -0
  494. package/widget/multimodal_v2/styled-system/css/sva.js +69 -0
  495. package/widget/multimodal_v2/styled-system/helpers.js +384 -0
  496. package/widget/multimodal_v2/styled-system/jsx/create-style-context.js +96 -0
  497. package/widget/multimodal_v2/styled-system/jsx/factory-helper.js +19 -0
  498. package/widget/multimodal_v2/styled-system/jsx/factory.js +111 -0
  499. package/widget/multimodal_v2/styled-system/jsx/index.js +12 -0
  500. package/widget/multimodal_v2/styled-system/jsx/is-valid-prop.js +22 -0
  501. package/widget/multimodal_v2/types.js +105 -0
  502. package/widget/multimodal_v2/utils/auto_scroller.js +157 -0
  503. package/widget/multimodal_v2/utils/flip_animation.js +124 -0
  504. package/widget/multimodal_v2/utils/focus_gate.js +237 -0
  505. package/widget/multimodal_v2/utils/locale.js +16 -0
  506. package/widget/multimodal_v2/utils/media_queries.js +30 -0
  507. package/widget/multimodal_v2/utils/multimodal_cache.js +19 -0
  508. package/widget/multimodal_v2/utils/mutation_effect.js +14 -0
  509. package/widget/multimodal_v2/utils/navigation_interceptor.js +205 -0
  510. package/widget/multimodal_v2/utils/navigation_strategies/dom_swap.js +393 -0
  511. package/widget/multimodal_v2/utils/navigation_strategies/index.js +12 -0
  512. package/widget/multimodal_v2/utils/navigation_strategies/lwr.js +61 -0
  513. package/widget/multimodal_v2/utils/navigation_strategies/navigation_utils.js +46 -0
  514. package/widget/multimodal_v2/utils/navigation_strategies/next_js.js +24 -0
  515. package/widget/multimodal_v2/utils/navigation_strategies/wouter_v3.js +15 -0
  516. package/widget/multimodal_v2/utils/objects_map.js +38 -0
  517. package/widget/multimodal_v2/utils/perceived_voice_turn_tracker.js +345 -0
  518. package/widget/multimodal_v2/utils/sanitize_html.js +132 -0
  519. package/widget/multimodal_v2/utils/signals.js +97 -0
  520. package/widget/multimodal_v2/utils/slide_zoom.js +114 -0
  521. package/widget/multimodal_v2/utils/theme_styles.js +137 -0
  522. package/widget/multimodal_v2/utils/url_observer.js +52 -0
  523. package/widget/multimodal_v2/utils/voice_onset_detector.js +127 -0
  524. package/widget/page_mirror.js +89 -0
  525. package/widget/page_view_activity_emitter.js +71 -0
  526. package/widget/pardot_visitor.js +137 -0
  527. package/widget/personalization_observer.js +96 -0
  528. package/widget/personalizations_config.js +160 -0
  529. package/widget/qualified_form/constants.js +23 -0
  530. package/widget/qualified_form/phone_utils.js +38 -0
  531. package/widget/qualified_form/qualified_form_action.js +91 -0
  532. package/widget/qualified_form/qualified_form_action_orchestrator.js +21 -0
  533. package/widget/qualified_form/qualified_form_api.js +471 -0
  534. package/widget/scroll_disabler.js +109 -0
  535. package/widget/server-logger.js +156 -0
  536. package/widget/smart_website_config.js +112 -0
  537. package/widget/telemetry/context.js +75 -0
  538. package/widget/telemetry/index.js +16 -0
  539. package/widget/telemetry/messenger_uptime.js +80 -0
  540. package/widget/telemetry/metrics.js +120 -0
  541. package/widget/telemetry/span.js +82 -0
  542. package/widget/telemetry/telemetry.js +180 -0
  543. package/widget/telemetry/tracer.js +41 -0
  544. package/widget/telemetry/tracing_store.js +310 -0
  545. package/widget/tracker.js +916 -0
  546. package/widget/utils/native_globals.js +129 -0
  547. package/widget/v1_adapter.js +50 -0
  548. package/widget/v2_adapter.js +368 -0
  549. package/widget/visitor/base_visitor_state.js +11 -0
  550. package/widget/visitor/cookie_visitor_state.js +128 -0
  551. package/widget/visitor/in_memory_visitor_state.js +29 -0
  552. package/widget/visitor/visitor_state.js +384 -0
  553. package/widget/visitor.js +356 -0
  554. package/widget/widget/linked_widget_v2.js +227 -0
  555. package/widget/widget/page_mirror_factory.js +22 -0
  556. package/widget/widget/sentry.js +130 -0
  557. package/widget/widget/widget.js +1698 -0
  558. package/widget/widget.split-css.js +2 -0
  559. package/widget/widget_bootstrap.js +97 -0
  560. package/widget/widget_object.js +73 -0
@@ -0,0 +1,1919 @@
1
+ import { __webpack_require__ } from "../../../js/runtime.js";
2
+ import { hooks_module_x, message_initial_namespaceObject, Q, message_sent_namespaceObject, signals_core_module_d, signals_core_module_w, message_received_namespaceObject, signals_core_module_r } from "../../../js/multimodal_v2.js";
3
+ import { playAudio } from "../../../src/audio.js";
4
+ import { BoundedSet } from "../../../src/bounded-set.js";
5
+ import { isDebugMode } from "../../../src/smart_website/utils.js";
6
+ import { snakify } from "../../../src/utils.js";
7
+ import { BookerIntentTracker } from "../../booker_intent_tracker.js";
8
+ import { BOOKER_PATHWAY_ORIGIN, BOOKER_SURFACE } from "../../booker_outcome_tracker.js";
9
+ import { serverLogger } from "../../server-logger.js";
10
+ import "../../telemetry/index.js";
11
+ import { getSentryClient } from "../../widget/sentry.js";
12
+ import { CAN_OFFER_MEETING_BOOKER_EVENT_TYPE } from "../constants.js";
13
+ import { createActiveConversationSignal } from "../signals/active_conversation_signal.js";
14
+ import { createMessagesSignal, isStreamableMessage, isAssistantMessage, isEventMessage } from "../signals/messages_signal.js";
15
+ import { $fromImport } from "../utils/signals.js";
16
+ import { ArtifactStore } from "./artifact_store.js";
17
+ import { getCallUiAdapter } from "./call_ui_adapter.js";
18
+ import { DockingStore } from "./docking_store.js";
19
+ import { TranslationStore } from "./translation_store.js";
20
+ import { UIStore } from "./ui_store.js";
21
+ import { BaseStore } from "./base_store.js";
22
+ import "../../utils/native_globals.js";
23
+ import { validateEmail } from "../../../src/validation.js.js";
24
+ import { ConversationMode as types_ConversationMode, LoadingState as types_LoadingState, DisplayMode as types_DisplayMode, MaximizedState as types_MaximizedState, InputState as types_InputState } from "../types.js";
25
+ import { buildCustEvChatViewPayload, buildCustEvContentImpressionPayload } from "../components/helpers/content_click_payloads.js";
26
+ import { esm_browser_v4 } from "../../../js/4101.js";
27
+ import { metrics } from "../../telemetry/metrics.js";
28
+
29
+ /* provided dependency */ var __nativeDocumentRemoveEventListener = __webpack_require__(68034).LA;
30
+ /* provided dependency */ var root_store_setTimeout = __webpack_require__(68034).pS;
31
+ /* provided dependency */ var root_store_clearTimeout = __webpack_require__(68034).Kj;
32
+ /* provided dependency */ var __nativeDocumentAddEventListener = __webpack_require__(68034).Qj;
33
+ function _extends() {
34
+ _extends = Object.assign || function(target) {
35
+ for(var i = 1; i < arguments.length; i++){
36
+ var source = arguments[i];
37
+ for(var key in source){
38
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
39
+ target[key] = source[key];
40
+ }
41
+ }
42
+ }
43
+ return target;
44
+ };
45
+ return _extends.apply(this, arguments);
46
+ }
47
+ function _object_without_properties_loose(source, excluded) {
48
+ if (source == null) return {};
49
+ var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
50
+ for(i = 0; i < sourceKeys.length; i++){
51
+ key = sourceKeys[i];
52
+ if (excluded.indexOf(key) >= 0) continue;
53
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
54
+ target[key] = source[key];
55
+ }
56
+ return target;
57
+ }
58
+ /* eslint-disable no-continue */
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+ // A reply slower than RESPONSE_BUDGET_MS (or none at all) counts as unavailable. Both live in the
88
+ // leaf constants module (avoids a store import cycle), re-exported so `from "./root_store"`
89
+ // importers still work.
90
+
91
+ /**
92
+ * Whether an offer was authored by the AI rather than a rep, a form, or a bot
93
+ * script. `auto_respond` is the same marker `bookerPathwayOrigin` reads to
94
+ * classify an offer as `ai_agent`; both AI tool paths stamp it.
95
+ */ function isAiAuthoredOffer(source) {
96
+ return (source != null ? source : "").toLowerCase() === "auto_respond";
97
+ }
98
+ class RootStore extends BaseStore {
99
+ get allowVoiceVideoToggle() {
100
+ return this.uiStore.allowVoiceVideoToggle;
101
+ }
102
+ /**
103
+ * Get the appropriate CallUiAdapter for the current context.
104
+ * In debug mode, returns a debug adapter backed by DebugMultimodalScenarioStore.
105
+ * Otherwise, returns the real adapter backed by CallStore/DeviceStore/TavusStore.
106
+ */ getCallUiAdapter() {
107
+ return getCallUiAdapter(this);
108
+ }
109
+ // --- Backward-compat getters delegating to UIStore ---
110
+ get uiState() {
111
+ return this.uiStore.uiState;
112
+ }
113
+ get maximizedState() {
114
+ return this.uiStore.maximizedState;
115
+ }
116
+ get initialDisplayMode() {
117
+ return this.uiStore.initialDisplayMode;
118
+ }
119
+ get openedDisplayMode() {
120
+ return this.uiStore.openedDisplayMode;
121
+ }
122
+ get launcherImageUrl() {
123
+ return this.uiStore.launcherImageUrl;
124
+ }
125
+ get orbConfig() {
126
+ return this.uiStore.orbConfig;
127
+ }
128
+ get previewVideoConfig() {
129
+ return this.uiStore.previewVideoConfig;
130
+ }
131
+ get demoFeatures() {
132
+ return this.uiStore.demoFeatures;
133
+ }
134
+ get layout() {
135
+ return this.uiStore.layout;
136
+ }
137
+ get piperConversationId() {
138
+ var _ref;
139
+ const conversation = this.activeConversation.value;
140
+ return (_ref = conversation == null ? void 0 : conversation.encodedId) != null ? _ref : "";
141
+ }
142
+ get featureFlags() {
143
+ var _ref;
144
+ var _this_config;
145
+ return (_ref = (_this_config = this.config) == null ? void 0 : _this_config.featureFlags) != null ? _ref : {};
146
+ }
147
+ /**
148
+ * Server-side email validation shared by chat and meeting flows.
149
+ * Fail-open: network / API errors treat the email as valid.
150
+ */ async validateEmail(email, source) {
151
+ if (source === void 0) source = "Chat";
152
+ try {
153
+ const url = this.visitor.resourceUrl("validate_email", {});
154
+ const response = await fetch(url, {
155
+ method: "POST",
156
+ headers: {
157
+ "Content-Type": "application/json; charset=utf-8"
158
+ },
159
+ body: JSON.stringify({
160
+ email,
161
+ source
162
+ })
163
+ });
164
+ if (response.ok) {
165
+ const json = await response.json();
166
+ return json.valid !== false;
167
+ }
168
+ return true;
169
+ } catch (error) {
170
+ var _getSentryClient;
171
+ (_getSentryClient = getSentryClient({
172
+ project: "multimodal"
173
+ })) == null ? void 0 : _getSentryClient.captureException(error);
174
+ return true;
175
+ }
176
+ }
177
+ get displayMode() {
178
+ return this.uiStore.displayMode;
179
+ }
180
+ get conversationMode() {
181
+ return this.uiStore.conversationMode;
182
+ }
183
+ get input() {
184
+ return this.uiStore.input;
185
+ }
186
+ get artifact() {
187
+ return this.artifactStore.current;
188
+ }
189
+ /** Messages whose artifact is on its way into the overlay. See ArtifactStore#pending. */ get pendingArtifacts() {
190
+ return this.artifactStore.pending;
191
+ }
192
+ get userHasIgnoredMultimodal() {
193
+ return this.uiStore.userHasIgnoredMultimodal;
194
+ }
195
+ get isPiP() {
196
+ return this.uiStore.isPiP;
197
+ }
198
+ dispose() {
199
+ var _this_pounceTrackingStore_value, _this_callStore_value, _this_waitingStore_value, _this_websiteNavigationStore_value, _this_presentationsStore_value, _this_decksStore_value, _this_screenShareStore_value;
200
+ // Unsubscribe WS message handlers from the (persistent) channel so a rebuilt
201
+ // store doesn't run alongside this disposed one when the multimodal UI is
202
+ // torn down and later recreated on the same channel.
203
+ for (const [event, handler] of Object.entries(this.messageHandlers)){
204
+ this.channel.off(event, handler);
205
+ }
206
+ this.dockingStore.disable();
207
+ // Armed trackers hold window/document listeners; the multimodal rebuild path
208
+ // replaces this store in-page, so an undisposed tracker would outlive it and
209
+ // emit a false abandonment alongside its replacement.
210
+ this.bookerIntentTracker.dispose();
211
+ (_this_pounceTrackingStore_value = this.pounceTrackingStore.value) == null ? void 0 : _this_pounceTrackingStore_value.dispose();
212
+ (_this_callStore_value = this.callStore.value) == null ? void 0 : _this_callStore_value.dispose();
213
+ (_this_waitingStore_value = this.waitingStore.value) == null ? void 0 : _this_waitingStore_value.dispose();
214
+ (_this_websiteNavigationStore_value = this.websiteNavigationStore.value) == null ? void 0 : _this_websiteNavigationStore_value.dispose();
215
+ (_this_presentationsStore_value = this.presentationsStore.value) == null ? void 0 : _this_presentationsStore_value.dispose();
216
+ (_this_decksStore_value = this.decksStore.value) == null ? void 0 : _this_decksStore_value.dispose();
217
+ (_this_screenShareStore_value = this.screenShareStore.value) == null ? void 0 : _this_screenShareStore_value.dispose();
218
+ this.clearResponseTimeout();
219
+ this.flushHeldTimeout();
220
+ this.turnToken++;
221
+ if (typeof document !== "undefined") {
222
+ __nativeDocumentRemoveEventListener("visibilitychange", this.handleTurnVisibilityChange);
223
+ }
224
+ }
225
+ startTextTurn(messageClientId) {
226
+ // Before any per-turn state resets: the held metric belongs to the turn that
227
+ // just timed out and reads `turnCause` when it fires.
228
+ this.flushHeldTimeout();
229
+ this.lastVisitorMessageSentAt = performance.now();
230
+ this.turnMessageClientId = messageClientId;
231
+ this.turnCounterEmitted = false;
232
+ this.turnReplyHandled = false;
233
+ this.turnObscured = this.isDocumentHidden();
234
+ this.turnCallActive = this.callInProgress.peek();
235
+ this.turnCause = null;
236
+ this.turnHasToolCall = false;
237
+ const token = ++this.turnToken;
238
+ this.clearResponseTimeout();
239
+ this.responseTimeoutId = root_store_setTimeout(()=>{
240
+ this.responseTimeoutId = null;
241
+ if (token !== this.turnToken || this.turnCounterEmitted) return;
242
+ // Treat the turn as obscured if the tab was hidden at any point, not just
243
+ // now: backgrounded tabs throttle setTimeout, so the timer often fires only
244
+ // after the visitor returns (document.hidden already false). Checking the
245
+ // whole wait keeps that throttling delay out of the timeout (unavailable) count.
246
+ const obscured = this.turnObscured || this.isDocumentHidden();
247
+ // The turn is counted from this moment, whenever the metric actually
248
+ // leaves: a reply or a `textResponseEnded` arriving later must not talk us
249
+ // out of a timeout the visitor has already experienced.
250
+ this.turnCounterEmitted = true;
251
+ if (obscured) {
252
+ metrics.emitIncrement("multimodal_text_response", {
253
+ status: "backgrounded",
254
+ call_active: this.turnCallActiveTag
255
+ });
256
+ return;
257
+ }
258
+ // Before the breadcrumb: nothing between latching the outcome and arming the
259
+ // emission, so a counted timeout cannot be lost to a failure in between.
260
+ this.holdTimeoutForCause();
261
+ serverLogger.serverLog({
262
+ type: "log",
263
+ message: "Multimodal text reply did not arrive within response budget"
264
+ });
265
+ }, (/* inlined export .RESPONSE_BUDGET_MS */25000));
266
+ return token;
267
+ }
268
+ get turnCallActiveTag() {
269
+ return this.turnCallActive ? "true" : "false";
270
+ }
271
+ /**
272
+ * Holds a decided timeout's metric back briefly so the server's cause report
273
+ * can land on it (see CAUSE_REPORT_GRACE_MS). Only the `cause` tag is
274
+ * outstanding — the turn is already counted — so this delays an emission, it
275
+ * never changes an outcome.
276
+ *
277
+ * Ends early when the report arrives, and is flushed rather than dropped if the
278
+ * turn is superseded or the store torn down first, so a held timeout can't go
279
+ * missing from the SLI.
280
+ */ holdTimeoutForCause() {
281
+ // Flush rather than clear: a hold here would already have been counted, and
282
+ // dropping it would delete a failure from the SLI. Unreachable today (one
283
+ // budget timer per turn, and starting a turn flushes), enforced here so it
284
+ // stays that way.
285
+ this.flushHeldTimeout();
286
+ // Captured now: a turn starting during the window resets the live value.
287
+ const callActive = this.turnCallActiveTag;
288
+ this.heldTimeoutFlush = ()=>{
289
+ var _this_turnCause;
290
+ this.clearTimeoutHold();
291
+ metrics.emitIncrement("multimodal_text_response", {
292
+ status: "timeout",
293
+ call_active: callActive,
294
+ // `unknown` rather than omitted: every timeout carries a cause, so a
295
+ // dashboard split by cause always adds up to the timeout total. A growing
296
+ // `unknown` slice means the report is not reaching us.
297
+ cause: (_this_turnCause = this.turnCause) != null ? _this_turnCause : "unknown"
298
+ });
299
+ };
300
+ this.timeoutHoldId = root_store_setTimeout(this.heldTimeoutFlush, (/* inlined export .CAUSE_REPORT_GRACE_MS */1500));
301
+ }
302
+ // No-op unless a timeout is being held. Self-clearing, so it is safe to call
303
+ // from every path that might race the window.
304
+ flushHeldTimeout() {
305
+ this.heldTimeoutFlush == null ? void 0 : this.heldTimeoutFlush.call(this);
306
+ }
307
+ clearTimeoutHold() {
308
+ if (this.timeoutHoldId !== null) {
309
+ root_store_clearTimeout(this.timeoutHoldId);
310
+ this.timeoutHoldId = null;
311
+ }
312
+ this.heldTimeoutFlush = null;
313
+ }
314
+ clearResponseTimeout() {
315
+ if (this.responseTimeoutId !== null) {
316
+ root_store_clearTimeout(this.responseTimeoutId);
317
+ this.responseTimeoutId = null;
318
+ }
319
+ }
320
+ isDocumentHidden() {
321
+ return typeof document !== "undefined" && document.hidden;
322
+ }
323
+ handleTextTurnSendResult(result, turnToken) {
324
+ if (!(result == null ? void 0 : result.error)) return;
325
+ if (turnToken !== this.turnToken || this.turnCounterEmitted) return;
326
+ this.clearResponseTimeout();
327
+ metrics.emitIncrement("multimodal_text_response", {
328
+ status: "send_failed",
329
+ call_active: this.turnCallActiveTag
330
+ });
331
+ // A failed send has no reply coming, so close the turn entirely (no latency).
332
+ this.turnCounterEmitted = true;
333
+ this.turnReplyHandled = true;
334
+ this.turnToken++;
335
+ }
336
+ static isTextResponseEndedReason(reason) {
337
+ return RootStore.TEXT_RESPONSE_ENDED_REASONS.includes(reason);
338
+ }
339
+ static isTurnCause(cause) {
340
+ return RootStore.TURN_CAUSES.includes(cause);
341
+ }
342
+ unresolvedAiSdrEmailRequest() {
343
+ var _this_activeConversation_value;
344
+ const activeConversationId = (_this_activeConversation_value = this.activeConversation.value) == null ? void 0 : _this_activeConversation_value.id;
345
+ if (!activeConversationId) return null;
346
+ const resolvedFieldIds = new Set();
347
+ for (const message of [
348
+ ...this.messages.value
349
+ ].reverse()){
350
+ if (message.conversationId !== activeConversationId) continue;
351
+ if (message.type === "field_entry" && message.fieldId) {
352
+ resolvedFieldIds.add(message.fieldId);
353
+ continue;
354
+ }
355
+ if (message.type === "field_request" && message.createdByMultimodalAgent === true && message.fieldType === "email" && (!message.fieldId || !resolvedFieldIds.has(message.fieldId))) {
356
+ return message;
357
+ }
358
+ }
359
+ return null;
360
+ }
361
+ async aisdrEmailReplyPassesPreflight(text) {
362
+ if (!this.featureFlags.aisdrChatEmailValidation) return true;
363
+ if (!this.unresolvedAiSdrEmailRequest()) return true;
364
+ const email = text.trim();
365
+ if (!email.includes("@") || /\s/.test(email)) return true;
366
+ const [formatValid] = validateEmail(email, false);
367
+ if (!formatValid) return false;
368
+ return this.validateEmail(email);
369
+ }
370
+ async sendVisitorTextWithoutCookieConsent(text, extra) {
371
+ if (!await this.aisdrEmailReplyPassesPreflight(text)) {
372
+ this.sendTextError.value = "Invalid email address";
373
+ return;
374
+ }
375
+ const result = await this.sendMessage(_extends({
376
+ type: "text",
377
+ text,
378
+ isOwn: true
379
+ }, extra));
380
+ if (result.error) {
381
+ this.sendTextError.value = result.error.message || "Your message wasn't sent. Please try again.";
382
+ }
383
+ }
384
+ // Initialize voice and video stores when needed
385
+ async initializeVoiceAndVideo() {
386
+ this.isVideoLoading.value = true;
387
+ await this.callStore.load();
388
+ }
389
+ async checkPermissions() {
390
+ // Check current permission status before
391
+ let res = await navigator.permissions.query({
392
+ name: "microphone"
393
+ });
394
+ if (res.state !== "prompt") {
395
+ this.sendMessage({
396
+ type: "event",
397
+ eventType: "mediaPermissionStatus",
398
+ mediaStatus: "audio_already_" + res.state
399
+ });
400
+ } else {
401
+ // Request permission
402
+ const stream = await navigator.mediaDevices.getUserMedia({
403
+ video: false,
404
+ audio: true
405
+ }).catch(()=>null);
406
+ stream == null ? void 0 : stream.getTracks().forEach((track)=>track.stop());
407
+ // Check state again
408
+ res = await navigator.permissions.query({
409
+ name: "microphone"
410
+ });
411
+ this.sendMessage({
412
+ type: "event",
413
+ eventType: "mediaPermissionStatus",
414
+ mediaStatus: "audio_prompted_" + res.state
415
+ });
416
+ }
417
+ }
418
+ constructor(context, config = null){
419
+ super(context), this.config = config, // Initialized is true once we receive the first init state.
420
+ this.initialized = signals_core_module_d(false), // Set while a socket reconnect is in flight. The server answers a reconnect
421
+ // with a full initState re-broadcast, which must not move the widget away
422
+ // from where the visitor left it. Cleared once that initState is applied.
423
+ this.isReconnecting = signals_core_module_d(false), /** Admin-customizable chat input placeholder (English only) */ this.inputPlaceholder = signals_core_module_d(null), /** Whether to hide the visible 'Ask {name}' label on the multimodal messenger launcher */ this.multimodalHideLauncherLabel = signals_core_module_d(false), /**
424
+ * When the user expresses chat-view intent before initState provides the `formJoinIdUnique`
425
+ * payload field (or before conversations exist), we defer `custEv_chatView` until the store
426
+ * has `formJoinIDUnique` and an active conversation.
427
+ */ this.chatViewDeferredUserIntent = false, // Sub Stores (lazy-loaded via $fromImport)
428
+ this.meetingStore = $fromImport(()=>import("./meeting_store.js"), this), this.fieldRequestStore = $fromImport(()=>import("./field_request_store.js"), this), this.callStore = $fromImport(()=>import("./call_store.js"), this), this.pounceTrackingStore = $fromImport(()=>this.featureFlags.piperXAgent ? import("./pounce_tracking_store_v2.js") : import("./pounce_tracking_store.js"), this), this.slidesStore = $fromImport(()=>import("./slides_store.js"), this), this.presentationsStore = $fromImport(()=>import("./presentations_store.js"), this), this.decksStore = $fromImport(()=>import("./decks_store.js"), this), this.screenShareStore = $fromImport(()=>import("./screen_share_store.js"), this), this.waitingStore = $fromImport(()=>import("./waiting_store.js"), this), this.websiteNavigationStore = $fromImport(()=>import("./website_navigation_store.js"), this), this.debugScenarioStore = $fromImport(()=>import("./debug_multimodal_scenario_store.js"), this), this.postCallSurveyStore = $fromImport(()=>import("./post_call_survey_store.js"), this), /**
429
+ * Pre-offer booker SLI (intent -> offer -> shown). Owned here, not by
430
+ * `meetingStore`, for two reasons: the intent signal arrives on this store's
431
+ * message stream, and `meetingStore` is lazily imported — routing the arm
432
+ * through it would make the intent timestamp wait on a dynamic import,
433
+ * inflating the very latency we are measuring. `meetingStore` resolves it
434
+ * (`markOffered` / `markShown`) once the offer lands.
435
+ */ this.bookerIntentTracker = new BookerIntentTracker({
436
+ surface: BOOKER_SURFACE.MULTIMODAL,
437
+ log: (params)=>serverLogger.serverLog(params)
438
+ }), // Translation store is directly instantiated (not lazy-loaded) because
439
+ // translations are needed immediately when the app renders
440
+ this.translationStore = new TranslationStore(this), this.dockingStore = new DockingStore(this), this.artifactStore = new ArtifactStore(this), // Mutable State
441
+ this.isVisitorBlocked = signals_core_module_d(false), /** Piper form join ID for this page view; same for all custEv_* events on the page. */ this.formJoinIDUnique = signals_core_module_d(null), /** Tracks fired custEv_contentImpression IDs; bounded to prevent unbounded growth. */ this.impressedMessageIds = new BoundedSet(RootStore.IMPRESSED_MESSAGE_IDS_MAX_SIZE), this.agentsAvailable = signals_core_module_d(false), this.companyName = signals_core_module_d(), this.disableTitleFlash = signals_core_module_d(false), this.messengerEventListener = null, this.callInProgress = signals_core_module_w(()=>{
442
+ var _this_callStore_value;
443
+ return ((_this_callStore_value = this.callStore.value) == null ? void 0 : _this_callStore_value.dailyCall.value) != null;
444
+ }), this.typingIndicatorState = signals_core_module_d(false), this.activeToolCall = signals_core_module_d(null), this.pounceResponseStartTimestamp = null, this.callInitiatedAt = null, // Whether the team has configured a custom voice greeting (set by the admin
445
+ // via the multimodal voice greeting setting). When true, the initial greeting
446
+ // can be multiple sentences and varies per team, which affects greeting-sensitive
447
+ // timing metrics. Used to tag those metrics so dashboards can filter them out.
448
+ this.hasCustomVoiceGreeting = false, this.pounceTrackingLoadStarted = false, this.lastVisitorMessageSentAt = null, this.turnCounterEmitted = false, // Separate from the counter: lets a late reply still record latency after the
449
+ // timer resolved availability.
450
+ this.turnReplyHandled = false, this.responseTimeoutId = null, // A timeout that has been counted but whose metric is still waiting on the
451
+ // server's cause report (see holdTimeoutForCause).
452
+ this.timeoutHoldId = null, this.heldTimeoutFlush = null, // Dedups a late reply against a turn the timer already resolved.
453
+ this.turnToken = 0, // clientId of the message that opened the current turn; used to ignore a
454
+ // stale `textResponseEnded` event from a turn we've already superseded.
455
+ this.turnMessageClientId = null, // Latest cause the server reported for the outstanding turn, if any. Read only
456
+ // when the turn times out.
457
+ this.turnCause = null, // Whether the agent reached for a tool on this turn, which costs the call plus
458
+ // another model round trip to use what it returned. Reported as it happens, so a
459
+ // turn that never finishes is still on the right side of the split.
460
+ this.turnHasToolCall = false, // Tab hidden mid-turn → bucket as `backgrounded` (not a false `timeout`) and skip its latency.
461
+ this.turnObscured = false, this.turnCallActive = false, this.conversations = signals_core_module_d([]), this.messages = createMessagesSignal(), this.pounceCandidates = signals_core_module_d(null), this.isVideoLoading = signals_core_module_d(false), this.isBlurredVideoActive = signals_core_module_d(false), /**
462
+ * Which provider's track Coffee has committed to as the avatar video for this call.
463
+ * Null until Coffee reports one (an older Coffee never will), which callers treat as
464
+ * "fall back to the per-team flag".
465
+ */ this.activeAvatarProvider = signals_core_module_d(null), this.conversationModeFailover = signals_core_module_d({
466
+ voiceDisabled: false,
467
+ videoDisabled: false
468
+ }), this.modalityPreference = signals_core_module_d(null), this.dailyCallObjectBundleUrl = signals_core_module_d(null), this.dailyWsProxyUrl = signals_core_module_d(null), this.privacyDisclosures = signals_core_module_d(null), this.privacyDisclosureShown = signals_core_module_d(false), this.privacyDisclosureConsented = signals_core_module_d(false), this.cookieConsent = signals_core_module_d(null), this.cookieConsentGiven = signals_core_module_d(false), this.showCookieConsentModal = signals_core_module_d(false), this.pendingMessage = signals_core_module_d(null), // A call start awaiting cookie consent. When set, it also carries the optional
469
+ // trigger context (e.g. from a "present_video" card) so a single signal survives
470
+ // the consent re-entry path; the consent handlers read it back and re-invoke
471
+ // startCall with the stored context. `null` means no pending call.
472
+ this.pendingCallStart = signals_core_module_d(null), // Set when a visitor-typed text send is rejected server-side (e.g. the 2000-character
473
+ // limit in Message::Text) so the composer can tell the visitor their message never went
474
+ // through, rather than leaving them to wait on a reply that isn't coming. Cleared at the
475
+ // start of the next send attempt.
476
+ this.sendTextError = signals_core_module_d(null), // Loading overlay state (for lightbox / messenger loading screens)
477
+ this.loadingState = signals_core_module_d(types_LoadingState.NONE), this.loadingUuid = signals_core_module_d(null), // Element conversation state (for lightbox_gather from smart buttons)
478
+ this.elementConversation = signals_core_module_d(null), // Element conversation meeting offer (for calendar_event_offer from smart forms)
479
+ this.elementConversationOffer = signals_core_module_d(null), // Element conversation text message (for LightboxMessage step from offer/form bots)
480
+ this.elementConversationTextMessage = signals_core_module_d(null), // True while waiting for the backend to respond after submitLightboxGather
481
+ this.elementConversationLoading = signals_core_module_d(false), // Bumped whenever the element-conversation loading phase (re)starts. The inline
482
+ // meeting booker uses this to distinguish "the experience is still producing a
483
+ // conversation" (a fresh loading tick arrived after an endLoadingState) from
484
+ // "it ended without one", so it doesn't clear the spinner mid-flow (a white
485
+ // flash) while a slow booker is still computing its offer.
486
+ this.elementConversationLoadingSeq = signals_core_module_d(0), // Set by restoreGatherFromOffer ("Not you?") while a change_identity event is
487
+ // in flight and we are waiting for the backend to re-run the gather step. For a
488
+ // manual booker the backend echoes a stale calendar_event_offer (a known
489
+ // change_identity limitation) *before* the fresh lightbox_gather, both as
490
+ // separate elementMessage broadcasts in that order. Without this flag the offer
491
+ // flips elementConversationLoading to false and the gather that follows is
492
+ // dropped by the loading guard, stranding the visitor on an email-less offer
493
+ // instead of the email step. While set, an incoming offer is ignored; the flag
494
+ // clears when the gather (or a text/end) arrives, or the element state resets.
495
+ this.awaitingIdentityChangeRegather = signals_core_module_d(false), // True when a manual-experience meeting booker is being rendered inline into a
496
+ // page container div (inline_meeting_booker flag + a tagged container present).
497
+ // While set, the full-screen LightboxExperience suppresses itself so the booker
498
+ // only appears in the container, not as the default full-screen overlay.
499
+ this.inlineMeetingBookerActive = signals_core_module_d(false), // Computed: select the right disclosure based on effective locale
500
+ this.activePrivacyDisclosure = signals_core_module_w(()=>{
501
+ var _disclosures_;
502
+ var _disclosuresData_disclosures;
503
+ const disclosuresData = this.privacyDisclosures.value;
504
+ if (!(disclosuresData == null ? void 0 : (_disclosuresData_disclosures = disclosuresData.disclosures) == null ? void 0 : _disclosuresData_disclosures.length)) return null;
505
+ const locale = this.translationStore.effectiveLocale.value;
506
+ const { disclosures } = disclosuresData;
507
+ // First try exact locale match
508
+ const exactMatch = disclosures.find((d)=>d.locale === locale);
509
+ if (exactMatch) return exactMatch;
510
+ // Fallback to English
511
+ const englishMatch = disclosures.find((d)=>d.locale === "en");
512
+ if (englishMatch) return englishMatch;
513
+ // Return first available if no English
514
+ return (_disclosures_ = disclosures[0]) != null ? _disclosures_ : null;
515
+ }), // Computed: select the right cookie consent disclosure based on visitor location and locale.
516
+ // Resolution: state-specific > country-specific > ALL, with locale match then English fallback.
517
+ this.activeCookieDisclosure = signals_core_module_w(()=>{
518
+ var _cookieConsentData_disclosures;
519
+ const cookieConsentData = this.cookieConsent.value;
520
+ if (!(cookieConsentData == null ? void 0 : (_cookieConsentData_disclosures = cookieConsentData.disclosures) == null ? void 0 : _cookieConsentData_disclosures.length)) return null;
521
+ const locale = this.translationStore.effectiveLocale.value;
522
+ const { disclosures, visitorCountryCode, visitorStateCode } = cookieConsentData;
523
+ const findByLocation = (countryCode, stateCode)=>{
524
+ const localeMatch = disclosures.find((d)=>{
525
+ var _d_stateCode;
526
+ return d.countryCode === countryCode && ((_d_stateCode = d.stateCode) != null ? _d_stateCode : null) === (stateCode != null ? stateCode : null) && d.locale === locale;
527
+ });
528
+ if (localeMatch) return localeMatch;
529
+ const englishMatch = disclosures.find((d)=>{
530
+ var _d_stateCode;
531
+ return d.countryCode === countryCode && ((_d_stateCode = d.stateCode) != null ? _d_stateCode : null) === (stateCode != null ? stateCode : null) && d.locale === "en";
532
+ });
533
+ if (englishMatch) return englishMatch;
534
+ return null;
535
+ };
536
+ if (visitorStateCode && visitorCountryCode) {
537
+ const stateMatch = findByLocation(visitorCountryCode, visitorStateCode);
538
+ if (stateMatch) return stateMatch;
539
+ }
540
+ if (visitorCountryCode) {
541
+ const countryMatch = findByLocation(visitorCountryCode, null);
542
+ if (countryMatch) return countryMatch;
543
+ }
544
+ return findByLocation("ALL", null);
545
+ }), this.needsCookieConsent = signals_core_module_w(()=>{
546
+ var _cookieConsentData_consentedDisclosureIds;
547
+ if (!this.featureFlags.piperXCookieConsent) return false;
548
+ const cookieConsentData = this.cookieConsent.value;
549
+ if (!cookieConsentData) return !this.initialized.value;
550
+ const activeDisclosure = this.activeCookieDisclosure.value;
551
+ if (activeDisclosure && ((_cookieConsentData_consentedDisclosureIds = cookieConsentData.consentedDisclosureIds) == null ? void 0 : _cookieConsentData_consentedDisclosureIds.includes(activeDisclosure.id))) return false;
552
+ if (this.cookieConsentGiven.value) return false;
553
+ return !!this.activeCookieDisclosure.value;
554
+ }), // Cold start questions
555
+ this.coldStartQuestions = signals_core_module_d([]), this.coldStartVisibleLimit = signals_core_module_d(3), // Team-configured inactivity threshold (ms) before a follow-up pounce fires.
556
+ // Falls back to the hardcoded ACTIVE_THRESHOLD_MS default if not set.
557
+ this.pounceInactivityThresholdMs = signals_core_module_d(null), /**
558
+ * Debug mode for multimodal development.
559
+ * Enabled by adding `?q_debug_multimodal=1` to the URL.
560
+ * When enabled, allows previewing call UI states without starting a real call.
561
+ */ this.isDebugMultimodal = signals_core_module_w(()=>{
562
+ try {
563
+ var _window_location;
564
+ if (typeof window === "undefined") return false;
565
+ if (!((_window_location = window.location) == null ? void 0 : _window_location.search)) return false;
566
+ return new URLSearchParams(window.location.search).get("q_debug_multimodal") === "1";
567
+ } catch (unused) {
568
+ return false;
569
+ }
570
+ }), this.joinCallForPresentation = ()=>{
571
+ this.getCallUiAdapter().actions.startCall();
572
+ }, this.activeConversation = createActiveConversationSignal(this.conversations), this.userEngaged = signals_core_module_w(()=>!!this.activeConversation.user.value), this.isMessageStreamingEnabled = signals_core_module_w(()=>{
573
+ return !this.getCallUiAdapter().state.isInCall.value;
574
+ }), // UIStore must be initialized after messages, activeConversation, callStore
575
+ // since createLayoutSignal uses those during construction.
576
+ this.uiStore = new UIStore(this), /**
577
+ * Emits custEv_chatView piper web tracking event when eligible.
578
+ * Fires once per conversation after active user intent (expand launcher, focus composer,
579
+ * CTA/canned prompt, voice CTA, etc.) — not on page load when the widget restores opened.
580
+ * Pass `{ fromUserIntent: true }` from UI entry points so we can defer until initState fills
581
+ * `formJoinIdUnique` (stored as `formJoinIDUnique`) and conversations when intent is early.
582
+ * Only emits when `formJoinIDUnique` is set so the event matches other custEv_* events.
583
+ */ this.emitChatViewIfEligible = (options)=>{
584
+ var _ref, _this_formJoinIDUnique_value;
585
+ var _this_config_featureFlags, _this_config, _this_activeConversation_value;
586
+ const fromUserIntent = (_ref = options == null ? void 0 : options.fromUserIntent) != null ? _ref : false;
587
+ if (!((_this_config = this.config) == null ? void 0 : (_this_config_featureFlags = _this_config.featureFlags) == null ? void 0 : _this_config_featureFlags.piperWebTrackingEvents)) return;
588
+ if (this.userEngaged.value) {
589
+ this.chatViewDeferredUserIntent = false;
590
+ return;
591
+ }
592
+ const activeConvId = (_this_activeConversation_value = this.activeConversation.value) == null ? void 0 : _this_activeConversation_value.id;
593
+ if (!activeConvId) {
594
+ // Mirror !formJoinIDUnique: only set defer on user intent; do not clear defer here —
595
+ // system calls before conversations exist must not wipe a pending user intent.
596
+ if (fromUserIntent) {
597
+ this.chatViewDeferredUserIntent = true;
598
+ }
599
+ return;
600
+ }
601
+ const hasFired = this.messages.peek().some((m)=>m.type === "event" && m.eventType === "chatViewFired" && m.conversationId === activeConvId);
602
+ if (hasFired) {
603
+ this.chatViewDeferredUserIntent = false;
604
+ return;
605
+ }
606
+ const formJoinIDUnique = (_this_formJoinIDUnique_value = this.formJoinIDUnique.value) != null ? _this_formJoinIDUnique_value : "";
607
+ if (!formJoinIDUnique) {
608
+ if (fromUserIntent) {
609
+ this.chatViewDeferredUserIntent = true;
610
+ }
611
+ return;
612
+ }
613
+ this.chatViewDeferredUserIntent = false;
614
+ this.sendMessage({
615
+ type: "event",
616
+ eventType: "chatViewFired"
617
+ });
618
+ const data = buildCustEvChatViewPayload(this.piperConversationId, formJoinIDUnique);
619
+ this.channel.emitPiperWebTrackingEvent({
620
+ name: "custEv_chatView",
621
+ data
622
+ });
623
+ }, /**
624
+ * Emits custEv_contentImpression piper web tracking event.
625
+ * Used when links or rich content become visible in the viewport.
626
+ * Payload matches cold-start content impressions (no formJoinIDUnique).
627
+ */ this.emitContentImpression = (modules)=>{
628
+ var _this_config_featureFlags, _this_config;
629
+ if (!((_this_config = this.config) == null ? void 0 : (_this_config_featureFlags = _this_config.featureFlags) == null ? void 0 : _this_config_featureFlags.piperWebTrackingEvents)) return;
630
+ if (modules.length === 0) return;
631
+ const data = buildCustEvContentImpressionPayload(modules);
632
+ this.channel.emitPiperWebTrackingEvent({
633
+ name: "custEv_contentImpression",
634
+ data
635
+ });
636
+ }, this.handleTurnVisibilityChange = ()=>{
637
+ if (this.isDocumentHidden() && this.lastVisitorMessageSentAt !== null && !this.turnReplyHandled) {
638
+ this.turnObscured = true;
639
+ }
640
+ }, // Actions — delegated to UIStore
641
+ this.setUIState = (uiState)=>{
642
+ this.uiStore.setUIState(uiState);
643
+ }, this.setDisplayMode = (displayMode)=>{
644
+ this.uiStore.setDisplayMode(displayMode);
645
+ }, this.setOpenedDisplayMode = ()=>{
646
+ this.uiStore.setOpenedDisplayMode();
647
+ }, this.updateOpenedDisplayMode = (openedDisplayMode)=>{
648
+ this.uiStore.updateOpenedDisplayMode(openedDisplayMode);
649
+ }, this.setConversationMode = (conversationMode)=>{
650
+ this.uiStore.setConversationMode(conversationMode);
651
+ }, this.toggleVideoMode = (mode)=>{
652
+ this.uiStore.toggleVideoMode(mode);
653
+ }, this.setMaximizedState = (state)=>{
654
+ this.uiStore.setMaximizedState(state);
655
+ }, this.clearMaximizedState = (param)=>{
656
+ let { when } = param === void 0 ? {} : param;
657
+ this.uiStore.clearMaximizedState({
658
+ when
659
+ });
660
+ }, this.sendTypingEvent = (content)=>{
661
+ this.channel.perform("update_visitor_typing", {
662
+ content
663
+ });
664
+ }, this.updateConversationModeFailover = (failover)=>{
665
+ signals_core_module_r(()=>{
666
+ this.conversationModeFailover.value = _extends({}, this.conversationModeFailover.value, failover);
667
+ if (this.conversationModeFailover.value.voiceDisabled) {
668
+ this.cancelCallOrConnection({
669
+ closeWidget: false
670
+ });
671
+ } else if (this.conversationModeFailover.value.videoDisabled) {
672
+ this.isVideoLoading.value = false;
673
+ }
674
+ this.uiStore.ensureValidUIState();
675
+ });
676
+ }, this.sendMessage = async (payload, param)=>{
677
+ let { optimistic = true, conversationId } = param === void 0 ? {} : param;
678
+ var _ref, _ref1, _ref2;
679
+ var _this_elementConversationOffer_value, _this_activeConversation_value, _this_elementConversation_value;
680
+ const id = esm_browser_v4();
681
+ const resolvedConversationId = (_ref = (_ref1 = (_ref2 = conversationId != null ? conversationId : (_this_elementConversationOffer_value = this.elementConversationOffer.value) == null ? void 0 : _this_elementConversationOffer_value.conversationId) != null ? _ref2 : (_this_activeConversation_value = this.activeConversation.value) == null ? void 0 : _this_activeConversation_value.id) != null ? _ref1 : (_this_elementConversation_value = this.elementConversation.value) == null ? void 0 : _this_elementConversation_value.id) != null ? _ref : "";
682
+ const message = _extends({}, payload, {
683
+ id,
684
+ clientId: id,
685
+ optimistic,
686
+ conversationId: resolvedConversationId,
687
+ createdAt: new Date().toISOString(),
688
+ source: "standard",
689
+ multimodalDisplayMode: this.displayMode.value
690
+ });
691
+ if (optimistic && payload.type !== "field_entries") {
692
+ this.addMessage(message);
693
+ }
694
+ const { isInCall, isVideoLoading } = this.getCallUiAdapter().state;
695
+ if (!isInCall.peek() && !isVideoLoading.peek() && payload.type === "text" && payload.isOwn && this.uiStore.allowedConversationModes.video.peek()) {
696
+ this.setUIState({
697
+ userHasIgnoredMultimodal: true
698
+ });
699
+ }
700
+ const isVisitorAction = payload.type === "text" && "isOwn" in payload && payload.isOwn || payload.type === "field_entry" && "isOwn" in payload && payload.isOwn || payload.type === "calendar_event_pick";
701
+ if (message.type !== "event") {
702
+ // Visitor actions (text, field entry, calendar pick) imply chat-view intent even when
703
+ // the widget is already open — e.g. first interaction is booking while in SIDEBAR.
704
+ if (isVisitorAction) {
705
+ this.emitChatViewIfEligible({
706
+ fromUserIntent: true
707
+ });
708
+ }
709
+ // Don't pop the full messenger open beside the inline meeting booker: its
710
+ // container has no overlay, so opening the messenger would be an unwanted
711
+ // visible side-effect (same reasoning as openMessengerForElementConversation).
712
+ // The inline gather submit (field_entries) and time confirm
713
+ // (calendar_event_pick) route through here, so guard them too.
714
+ if (!this.inlineMeetingBookerActive.value) {
715
+ this.setOpenedDisplayMode();
716
+ }
717
+ }
718
+ if (payload.type === "text") {
719
+ this.recordPrivacyDisclosureConsent(id);
720
+ }
721
+ // Known limitation: we track a single outstanding turn (first-message-wins).
722
+ // If a turn times out and the visitor sends again before its late reply lands,
723
+ // that reply is attributed to the newer turn (replies carry no link to the
724
+ // visitor message they answer, so we can't match them by anything but timing).
725
+ // Rare (needs a >budget reply plus a resend in the gap) and self-correcting in
726
+ // aggregate, so we accept it rather than track per-message turns.
727
+ const startedTurnToken = isVisitorAction && (this.lastVisitorMessageSentAt === null || this.turnCounterEmitted) ? this.startTextTurn(id) : null;
728
+ const result = await this.channel.perform("send_message", snakify(message));
729
+ if (startedTurnToken !== null) {
730
+ this.handleTextTurnSendResult(result, startedTurnToken);
731
+ }
732
+ return result;
733
+ }, /**
734
+ * Backend closed a turn with no reply on purpose (guardrail block, rep
735
+ * takeover, blank output, ...). Close the turn under a distinct status so the
736
+ * budget timer doesn't fire a false `timeout` and dashboards can exclude it
737
+ * from the success rate. Guarded on `turnCounterEmitted` so a turn already
738
+ * resolved by a real reply (or the timer) is left untouched.
739
+ */ this.handleTextResponseEnded = (payload)=>{
740
+ var _ref;
741
+ if (this.lastVisitorMessageSentAt === null || this.turnCounterEmitted) return;
742
+ // Ignore a late event from a turn we've already superseded: it must belong
743
+ // to the message that opened the current outstanding turn.
744
+ if ((payload == null ? void 0 : payload.clientId) !== this.turnMessageClientId) return;
745
+ const reason = (_ref = payload == null ? void 0 : payload.reason) != null ? _ref : "";
746
+ const status = RootStore.isTextResponseEndedReason(reason) ? reason : "suppressed";
747
+ this.clearResponseTimeout();
748
+ metrics.emitIncrement("multimodal_text_response", _extends({
749
+ status,
750
+ call_active: this.turnCallActiveTag
751
+ }, this.turnCause ? {
752
+ cause: this.turnCause
753
+ } : {}));
754
+ // No reply is coming, so close the turn entirely (no latency recorded).
755
+ this.turnCounterEmitted = true;
756
+ this.turnReplyHandled = true;
757
+ this.turnToken++;
758
+ }, /**
759
+ * The server telling us what this turn is spending its time on, sent when the
760
+ * response budget expires (and again afterwards for turns that finished slow).
761
+ * Purely an annotation: it never resolves or ends a turn, it only supplies the
762
+ * `cause` tag the timeout would otherwise lack.
763
+ */ this.handleTextTurnDiagnostics = (payload)=>{
764
+ var _ref;
765
+ if ((payload == null ? void 0 : payload.clientId) !== this.turnMessageClientId) return;
766
+ if ((payload == null ? void 0 : payload.hasToolCall) === true) this.turnHasToolCall = true;
767
+ // A tool report carries no cause and arrives mid-turn, so it must not release a
768
+ // held timeout: that would emit the metric before the cause it is waiting for.
769
+ const cause = (_ref = payload == null ? void 0 : payload.cause) != null ? _ref : "";
770
+ if (!RootStore.isTurnCause(cause)) return;
771
+ // Preserve the first concrete explanation for this client turn; `unknown`
772
+ // is a placeholder and may be replaced when a real cause arrives.
773
+ this.turnCause = this.turnCause && this.turnCause !== "unknown" ? this.turnCause : cause;
774
+ // This report is what a held timeout was waiting for; no reason to sit out
775
+ // the rest of the window.
776
+ this.flushHeldTimeout();
777
+ }, this.sendVisitorText = async (text, extra)=>{
778
+ this.sendTextError.value = null;
779
+ if (this.featureFlags.piperXCookieConsent && this.needsCookieConsent.value) {
780
+ this.pendingMessage.value = _extends({
781
+ text
782
+ }, extra);
783
+ this.setOpenedDisplayMode();
784
+ this.showCookieConsentModal.value = true;
785
+ return;
786
+ }
787
+ await this.sendVisitorTextWithoutCookieConsent(text, extra);
788
+ }, this.markMessagesAsRead = (messages)=>{
789
+ const messagesToMarkAsRead = messages != null ? messages : this.messages.unread.value;
790
+ const messageIds = messagesToMarkAsRead.filter((m)=>!m.isRead).map((m)=>m.id);
791
+ if (messageIds.length === 0) return;
792
+ this.channel.perform("mark_messages_as_read", snakify({
793
+ messageIds
794
+ }));
795
+ signals_core_module_r(()=>{
796
+ for (const message of messagesToMarkAsRead){
797
+ this.updateMessage(message, {
798
+ isRead: true
799
+ });
800
+ }
801
+ });
802
+ }, this.dismissPounce = ()=>{
803
+ if (this.messages.pounceActive.peek()) {
804
+ this.sendMessage({
805
+ type: "event",
806
+ eventType: "pounce_dismissed"
807
+ });
808
+ }
809
+ this.markMessagesAsRead();
810
+ }, this.fireMessagesDismissed = ()=>{
811
+ this.messengerEventListener == null ? void 0 : this.messengerEventListener.call(this, "messagesDismissed");
812
+ }, this.recordPrivacyDisclosure = ()=>{
813
+ var _this_activeConversation_value, _this_activeConversation_value1;
814
+ const disclosure = this.activePrivacyDisclosure.value;
815
+ if (!disclosure || !((_this_activeConversation_value = this.activeConversation.value) == null ? void 0 : _this_activeConversation_value.id)) return;
816
+ // Send the exact disclosure ID that was shown to the user
817
+ this.channel.perform("record_privacy_disclosure_shown", {
818
+ disclosure_id: disclosure.id,
819
+ conversation_id: (_this_activeConversation_value1 = this.activeConversation.value) == null ? void 0 : _this_activeConversation_value1.id
820
+ });
821
+ this.privacyDisclosureShown.value = true;
822
+ }, this.recordPrivacyDisclosureConsent = (clientId)=>{
823
+ if (this.privacyDisclosureConsented.value) return;
824
+ if (!this.privacyDisclosures.value) return;
825
+ this.channel.perform("record_privacy_disclosure_consent_given", {
826
+ client_id: clientId
827
+ });
828
+ this.privacyDisclosureConsented.value = true;
829
+ }, // Cookie consent actions
830
+ this.acceptCookieConsent = ()=>{
831
+ if (!this.featureFlags.piperXCookieConsent) return;
832
+ const pending = this.pendingMessage.value;
833
+ const disclosure = this.activeCookieDisclosure.value;
834
+ const cookieConsentData = this.cookieConsent.value;
835
+ if (!disclosure || !cookieConsentData) return;
836
+ const pendingCall = this.pendingCallStart.value;
837
+ signals_core_module_r(()=>{
838
+ this.channel.perform("record_cookie_consent", {
839
+ messenger_theme_id: cookieConsentData.messengerThemeId,
840
+ cookie_disclosure_id: disclosure.id
841
+ });
842
+ this.cookieConsentGiven.value = true;
843
+ this.showCookieConsentModal.value = false;
844
+ if (pending) {
845
+ const { text } = pending, extra = _object_without_properties_loose(pending, [
846
+ "text"
847
+ ]);
848
+ this.pendingMessage.value = null;
849
+ void this.sendVisitorTextWithoutCookieConsent(text, extra);
850
+ }
851
+ this.pendingCallStart.value = null;
852
+ });
853
+ if (pendingCall) {
854
+ var _pendingCall_context;
855
+ this.startCall((_pendingCall_context = pendingCall.context) != null ? _pendingCall_context : undefined);
856
+ }
857
+ }, this.denyCookieConsent = ()=>{
858
+ if (!this.featureFlags.piperXCookieConsent) return;
859
+ signals_core_module_r(()=>{
860
+ this.showCookieConsentModal.value = false;
861
+ this.pendingMessage.value = null;
862
+ // Clearing the pending call also discards any stashed trigger context, so a
863
+ // later regular call is never mistaken for a presentation start.
864
+ this.pendingCallStart.value = null;
865
+ this.setDisplayMode(types_DisplayMode.CLOSED);
866
+ });
867
+ }, this.flushPendingCookieConsentActions = ()=>{
868
+ if (!this.featureFlags.piperXCookieConsent) return;
869
+ const pending = this.pendingMessage.value;
870
+ const pendingCall = this.pendingCallStart.value;
871
+ if (!pending && !pendingCall) return;
872
+ if (this.needsCookieConsent.value) {
873
+ this.setOpenedDisplayMode();
874
+ this.showCookieConsentModal.value = true;
875
+ } else {
876
+ if (pending) {
877
+ const { text } = pending, extra = _object_without_properties_loose(pending, [
878
+ "text"
879
+ ]);
880
+ this.pendingMessage.value = null;
881
+ void this.sendVisitorTextWithoutCookieConsent(text, extra);
882
+ }
883
+ if (pendingCall) {
884
+ var _pendingCall_context;
885
+ this.pendingCallStart.value = null;
886
+ this.startCall((_pendingCall_context = pendingCall.context) != null ? _pendingCall_context : undefined);
887
+ }
888
+ }
889
+ }, this.updateMessage = (message, payload)=>{
890
+ this.messages.value = this.messages.value.map((m)=>m.id === message.id ? this.mergeMessage(m, payload) : m);
891
+ }, this.mergeMessage = (existing, incoming)=>_extends({}, existing, incoming, {
892
+ isRead: existing.isRead || incoming.isRead
893
+ }), this.updateInputMessage = async (message)=>{
894
+ await this.fieldRequestStore.load();
895
+ signals_core_module_r(()=>{
896
+ this.setOpenedDisplayMode();
897
+ this.setUIState({
898
+ inputMessageId: message.id
899
+ });
900
+ });
901
+ }, /** Opens the booker in the artifact overlay, or closes it if it is already showing this offer. */ this.toggleMeetingBookerArtifact = async (message)=>{
902
+ if (this.artifact.messageId.peek() === message.id) {
903
+ this.clearArtifact();
904
+ return;
905
+ }
906
+ await this.artifactStore.presentArtifactMessage(message);
907
+ }, /** Dismisses the booker on whichever surface is showing it. */ this.closeMeetingBooker = ()=>{
908
+ signals_core_module_r(()=>{
909
+ this.clearMeetingArtifact();
910
+ this.elementConversationOffer.value = null;
911
+ this.elementConversationLoading.value = false;
912
+ // NOTE: elementConversationTextMessage is intentionally NOT cleared here —
913
+ // see the note in clearInputMessage.
914
+ });
915
+ }, /** Tears down the artifact overlay only when it is the meeting booker. */ this.clearMeetingArtifact = ()=>{
916
+ var _this_artifact_message_peek;
917
+ if (((_this_artifact_message_peek = this.artifact.message.peek()) == null ? void 0 : _this_artifact_message_peek.type) !== "calendar_event_offer") return;
918
+ this.clearArtifact();
919
+ }, /** Hands an incoming message to the overlay. See ArtifactStore#queueArtifactMessage. */ this.queueArtifactMessage = (message, options)=>{
920
+ if (options === void 0) options = {};
921
+ return this.artifactStore.queueArtifactMessage(message, options);
922
+ }, /** Re-opens an artifact the visitor asked for from the timeline. */ this.presentArtifactMessage = (message)=>this.artifactStore.presentArtifactMessage(message), this.revisitDeckSlide = (message, slideIndex, pageTitle)=>this.artifactStore.revisitDeckSlide(message, slideIndex, pageTitle), this.clearArtifact = ()=>{
923
+ this.artifactStore.clearArtifact();
924
+ }, this.clearInputMessage = (param)=>{
925
+ let { when } = param === void 0 ? {} : param;
926
+ if (!when || this.input.state.value === when) {
927
+ this.setUIState({
928
+ inputMessageId: null
929
+ });
930
+ signals_core_module_r(()=>{
931
+ this.elementConversationOffer.value = null;
932
+ this.elementConversationLoading.value = false;
933
+ });
934
+ // NOTE: elementConversationTextMessage is intentionally NOT cleared here.
935
+ // After a successful booking, the server broadcasts calendar_event_confirmation
936
+ // (which sets elementConversationTextMessage) BEFORE send_message:response is
937
+ // processed. Clearing it here would race with that broadcast and erase the
938
+ // confirmation overlay. Instead, clear it when a new element conversation
939
+ // begins (handleInitElementConversation / handleInitQualifiedFormElementConversation)
940
+ // or when the user dismisses it via the "Done" button in LightboxExperience.
941
+ }
942
+ }, this.setTypingIndicator = (typing)=>{
943
+ this.typingIndicatorState.value = typing;
944
+ if (!typing) {
945
+ this.activeToolCall.value = null;
946
+ }
947
+ }, this.startCall = async (startCallContext, displayState)=>{
948
+ if (displayState === void 0) displayState = "open";
949
+ var _this_pounceTrackingStore_value, _this_callStore_value;
950
+ if (this.conversationMode.text.peek()) {
951
+ return;
952
+ }
953
+ if (this.featureFlags.piperXCookieConsent && this.needsCookieConsent.value) {
954
+ // Stash the (optional) trigger context so it survives the cookie-consent
955
+ // re-entry path: acceptCookieConsent/flushPendingCookieConsentActions read
956
+ // it back and re-call startCall with the stored context.
957
+ //
958
+ // The requested display state is deliberately dropped. Asking for consent
959
+ // opens the widget and puts the visitor in front of it, so re-applying the
960
+ // original request afterwards would move (or close) a widget they are
961
+ // already looking at.
962
+ this.pendingCallStart.value = {
963
+ context: startCallContext != null ? startCallContext : null
964
+ };
965
+ this.setOpenedDisplayMode();
966
+ this.showCookieConsentModal.value = true;
967
+ return;
968
+ }
969
+ this.callInitiatedAt = performance.now();
970
+ this.messengerEventListener == null ? void 0 : this.messengerEventListener.call(this, "callRequested");
971
+ (_this_pounceTrackingStore_value = this.pounceTrackingStore.value) == null ? void 0 : _this_pounceTrackingStore_value.notifyCallRequested();
972
+ this.sendMessage({
973
+ type: "event",
974
+ eventType: "ai_sdr_call_requested"
975
+ });
976
+ signals_core_module_r(()=>{
977
+ this.setUIState({
978
+ userHasIgnoredMultimodal: false
979
+ });
980
+ this.applyStartCallDisplayState(displayState);
981
+ });
982
+ const callStore = this.callStore.value;
983
+ if (!callStore) {
984
+ await this.initializeVoiceAndVideo();
985
+ }
986
+ const dailyCall = (_this_callStore_value = this.callStore.value) == null ? void 0 : _this_callStore_value.dailyCall.value;
987
+ if (!dailyCall) {
988
+ var _this_callStore_value1;
989
+ (_this_callStore_value1 = this.callStore.value) == null ? void 0 : _this_callStore_value1.aiConversationStore.startConversation(false, startCallContext != null ? startCallContext : null);
990
+ }
991
+ }, /**
992
+ * Position the widget for a call that is about to start.
993
+ *
994
+ * `minimized` runs the call in picture-in-picture over the host page, which
995
+ * only reads as picture-in-picture with nothing layered on top: a maximized
996
+ * artifact keeps its backdrop and z-index even once the display mode is
997
+ * closed, so it has to be cleared as well.
998
+ */ this.applyStartCallDisplayState = (displayState)=>{
999
+ if (displayState === "minimized") {
1000
+ this.clearMaximizedState();
1001
+ this.setDisplayMode(types_DisplayMode.CLOSED);
1002
+ return;
1003
+ }
1004
+ // Expand to opened display mode if minimized
1005
+ if (this.displayMode.minimized.value) {
1006
+ this.setOpenedDisplayMode();
1007
+ }
1008
+ // Maximizing centers the multimodal UI, which collides with the custom entry
1009
+ // points voice-only setups render, so it is video-only.
1010
+ if (displayState === "maximized" && this.conversationMode.video.peek()) {
1011
+ this.setMaximizedState(types_MaximizedState.MULTIMODAL);
1012
+ }
1013
+ }, this.resetToStartingPosition = ()=>{
1014
+ this.uiStore.resetToStartingPosition();
1015
+ }, this.dismissWidget = ()=>{
1016
+ this.uiStore.dismissWidget();
1017
+ }, this.closeWidget = ()=>{
1018
+ this.uiStore.closeWidget();
1019
+ }, /**
1020
+ * Show a full-screen lightbox loading overlay and expand the widget.
1021
+ * If the widget is minimized, opens it first.
1022
+ */ this.showLightboxLoading = ()=>{
1023
+ signals_core_module_r(()=>{
1024
+ this.loadingState.value = types_LoadingState.LIGHTBOX;
1025
+ if (this.displayMode.minimized.value && !this.uiStore.hasPendingRedirectDismissedUIState()) {
1026
+ this.setOpenedDisplayMode();
1027
+ }
1028
+ });
1029
+ }, /**
1030
+ * Opens the messenger for an element-conversation step when the widget is
1031
+ * minimized — unless the meeting booker is being rendered inline into a page
1032
+ * container ({@link inlineMeetingBookerActive}). The full-screen lightbox flow
1033
+ * hides the opened messenger behind its overlay, but inline mode has no
1034
+ * overlay, so popping the messenger open would be an unwanted visible
1035
+ * side-effect next to the container booker.
1036
+ */ this.openMessengerForElementConversation = ()=>{
1037
+ if (this.inlineMeetingBookerActive.value) return;
1038
+ if (this.displayMode.minimized.value) {
1039
+ this.setOpenedDisplayMode();
1040
+ }
1041
+ }, /**
1042
+ * Enters the element-conversation loading phase used by lightbox smart-site
1043
+ * flows before the gather/offer payload is available.
1044
+ */ this.showElementConversationLoadingState = ()=>{
1045
+ signals_core_module_r(()=>{
1046
+ this.openMessengerForElementConversation();
1047
+ this.elementConversation.value = null;
1048
+ this.elementConversationOffer.value = null;
1049
+ this.elementConversationTextMessage.value = null;
1050
+ this.elementConversationLoading.value = true;
1051
+ this.elementConversationLoadingSeq.value += 1;
1052
+ this.closeLightbox();
1053
+ });
1054
+ }, /**
1055
+ * Show a messenger-panel loading overlay and expand the widget.
1056
+ */ this.showMessengerLoading = ()=>{
1057
+ signals_core_module_r(()=>{
1058
+ this.loadingState.value = types_LoadingState.MESSENGER;
1059
+ this.setOpenedDisplayMode();
1060
+ });
1061
+ }, /**
1062
+ * Show an inline spinner for a specific personalization element.
1063
+ * The DOM spinner is managed by PersonalizationManager; this just
1064
+ * tracks the uuid for cleanup purposes.
1065
+ */ this.showInlineLoading = (uuid)=>{
1066
+ signals_core_module_r(()=>{
1067
+ this.loadingState.value = types_LoadingState.INLINE;
1068
+ this.loadingUuid.value = uuid;
1069
+ });
1070
+ }, /**
1071
+ * Clear any active loading state (lightbox, messenger, or inline).
1072
+ * No-op when loading state is already NONE.
1073
+ */ this.closeLightbox = ()=>{
1074
+ if (this.loadingState.peek() !== types_LoadingState.NONE) {
1075
+ signals_core_module_r(()=>{
1076
+ this.loadingState.value = types_LoadingState.NONE;
1077
+ this.loadingUuid.value = null;
1078
+ });
1079
+ }
1080
+ }, /**
1081
+ * Cancels any active call or connecting state and returns to starting position.
1082
+ * Used when the Toolbar close button is clicked while in a call or connecting.
1083
+ *
1084
+ * Behavior:
1085
+ * - FULLSCREEN → COLLAPSED
1086
+ * - SIDEBAR → CLOSED
1087
+ */ this.cancelCallOrConnection = async (param)=>{
1088
+ let { closeWidget = true } = param === void 0 ? {} : param;
1089
+ // Reset maximized state when ending call
1090
+ this.clearMaximizedState();
1091
+ // Handle debug mode - reset the scenario store
1092
+ const debugStore = this.debugScenarioStore.value;
1093
+ if (this.isDebugMultimodal.value && debugStore) {
1094
+ debugStore.reset();
1095
+ if (closeWidget) {
1096
+ this.closeWidget();
1097
+ }
1098
+ return;
1099
+ }
1100
+ // Handle real call mode
1101
+ const callStore = this.callStore.value;
1102
+ const aiConversationStore = callStore == null ? void 0 : callStore.aiConversationStore;
1103
+ const dailyCall = callStore == null ? void 0 : callStore.dailyCall.value;
1104
+ // Always reset the loading state first to prevent any pending async operations
1105
+ // from continuing (e.g., tavusStore.handleStartResponse checks this flag)
1106
+ this.isVideoLoading.value = false;
1107
+ this.isBlurredVideoActive.value = false;
1108
+ this.activeAvatarProvider.value = null;
1109
+ this.setTypingIndicator(false);
1110
+ // End the tavus conversation if one exists
1111
+ if (aiConversationStore == null ? void 0 : aiConversationStore.conversation.value) {
1112
+ await aiConversationStore.endConversation();
1113
+ }
1114
+ // Leave any active Daily call
1115
+ if (dailyCall) {
1116
+ await (callStore == null ? void 0 : callStore.leaveCall());
1117
+ }
1118
+ if (closeWidget) {
1119
+ this.closeWidget();
1120
+ }
1121
+ }, // Everything below is private
1122
+ // Signal subscriptions
1123
+ this.signalSubscriptions = [
1124
+ ()=>this.activePrivacyDisclosure.subscribe(this.handlePrivacyDisclosureChange),
1125
+ ()=>this.messages.pounceActive.subscribe((active)=>{
1126
+ var _this_pounceTrackingStore_value;
1127
+ if (active) {
1128
+ this.startPounceTracking();
1129
+ return;
1130
+ }
1131
+ if (this.pounceTrackingStore.value) {
1132
+ this.pounceTrackingLoadStarted = false;
1133
+ }
1134
+ (_this_pounceTrackingStore_value = this.pounceTrackingStore.value) == null ? void 0 : _this_pounceTrackingStore_value.dispose();
1135
+ this.setTypingIndicator(false);
1136
+ })
1137
+ ], this.handlePrivacyDisclosureChange = ()=>{
1138
+ var _this_privacyDisclosures_value, _this_activeConversation_value;
1139
+ const isInline = ((_this_privacyDisclosures_value = this.privacyDisclosures.value) == null ? void 0 : _this_privacyDisclosures_value.displayMode) === "inline";
1140
+ const isDisclosureVisible = isInline ? this.displayMode.opened.value : !this.displayMode.closed.value;
1141
+ if (isDisclosureVisible && this.activePrivacyDisclosure.value && ((_this_activeConversation_value = this.activeConversation.value) == null ? void 0 : _this_activeConversation_value.id)) {
1142
+ this.recordPrivacyDisclosure();
1143
+ }
1144
+ }, // Message handlers
1145
+ this.messageHandlers = {
1146
+ initState: (payload)=>this.handleInitState(payload),
1147
+ stateUpdate: (payload)=>this.handleStateUpdate(payload),
1148
+ message: (payload)=>this.handleMessage(payload),
1149
+ messageRead: (payload)=>this.handleMessageRead(payload),
1150
+ typingStarted: ()=>this.setTypingIndicator(true),
1151
+ typingEnded: ()=>this.setTypingIndicator(false),
1152
+ visitorBlocked: ()=>signals_core_module_r(()=>{
1153
+ this.isVisitorBlocked.value = true;
1154
+ this.setTypingIndicator(false);
1155
+ this.setConversationMode(types_ConversationMode.TEXT);
1156
+ }),
1157
+ visitorUnblocked: ()=>this.isVisitorBlocked.value = false,
1158
+ botProcessEnded: ()=>this.handleBotProcessEnded(),
1159
+ textResponseEnded: (payload)=>this.handleTextResponseEnded(payload),
1160
+ textTurnDiagnostics: (payload)=>this.handleTextTurnDiagnostics(payload),
1161
+ toolCallStarted: (payload)=>{
1162
+ var _ref;
1163
+ this.activeToolCall.value = (_ref = payload == null ? void 0 : payload.toolName) != null ? _ref : null;
1164
+ },
1165
+ toolCallCompleted: ()=>{
1166
+ this.activeToolCall.value = null;
1167
+ },
1168
+ open: ()=>{
1169
+ // Close via the adapter so the active experience's lightbox closes, whether it's the legacy iframe (V1Adapter) or multimodal (V2Adapter).
1170
+ this.experienceAdapter.closeLightbox();
1171
+ this.setOpenedDisplayMode();
1172
+ }
1173
+ }, this.handleInitElementConversation = (payload)=>{
1174
+ var _payload_messages_filter, _payload_messages;
1175
+ // Use the LAST lightbox_gather message — conversations with show_follow_up_questions
1176
+ // accumulate multiple lightbox_gather messages (initial + follow-up). .find() would
1177
+ // return the stale initial message; .at(-1) returns the most recent one.
1178
+ const lightboxGatherMsg = (_payload_messages = payload.messages) == null ? void 0 : (_payload_messages_filter = _payload_messages.filter((m)=>m.type === "lightbox_gather")) == null ? void 0 : _payload_messages_filter.at(-1);
1179
+ if (!lightboxGatherMsg) {
1180
+ var _payload_messages1;
1181
+ // No gather step — check for a direct meeting booker offer (bot goes straight
1182
+ // to RouteForMeeting without a LightboxGather step). The server still broadcasts
1183
+ // initElementConversation for manual (non-form) bots; the payload contains the
1184
+ // calendar_event_offer message we need to show the meeting calendar.
1185
+ const offerMsg = (_payload_messages1 = payload.messages) == null ? void 0 : _payload_messages1.find((m)=>m.type === "calendar_event_offer");
1186
+ if (offerMsg) {
1187
+ // "Not you?" in flight: ignore the stale offer and keep waiting for the
1188
+ // re-gather (see restoreGatherFromOffer / handleInitQualifiedFormElementConversation).
1189
+ if (this.awaitingIdentityChangeRegather.value) return;
1190
+ signals_core_module_r(()=>{
1191
+ this.openMessengerForElementConversation();
1192
+ this.elementConversationLoading.value = false;
1193
+ this.elementConversationOffer.value = offerMsg;
1194
+ this.elementConversationTextMessage.value = null;
1195
+ this.closeLightbox();
1196
+ });
1197
+ this.meetingStore.load();
1198
+ } else {
1199
+ signals_core_module_r(()=>{
1200
+ this.openMessengerForElementConversation();
1201
+ // StartElementConversation can arrive before the backend has produced the
1202
+ // follow-up gather or offer message. Keep the lightbox loading overlay up
1203
+ // so the visitor sees progress instead of falling back to no overlay.
1204
+ this.elementConversationLoading.value = true;
1205
+ // Bump the loading seq so the inline booker's end-of-experience grace
1206
+ // check (InlineMeetingBooker.handleExperienceEnd) sees this restart and
1207
+ // does not blank the container while the offer is still in flight.
1208
+ this.elementConversationLoadingSeq.value += 1;
1209
+ // Clear any stale confirmation overlay from a previous booking.
1210
+ this.elementConversationTextMessage.value = null;
1211
+ });
1212
+ }
1213
+ return;
1214
+ }
1215
+ signals_core_module_r(()=>{
1216
+ this.openMessengerForElementConversation();
1217
+ this.elementConversation.value = {
1218
+ id: payload.id,
1219
+ message: lightboxGatherMsg
1220
+ };
1221
+ this.elementConversationTextMessage.value = null;
1222
+ // Clear loading state — this handles both the initial gather and any
1223
+ // follow-up gather steps (show_follow_up_questions) where the server
1224
+ // re-broadcasts initElementConversation after processing the response.
1225
+ this.elementConversationLoading.value = false;
1226
+ // The re-gather we were waiting on ("Not you?") has arrived.
1227
+ this.awaitingIdentityChangeRegather.value = false;
1228
+ this.closeLightbox();
1229
+ });
1230
+ }, this.submitLightboxGather = (entries)=>{
1231
+ const elementConv = this.elementConversation.value;
1232
+ if (!elementConv) return;
1233
+ // Batched so subscribers (e.g. LightboxExperience's completion-hold effects)
1234
+ // never observe elementConversationLoading=true while elementConversation is
1235
+ // still its stale pre-submit value — that intermediate state spuriously
1236
+ // satisfied the gather-hold's isReady() and snapped the bar to 100% for the
1237
+ // wrong reason, long before the real offer ever arrived.
1238
+ signals_core_module_r(()=>{
1239
+ this.elementConversationLoading.value = true;
1240
+ // Restart the loading seq so the inline booker's grace check keeps the
1241
+ // spinner up while the offer computes (see handleInitElementConversation).
1242
+ this.elementConversationLoadingSeq.value += 1;
1243
+ this.elementConversation.value = null;
1244
+ });
1245
+ this.sendMessage({
1246
+ type: "field_entries",
1247
+ entries,
1248
+ id: elementConv.message.id,
1249
+ botStep: elementConv.message.botStep,
1250
+ executionStep: elementConv.message.executionStep
1251
+ }, {
1252
+ optimistic: false,
1253
+ conversationId: elementConv.id
1254
+ });
1255
+ }, /**
1256
+ * Clears the meeting offer and asks the backend to drop the visitor's
1257
+ * identity so the LightboxGather step can re-run ("Not you?" flow). The
1258
+ * server destroys identities in MeetingBookerOffer#call and broadcasts a
1259
+ * fresh lightbox_gather message, which the standard init path hydrates
1260
+ * back into `elementConversation`.
1261
+ */ this.restoreGatherFromOffer = ()=>{
1262
+ const offer = this.elementConversationOffer.value;
1263
+ if (!offer) return;
1264
+ this.sendMessage({
1265
+ type: "event",
1266
+ eventType: "change_identity",
1267
+ botStep: offer.botStep,
1268
+ executionStep: offer.executionStep
1269
+ }, {
1270
+ conversationId: offer.conversationId
1271
+ }).then((result)=>{
1272
+ // MultimodalChannel.perform reports timeouts and server errors by
1273
+ // resolving with an { error } result rather than rejecting, so a channel
1274
+ // failure lands here (not in catch). Without this, loading and the
1275
+ // re-gather guard would stay set forever and every later offer would be
1276
+ // dropped by the guard in handleInitElementConversation.
1277
+ if (result == null ? void 0 : result.error) this.clearRegatherOnChannelFailure();
1278
+ }).catch(()=>this.clearRegatherOnChannelFailure());
1279
+ signals_core_module_r(()=>{
1280
+ this.elementConversationOffer.value = null;
1281
+ this.elementConversationLoading.value = true;
1282
+ // Restart the loading seq so the inline booker's grace check keeps the
1283
+ // spinner up until the re-gathered lightbox_gather arrives.
1284
+ this.elementConversationLoadingSeq.value += 1;
1285
+ // Ignore the stale offer the backend echoes before the re-gather; hold the
1286
+ // spinner until the lightbox_gather arrives so we land on the email step.
1287
+ this.awaitingIdentityChangeRegather.value = true;
1288
+ });
1289
+ }, /**
1290
+ * Mirror LightboxEntry#handleRefreshMeetingOffer: when the "Not you?" re-gather
1291
+ * channel call drops or resolves with an error, clear the spinner so the
1292
+ * visitor isn't stuck on a perpetual overlay, and clear the re-gather guard so
1293
+ * a later offer isn't silently dropped.
1294
+ */ this.clearRegatherOnChannelFailure = ()=>{
1295
+ this.elementConversationLoading.value = false;
1296
+ this.awaitingIdentityChangeRegather.value = false;
1297
+ }, this.handleInitQualifiedFormElementConversation = (conversation)=>{
1298
+ var _conversation_messages;
1299
+ const offerMessage = conversation == null ? void 0 : (_conversation_messages = conversation.messages) == null ? void 0 : _conversation_messages.find((m)=>m.type === "calendar_event_offer");
1300
+ // "Not you?" in flight: the backend echoes a stale calendar_event_offer just
1301
+ // before the fresh gather. Ignore it so the spinner holds until the
1302
+ // lightbox_gather arrives and shows the email step (see restoreGatherFromOffer).
1303
+ if (offerMessage && this.awaitingIdentityChangeRegather.value) return;
1304
+ if (!offerMessage) {
1305
+ var _conversation_messages_filter, _conversation_messages1;
1306
+ const textMessage = conversation == null ? void 0 : (_conversation_messages1 = conversation.messages) == null ? void 0 : (_conversation_messages_filter = _conversation_messages1.filter((m)=>m.type === "text")) == null ? void 0 : _conversation_messages_filter.at(-1);
1307
+ if (!textMessage) return;
1308
+ this.handleElementConversationTextMessage(textMessage);
1309
+ return;
1310
+ }
1311
+ signals_core_module_r(()=>{
1312
+ this.openMessengerForElementConversation();
1313
+ this.elementConversationLoading.value = false;
1314
+ this.elementConversationOffer.value = offerMessage;
1315
+ this.elementConversationTextMessage.value = null;
1316
+ this.closeLightbox();
1317
+ });
1318
+ this.meetingStore.load();
1319
+ }, this.handleElementConversationTextMessage = (payload)=>{
1320
+ var _ref, _ref1, _ref2;
1321
+ const title = (_ref = payload == null ? void 0 : payload.title) != null ? _ref : "";
1322
+ const text = (_ref1 = payload == null ? void 0 : payload.text) != null ? _ref1 : "";
1323
+ const buttonText = (_ref2 = payload == null ? void 0 : payload.button_text) != null ? _ref2 : "Done";
1324
+ if (!title && !text) return;
1325
+ signals_core_module_r(()=>{
1326
+ this.openMessengerForElementConversation();
1327
+ this.elementConversationLoading.value = false;
1328
+ this.elementConversationTextMessage.value = {
1329
+ title,
1330
+ text,
1331
+ buttonText
1332
+ };
1333
+ // If the experience ended with text instead of a re-gather, stop waiting.
1334
+ this.awaitingIdentityChangeRegather.value = false;
1335
+ });
1336
+ }, this.handleInitState = (initialState)=>{
1337
+ // Ignore any state changes just set the reconnecting flag this ensures the next initState will be handled correctly.
1338
+ if (initialState.isReconnecting) {
1339
+ this.isReconnecting.value = true;
1340
+ return;
1341
+ }
1342
+ this.dockingStore.cancelAbort();
1343
+ this.initialized.value = true;
1344
+ metrics.multimodal.timeToInit.log();
1345
+ signals_core_module_r(()=>{
1346
+ var _ref, _initialState_formJoinIdUnique, _initialState_multimodalModalityPreference, _initialState_conversationModeFailover, _initialState_dailyCallObjectBundleUrl, _initialState_dailyWsProxyUrl;
1347
+ var _initialState_themeConfig, _initialState_themeConfig1, _initialState_themeConfig2;
1348
+ // Clear any loading overlay now that the widget has fully initialised.
1349
+ this.closeLightbox();
1350
+ if (initialState.companyName) {
1351
+ this.companyName.value = initialState.companyName;
1352
+ }
1353
+ if (initialState.disableTitleFlash != null) {
1354
+ this.disableTitleFlash.value = initialState.disableTitleFlash;
1355
+ }
1356
+ if (initialState.hasCustomVoiceGreeting !== undefined) {
1357
+ this.hasCustomVoiceGreeting = initialState.hasCustomVoiceGreeting;
1358
+ }
1359
+ if (initialState.conversations) {
1360
+ this.conversations.value = initialState.conversations;
1361
+ }
1362
+ if (initialState.agentsAvailable) {
1363
+ this.agentsAvailable.value = initialState.agentsAvailable;
1364
+ }
1365
+ if (initialState.messages) {
1366
+ const mergedServerMessages = initialState.messages.map((incoming)=>{
1367
+ const existing = this.messages.value.find((m)=>m.id === incoming.id);
1368
+ return existing ? this.mergeMessage(existing, incoming) : incoming;
1369
+ });
1370
+ this.messages.value = mergedServerMessages;
1371
+ this.handleLastInitStateMessage(initialState.messages);
1372
+ // Track pounce response time: start timer when the experience has started
1373
+ // (startChatBot present) but the pounce hasn't arrived yet. Skipped on
1374
+ // page reloads where the pounce is already in the initial messages.
1375
+ //
1376
+ // Not every startChatBot leads to a pounce. Generation is blocked when
1377
+ // proactive pounce is not configured, the visitor replied before the
1378
+ // pounce was created, or the pounce was dismissed. In those cases the
1379
+ // timer is set but never consumed — no metric is emitted.
1380
+ //
1381
+ // NOTE: If a visitor has multiple tabs open and the second tab connects
1382
+ // before the pounce arrives, both tabs will emit the metric. This is
1383
+ // acceptable for a P95 distribution — the duplication window is narrow
1384
+ // and multi-tab is rare.
1385
+ if (this.activeConversationAwaitsPounce() && this.featureFlags.piperXAgent) {
1386
+ this.pounceResponseStartTimestamp = performance.now();
1387
+ }
1388
+ }
1389
+ if (initialState.pounceCandidates !== undefined) {
1390
+ var _initialState_pounceCandidates;
1391
+ this.pounceCandidates.value = (_initialState_pounceCandidates = initialState.pounceCandidates) != null ? _initialState_pounceCandidates : null;
1392
+ }
1393
+ if (this.messages.pounceActive.value) {
1394
+ this.startPounceTracking();
1395
+ }
1396
+ const formJoinIDUnique = (_ref = (_initialState_formJoinIdUnique = initialState.formJoinIdUnique) != null ? _initialState_formJoinIdUnique : (_initialState_themeConfig = initialState.themeConfig) == null ? void 0 : _initialState_themeConfig.formJoinIDUnique) != null ? _ref : null;
1397
+ if (formJoinIDUnique) {
1398
+ this.formJoinIDUnique.value = formJoinIDUnique;
1399
+ }
1400
+ if (initialState.themeConfig) {
1401
+ var _themeConfig_inputPlaceholder, _themeConfig_multimodalHideLauncherLabel;
1402
+ const { themeConfig } = initialState;
1403
+ this.inputPlaceholder.value = (_themeConfig_inputPlaceholder = themeConfig.inputPlaceholder) != null ? _themeConfig_inputPlaceholder : null;
1404
+ this.multimodalHideLauncherLabel.value = (_themeConfig_multimodalHideLauncherLabel = themeConfig.multimodalHideLauncherLabel) != null ? _themeConfig_multimodalHideLauncherLabel : false;
1405
+ if (themeConfig.formJoinIDUnique != null && this.formJoinIDUnique.value == null) {
1406
+ this.formJoinIDUnique.value = themeConfig.formJoinIDUnique;
1407
+ }
1408
+ }
1409
+ this.modalityPreference.value = (_initialState_multimodalModalityPreference = initialState.multimodalModalityPreference) != null ? _initialState_multimodalModalityPreference : null;
1410
+ // Delegate UI-related init to UIStore after server-side modality is available.
1411
+ this.uiStore.handleInitState(initialState);
1412
+ const inputMessage = this.input.message.peek();
1413
+ if (inputMessage) {
1414
+ this.updateInputMessage(inputMessage);
1415
+ }
1416
+ if ((_initialState_themeConfig1 = initialState.themeConfig) == null ? void 0 : _initialState_themeConfig1.privacyDisclosures) {
1417
+ this.privacyDisclosures.value = initialState.themeConfig.privacyDisclosures;
1418
+ }
1419
+ if ((_initialState_themeConfig2 = initialState.themeConfig) == null ? void 0 : _initialState_themeConfig2.cookieConsent) {
1420
+ this.cookieConsent.value = initialState.themeConfig.cookieConsent;
1421
+ }
1422
+ this.flushPendingCookieConsentActions();
1423
+ // Initialize cold start questions
1424
+ if (initialState.coldStartQuestions) {
1425
+ this.coldStartQuestions.value = initialState.coldStartQuestions;
1426
+ }
1427
+ if (typeof initialState.coldStartVisibleLimit === "number") {
1428
+ this.coldStartVisibleLimit.value = initialState.coldStartVisibleLimit;
1429
+ }
1430
+ if (typeof initialState.pounceInactivityThresholdMs === "number") {
1431
+ this.pounceInactivityThresholdMs.value = initialState.pounceInactivityThresholdMs;
1432
+ } else if (initialState.pounceInactivityThresholdMs === null) {
1433
+ this.pounceInactivityThresholdMs.value = null;
1434
+ }
1435
+ if (initialState.scriptLocale) {
1436
+ this.translationStore.setScriptLocale(initialState.scriptLocale);
1437
+ }
1438
+ this.updateConversationModeFailover((_initialState_conversationModeFailover = initialState.conversationModeFailover) != null ? _initialState_conversationModeFailover : {
1439
+ voiceDisabled: false,
1440
+ videoDisabled: false
1441
+ });
1442
+ this.dailyCallObjectBundleUrl.value = (_initialState_dailyCallObjectBundleUrl = initialState.dailyCallObjectBundleUrl) != null ? _initialState_dailyCallObjectBundleUrl : null;
1443
+ this.dailyWsProxyUrl.value = (_initialState_dailyWsProxyUrl = initialState.dailyWsProxyUrl) != null ? _initialState_dailyWsProxyUrl : null;
1444
+ if (this.chatViewDeferredUserIntent) {
1445
+ this.emitChatViewIfEligible({
1446
+ fromUserIntent: true
1447
+ });
1448
+ }
1449
+ if (!this.displayMode.minimized.peek()) {
1450
+ this.markMessagesAsRead();
1451
+ }
1452
+ });
1453
+ this.submitInitialDisplayMode();
1454
+ this.submitInitialModality();
1455
+ this.submitInitialMessage();
1456
+ this.armBookerIntentFromHistory();
1457
+ this.isReconnecting.value = false;
1458
+ }, this.clearElementConversationState = ()=>{
1459
+ signals_core_module_r(()=>{
1460
+ this.elementConversation.value = null;
1461
+ this.elementConversationOffer.value = null;
1462
+ this.elementConversationTextMessage.value = null;
1463
+ this.elementConversationLoading.value = false;
1464
+ this.awaitingIdentityChangeRegather.value = false;
1465
+ });
1466
+ }, this.handleStateUpdate = (stateUpdate)=>{
1467
+ signals_core_module_r(()=>{
1468
+ if (typeof stateUpdate.agentsAvailable === "boolean") {
1469
+ this.agentsAvailable.value = stateUpdate.agentsAvailable;
1470
+ }
1471
+ if (stateUpdate.pounceCandidates !== undefined) {
1472
+ var _stateUpdate_pounceCandidates;
1473
+ this.pounceCandidates.value = (_stateUpdate_pounceCandidates = stateUpdate.pounceCandidates) != null ? _stateUpdate_pounceCandidates : null;
1474
+ }
1475
+ if (stateUpdate.hasCustomVoiceGreeting !== undefined) {
1476
+ this.hasCustomVoiceGreeting = stateUpdate.hasCustomVoiceGreeting;
1477
+ }
1478
+ if (stateUpdate.conversations) {
1479
+ stateUpdate.conversations.forEach((conversation)=>{
1480
+ this.updateConversation(conversation);
1481
+ });
1482
+ }
1483
+ if (stateUpdate.coldStartQuestions) {
1484
+ this.coldStartQuestions.value = stateUpdate.coldStartQuestions;
1485
+ }
1486
+ // A multimodal experience that starts after a delay broadcasts a stateUpdate with
1487
+ // its resolved starting state. Re-apply it so the widget opens in the correct mode
1488
+ // and with the correct profile assets rather than the fallbacks baked in at init.
1489
+ if (stateUpdate.multimodalModalityPreference !== undefined) {
1490
+ var _stateUpdate_multimodalModalityPreference;
1491
+ this.modalityPreference.value = (_stateUpdate_multimodalModalityPreference = stateUpdate.multimodalModalityPreference) != null ? _stateUpdate_multimodalModalityPreference : null;
1492
+ }
1493
+ this.uiStore.applyMultimodalStartState(stateUpdate);
1494
+ });
1495
+ }, this.handleMessage = (incomingMessage)=>{
1496
+ const existingMessage = this.messages.value.find((message)=>message.id === incomingMessage.id);
1497
+ if (existingMessage) {
1498
+ this.handleExistingMessage(existingMessage, incomingMessage);
1499
+ return;
1500
+ }
1501
+ const clientMessageIndex = this.messages.value.findIndex((message)=>message.id === incomingMessage.clientId);
1502
+ // Play audio for text messages
1503
+ if (incomingMessage.type === "text") {
1504
+ this.playMessageAudio(incomingMessage);
1505
+ }
1506
+ signals_core_module_r(()=>{
1507
+ if (incomingMessage.conversation) {
1508
+ this.updateConversation(incomingMessage.conversation);
1509
+ }
1510
+ if (isEventMessage(incomingMessage, "startChatBot") && this.pounceResponseStartTimestamp === null && this.featureFlags.piperXAgent) {
1511
+ this.pounceResponseStartTimestamp = performance.now();
1512
+ } else if (incomingMessage.isPounce && this.pounceResponseStartTimestamp !== null) {
1513
+ const deltaMs = performance.now() - this.pounceResponseStartTimestamp;
1514
+ metrics.emitTiming("multimodal_first_pounce_ms", deltaMs);
1515
+ this.pounceResponseStartTimestamp = null;
1516
+ }
1517
+ if (isAssistantMessage(incomingMessage) && !incomingMessage.isPounce && this.lastVisitorMessageSentAt !== null && !this.turnReplyHandled) {
1518
+ this.clearResponseTimeout();
1519
+ const deltaMs = performance.now() - this.lastVisitorMessageSentAt;
1520
+ const withinBudget = deltaMs <= (/* inlined export .RESPONSE_BUDGET_MS */25000);
1521
+ const obscured = this.turnObscured || this.isDocumentHidden();
1522
+ // Within budget the wait is short enough to trust regardless of visibility;
1523
+ // over budget we only trust the timing if the tab stayed foreground,
1524
+ // since a hidden tab can throttle delivery.
1525
+ if (withinBudget || !obscured) {
1526
+ metrics.emitTiming("multimodal_text_response_ms", deltaMs, {
1527
+ call_active: this.turnCallActiveTag,
1528
+ has_tool_call: this.turnHasToolCall ? "true" : "false"
1529
+ });
1530
+ }
1531
+ if (!this.turnCounterEmitted) {
1532
+ var _this_turnCause;
1533
+ const status = withinBudget ? "success" : obscured ? "backgrounded" : "timeout";
1534
+ metrics.emitIncrement("multimodal_text_response", _extends({
1535
+ status,
1536
+ call_active: this.turnCallActiveTag
1537
+ }, status === "timeout" ? {
1538
+ cause: (_this_turnCause = this.turnCause) != null ? _this_turnCause : "unknown"
1539
+ } : {}));
1540
+ this.turnCounterEmitted = true;
1541
+ } else {
1542
+ // The 25s timer already fired and counted this turn as a timeout.
1543
+ // Log the late reply so we can distinguish "AI responded slowly" from
1544
+ // "reply never arrived" when investigating timeout events.
1545
+ serverLogger.serverLog({
1546
+ type: "log",
1547
+ message: "Multimodal text reply arrived after response budget (late)",
1548
+ extra: {
1549
+ context: "elapsed_ms:" + Math.round(deltaMs)
1550
+ }
1551
+ });
1552
+ }
1553
+ this.turnReplyHandled = true;
1554
+ this.turnToken++;
1555
+ }
1556
+ this.addMessage(incomingMessage, clientMessageIndex);
1557
+ if (isAssistantMessage(incomingMessage)) {
1558
+ this.setTypingIndicator(false);
1559
+ this.markIncomingMessageAsRead(incomingMessage);
1560
+ }
1561
+ this.handleIncomingMessage(incomingMessage);
1562
+ });
1563
+ }, this.handleExistingMessage = (existingMessage, incomingMessage)=>{
1564
+ // Capture before updateMessage mutates existingMessage in place.
1565
+ // In voice mode the CalendarEventOffer starts hidden (showCalendarEventOfferUi: false)
1566
+ // until the voice placeholder is filled. When it transitions to visible we delay
1567
+ // showing the meeting booker so the visitor can read the transcript first.
1568
+ const wasHiddenByPlaceholder = existingMessage.type === "calendar_event_offer" && existingMessage.showCalendarEventOfferUi === false;
1569
+ signals_core_module_r(()=>{
1570
+ this.updateMessage(existingMessage, incomingMessage);
1571
+ this.markIncomingMessageAsRead(incomingMessage);
1572
+ this.handleIncomingMessage(incomingMessage, {
1573
+ wasHiddenByPlaceholder
1574
+ });
1575
+ });
1576
+ }, this.markIncomingMessageAsRead = (incomingMessage)=>{
1577
+ if (isAssistantMessage(incomingMessage) && !this.displayMode.minimized.value && (!isStreamableMessage(incomingMessage) || !this.isMessageStreamingEnabled.value)) {
1578
+ this.markMessagesAsRead([
1579
+ incomingMessage
1580
+ ]);
1581
+ }
1582
+ }, this.handleIncomingMessage = (incomingMessage, param)=>{
1583
+ let { wasHiddenByPlaceholder = false } = param === void 0 ? {} : param;
1584
+ switch(incomingMessage.type){
1585
+ case "calendar_event_offer":
1586
+ // Closes the pre-offer SLI here, at message *receipt*, which is where the
1587
+ // metric is defined to end. Resolving it off `activeOfferMessage` instead
1588
+ // would fold in client-side delay: that subscription waits on the lazy
1589
+ // `meetingStore` import, and the voice-placeholder path below defers it a
1590
+ // further second — neither of which is time the visitor spent waiting for
1591
+ // an offer.
1592
+ //
1593
+ // Only an AI-authored offer closes an AI intent. The client is never told
1594
+ // when the server decided *not* to offer (`no_offer` lives only in the
1595
+ // tool's `decision_outcome`), so a rejected intent stays armed — and a
1596
+ // later offer from a rep or a form would otherwise report `offered`
1597
+ // against it, giving one journey two terminal outcomes and inflating the
1598
+ // offer-made rate. `auto_respond` is the same discriminator
1599
+ // `bookerPathwayOrigin` uses to tell `ai_agent` from `chat`, and both AI
1600
+ // paths stamp it (Goals inline, Foundry via the deferred offer). Checked
1601
+ // directly rather than through that helper, which resolves `element`
1602
+ // conversations to `form` first and so would miss an AI offer made inside
1603
+ // one.
1604
+ if (isAiAuthoredOffer(incomingMessage.source)) {
1605
+ var _incomingMessage_calendarEventTypeId;
1606
+ this.bookerIntentTracker.markOffered(incomingMessage.id, {
1607
+ calendarEventTypeId: (_incomingMessage_calendarEventTypeId = incomingMessage.calendarEventTypeId) == null ? void 0 : _incomingMessage_calendarEventTypeId.toString()
1608
+ });
1609
+ }
1610
+ if (incomingMessage.showCalendarEventOfferUi !== false) {
1611
+ // When transitioning from hidden to visible (voice placeholder just
1612
+ // filled), delay showing the meeting booker so the visitor has time
1613
+ // to read the transcript text that appeared in the placeholder.
1614
+ void this.queueArtifactMessage(incomingMessage, {
1615
+ delayMs: wasHiddenByPlaceholder ? RootStore.MEETING_BOOKER_PLACEHOLDER_DELAY_MS : 0
1616
+ });
1617
+ }
1618
+ break;
1619
+ case "field_request":
1620
+ if (incomingMessage.showFieldUi) {
1621
+ this.updateInputMessage(incomingMessage);
1622
+ }
1623
+ break;
1624
+ case "field_entry":
1625
+ if (!this.conversationMode.text.value) {
1626
+ this.clearInputMessage({
1627
+ when: types_InputState.FIELD_REQUEST
1628
+ });
1629
+ }
1630
+ break;
1631
+ case "present_content":
1632
+ case "present_video":
1633
+ case "present_deck":
1634
+ case "navigate_content":
1635
+ void this.queueArtifactMessage(incomingMessage);
1636
+ break;
1637
+ case "point_cursor":
1638
+ {
1639
+ const { x, y, rect, nodeId, textSnippet } = incomingMessage;
1640
+ this.websiteNavigationStore.load().then((store)=>{
1641
+ // x/y => point at a spot on the slide/video image; otherwise anchor to a page element by node-id.
1642
+ if (x != null && y != null) {
1643
+ store.pointAtSlide(x, y, rect != null ? rect : null);
1644
+ } else {
1645
+ store.pointAtNode(nodeId != null ? nodeId : null, textSnippet);
1646
+ }
1647
+ });
1648
+ break;
1649
+ }
1650
+ case "event":
1651
+ if (incomingMessage.eventType === "hide_artifact") {
1652
+ this.artifactStore.hideArtifact(incomingMessage.artifactMessageId);
1653
+ }
1654
+ if (incomingMessage.eventType === "waiting") {
1655
+ this.waitingStore.load().then((store)=>store.handleWaitingMessage(incomingMessage));
1656
+ }
1657
+ if (incomingMessage.eventType === CAN_OFFER_MEETING_BOOKER_EVENT_TYPE) {
1658
+ this.armBookerIntent(incomingMessage.id, {
1659
+ scriptId: incomingMessage.scriptId
1660
+ });
1661
+ }
1662
+ break;
1663
+ case "system":
1664
+ {
1665
+ const { eventType } = incomingMessage;
1666
+ // if we are in an active call and a rep joins, coffee will signal to us to switch over to text
1667
+ if (eventType === "participant_joined" && !this.getCallUiAdapter().state.isInCall.peek()) {
1668
+ this.setConversationMode(types_ConversationMode.TEXT);
1669
+ }
1670
+ break;
1671
+ }
1672
+ default:
1673
+ break;
1674
+ }
1675
+ }, this.handleMessageRead = (messageId)=>{
1676
+ const message = this.messages.value.find((m)=>m.id === messageId);
1677
+ if (message && !message.isRead) {
1678
+ this.updateMessage(message, {
1679
+ isRead: true
1680
+ });
1681
+ }
1682
+ }, this.handleBotProcessEnded = ()=>{
1683
+ var _this_waitingStore_value;
1684
+ if (this.messages.hasStartChatBotEvent.peek() || ((_this_waitingStore_value = this.waitingStore.value) == null ? void 0 : _this_waitingStore_value.isWaiting.value)) {
1685
+ return;
1686
+ }
1687
+ this.setTypingIndicator(false);
1688
+ }, // Helpers
1689
+ /**
1690
+ * Scans init state messages from the end to find the last message that needs
1691
+ * to be handled (e.g. an unreplied field_request or an unresolved waiting event).
1692
+ * Only the first match is handled, ensuring a single call to handleIncomingMessage.
1693
+ */ this.handleLastInitStateMessage = (messages)=>{
1694
+ const matchers = [
1695
+ // Unreplied field_request from an assistant
1696
+ (m)=>m.type === "field_request" && m.showFieldUi === true && !this.messages.repliedToIds.value.has(m.id),
1697
+ // Active (unresolved) waiting event
1698
+ (m)=>isEventMessage(m, "waiting") && !this.messages.repliedToIds.value.has(m.id)
1699
+ ];
1700
+ for(let i = messages.length - 1; i >= 0; i--){
1701
+ const message = messages[i];
1702
+ if (matchers.some((matcher)=>matcher(message))) {
1703
+ this.handleIncomingMessage(message);
1704
+ return;
1705
+ }
1706
+ }
1707
+ }, /**
1708
+ * Inject a client-only text message into the active conversation. Renders as a
1709
+ * normal (non-own) text bubble, not a SystemMessage. Used for transient UI notices
1710
+ * (e.g. graceful degradation when voice/video is unavailable). Not persisted server-side.
1711
+ */ this.displayLocalNotice = (text)=>{
1712
+ var _this_activeConversation_value;
1713
+ const conversationId = (_this_activeConversation_value = this.activeConversation.value) == null ? void 0 : _this_activeConversation_value.id;
1714
+ if (!conversationId) return;
1715
+ this.addMessage({
1716
+ id: "local-" + Date.now() + "-" + Math.random().toString(36).slice(2, 8),
1717
+ type: "text",
1718
+ text,
1719
+ isOwn: false,
1720
+ conversationId,
1721
+ createdAt: new Date().toISOString()
1722
+ });
1723
+ }, this.addMessage = (message, index)=>{
1724
+ if (index !== undefined && index >= 0) {
1725
+ this.messages.value[index] = message;
1726
+ this.messages.value = [
1727
+ ...this.messages.value
1728
+ ];
1729
+ } else {
1730
+ this.messages.value = [
1731
+ ...this.messages.value,
1732
+ message
1733
+ ];
1734
+ }
1735
+ }, this.firstSystemMessageReceived = false, this.playMessageAudio = (message)=>{
1736
+ if (this.featureFlags.disableMessengerSounds) return;
1737
+ if (this.getCallUiAdapter().state.isInCall.peek()) {
1738
+ // Don't play audio if we're in a call
1739
+ return;
1740
+ }
1741
+ if (message.isOwn) {
1742
+ playAudio(message_sent_namespaceObject);
1743
+ } else if (!this.firstSystemMessageReceived) {
1744
+ playAudio(message_initial_namespaceObject);
1745
+ this.firstSystemMessageReceived = true;
1746
+ } else {
1747
+ playAudio(message_received_namespaceObject);
1748
+ }
1749
+ }, this.updateConversation = (conversation)=>{
1750
+ this.conversations.value = this.conversations.value.map((c)=>c.id === conversation.id ? conversation : c);
1751
+ }, /**
1752
+ * Arms the pre-offer booker SLI for the AI pathway.
1753
+ *
1754
+ * `pathway_origin` is the literal `ai_agent` rather than the derivation the
1755
+ * post-offer tracker uses: that derivation reads the offer's `source`, and at
1756
+ * intent there is no offer yet — it would silently classify every AI intent as
1757
+ * `chat`. This signal *is* the AI deciding to offer.
1758
+ */ this.armBookerIntent = (intentId, param)=>{
1759
+ let { scriptId, fromHistory = false } = param === void 0 ? {} : param;
1760
+ var _ref;
1761
+ var _this_activeConversation_peek;
1762
+ // Gated at arm rather than at emit: with nothing armed the tracker holds no
1763
+ // state and its listeners are never attached, so the feature costs nothing
1764
+ // when off. Does not affect the already-live `booker_outcome` stream, which
1765
+ // `meeting_store` emits independently.
1766
+ if (!this.featureFlags.bookerJourneySLI) return;
1767
+ this.bookerIntentTracker.arm({
1768
+ intentId,
1769
+ pathwayOrigin: BOOKER_PATHWAY_ORIGIN.AI_AGENT,
1770
+ conversationType: (_ref = (_this_activeConversation_peek = this.activeConversation.peek()) == null ? void 0 : _this_activeConversation_peek.type) != null ? _ref : "chat",
1771
+ scriptId,
1772
+ fromHistory
1773
+ });
1774
+ }, /**
1775
+ * Re-arms the pre-offer SLI after a reload that lands mid-wait: the intent
1776
+ * event is already in the hydrated history, so the live `case "event"` path
1777
+ * never sees it and the wait would go unmeasured.
1778
+ *
1779
+ * Armed as `fromHistory`, which reports it far more conservatively: no timings
1780
+ * (the intent moment belongs to a previous JS context) and never
1781
+ * `abandoned_pre_offer`. Absence of a later offer does not prove the intent is
1782
+ * still pending — a rejected server-side decision leaves exactly this shape,
1783
+ * since `no_offer` never reaches the client — so abandoning here would
1784
+ * double-count that journey against the server's own `no_offer`. `offered` is
1785
+ * the one transition this path can claim unambiguously.
1786
+ */ this.armBookerIntentFromHistory = ()=>{
1787
+ const messages = this.messages.peek();
1788
+ const intentIndex = messages.findLastIndex((message)=>message.type === "event" && message.eventType === CAN_OFFER_MEETING_BOOKER_EVENT_TYPE);
1789
+ if (intentIndex === -1) return;
1790
+ const intentMessage = messages[intentIndex];
1791
+ // If the offer this intent asked for already arrived, the wait is over.
1792
+ // Arming anyway would emit a second `offered` for an offer no one waited on.
1793
+ //
1794
+ // Matched on AI-authored offers only, the same test the live path applies. A
1795
+ // rep can offer a meeting while the AI's own offer is still being prepared, and
1796
+ // treating that as the intent's answer would abandon a wait that is still
1797
+ // running and drop the journey from the SLI entirely. Arming when the AI never
1798
+ // does answer is harmless: a hydrated intent cannot report abandonment.
1799
+ const offerArrived = messages.slice(intentIndex + 1).some((message)=>message.type === "calendar_event_offer" && isAiAuthoredOffer("source" in message ? message.source : undefined));
1800
+ if (offerArrived) return;
1801
+ this.armBookerIntent(intentMessage.id, {
1802
+ // An index cannot carry the narrowing out of the predicate above, and the
1803
+ // optimistic (not-yet-persisted) message variants carry no server fields at
1804
+ // all, so this probes for the field rather than asserting it away.
1805
+ scriptId: "scriptId" in intentMessage ? intentMessage.scriptId : undefined,
1806
+ fromHistory: true
1807
+ });
1808
+ }, this.submitInitialDisplayMode = ()=>{
1809
+ const hasStartingDisplayModeMessage = !!this.messages.peek().find((message)=>message.type === "event" && message.eventType === "startingDisplayMode");
1810
+ if (!hasStartingDisplayModeMessage) {
1811
+ this.sendMessage({
1812
+ type: "event",
1813
+ eventType: "startingDisplayMode"
1814
+ });
1815
+ }
1816
+ }, this.submitInitialModality = ()=>{
1817
+ const hasStartingModalityMessage = !!this.messages.peek().find((message)=>message.type === "event" && message.eventType === "startingModality");
1818
+ if (hasStartingModalityMessage) return;
1819
+ const modality = this.modalityPreference.peek();
1820
+ if (!modality) return;
1821
+ this.sendMessage({
1822
+ type: "event",
1823
+ eventType: "startingModality",
1824
+ multimodalStartingModality: modality
1825
+ });
1826
+ }, this.submitInitialMessage = ()=>{
1827
+ var _this_activeConversation_peek;
1828
+ const initialMessage = (_this_activeConversation_peek = this.activeConversation.peek()) == null ? void 0 : _this_activeConversation_peek.initialMessage;
1829
+ if (!initialMessage) return;
1830
+ const hasVisitorText = this.getActiveConversationMessages().some((m)=>m.type === "text" && "isOwn" in m && m.isOwn);
1831
+ if (!hasVisitorText) {
1832
+ this.sendVisitorText(initialMessage);
1833
+ }
1834
+ }, this.getActiveConversationMessages = ()=>{
1835
+ var _this_activeConversation_peek;
1836
+ const conversationId = (_this_activeConversation_peek = this.activeConversation.peek()) == null ? void 0 : _this_activeConversation_peek.id;
1837
+ if (!conversationId) return [];
1838
+ return this.messages.value.filter((m)=>m.conversationId === conversationId);
1839
+ }, this.activeConversationAwaitsPounce = ()=>{
1840
+ let pastStartChatBot = false;
1841
+ for (const m of this.getActiveConversationMessages()){
1842
+ if (isEventMessage(m, "startChatBot")) {
1843
+ pastStartChatBot = true;
1844
+ } else if (pastStartChatBot && m.type !== "event") {
1845
+ return false;
1846
+ }
1847
+ }
1848
+ return pastStartChatBot;
1849
+ }, this.debugLog = (msg, context)=>{
1850
+ if (isDebugMode()) {
1851
+ // eslint-disable-next-line no-console
1852
+ console.log("[Multimodal - RootStore] " + msg, context);
1853
+ }
1854
+ }, this.startPounceTracking = ()=>{
1855
+ if (this.pounceTrackingLoadStarted) {
1856
+ return;
1857
+ }
1858
+ this.pounceTrackingLoadStarted = true;
1859
+ this.pounceTrackingStore.load().then((pounceTrackingStore)=>{
1860
+ if (this.messages.pounceActive.peek()) {
1861
+ pounceTrackingStore.startTracking();
1862
+ } else {
1863
+ pounceTrackingStore.dispose();
1864
+ this.pounceTrackingLoadStarted = false;
1865
+ }
1866
+ }).catch(()=>{
1867
+ this.pounceTrackingLoadStarted = false;
1868
+ // Pounce tracking is non-critical - fail silently
1869
+ });
1870
+ };
1871
+ // WS message handlers
1872
+ for (const [event, handler] of Object.entries(this.messageHandlers)){
1873
+ this.channel.on(event, handler);
1874
+ }
1875
+ // Effect handlers
1876
+ for (const handler of this.signalSubscriptions){
1877
+ handler();
1878
+ }
1879
+ // Initialize translation store (sets up locale effects)
1880
+ this.translationStore.initialize();
1881
+ if (typeof document !== "undefined") {
1882
+ __nativeDocumentAddEventListener("visibilitychange", this.handleTurnVisibilityChange);
1883
+ }
1884
+ }
1885
+ }
1886
+ RootStore.IMPRESSED_MESSAGE_IDS_MAX_SIZE = 100;
1887
+ /**
1888
+ * How long the booker waits when the offer arrives by way of a voice
1889
+ * placeholder, so the visitor can read the transcript text that just filled it
1890
+ * before the overlay covers the page.
1891
+ */ RootStore.MEETING_BOOKER_PLACEHOLDER_DELAY_MS = 1000;
1892
+ // Kept in sync with MultimodalAgentWorker#broadcast_text_response_ended.
1893
+ RootStore.TEXT_RESPONSE_ENDED_REASONS = [
1894
+ "suppressed",
1895
+ "blank_output"
1896
+ ];
1897
+ // Kept in sync with AiConversations::TurnCause::CAUSES.
1898
+ RootStore.TURN_CAUSES = [
1899
+ "queue_wait",
1900
+ "setup",
1901
+ "llm_slow",
1902
+ "agent_loop",
1903
+ "tool_slow",
1904
+ "side_llm_wait",
1905
+ "generation_failed",
1906
+ "output_moderation_retry",
1907
+ "unknown"
1908
+ ];
1909
+ const RootStoreContext = Q(null);
1910
+ /**
1911
+ * Please avoid using this hook as much as possible!!!
1912
+ * It makes components harder to test and work with.
1913
+ */ function useRootStore() {
1914
+ return hooks_module_x(RootStoreContext);
1915
+ }
1916
+
1917
+ var root_store_CAUSE_REPORT_GRACE_MS = (/* inlined export .CAUSE_REPORT_GRACE_MS */1500);
1918
+ var root_store_RESPONSE_BUDGET_MS = (/* inlined export .RESPONSE_BUDGET_MS */25000);
1919
+ export { RootStore, RootStoreContext, root_store_CAUSE_REPORT_GRACE_MS as CAUSE_REPORT_GRACE_MS, root_store_RESPONSE_BUDGET_MS as RESPONSE_BUDGET_MS, useRootStore };