@flowengage/react-chatbot 8.0.11 → 8.0.13

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.
@@ -3505,7 +3505,19 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3505
3505
  sender: "user",
3506
3506
  text: t
3507
3507
  }));
3508
- }, Zt = async (e, t = "", n = null, a = {}) => {
3508
+ };
3509
+ function Zt() {
3510
+ if (typeof document > "u") return null;
3511
+ try {
3512
+ let e = (document.querySelector("main") || document.querySelector("[role='main']") || document.querySelector("article") || document.querySelector("#content") || document.querySelector(".content") || document.body).cloneNode(!0);
3513
+ e.querySelectorAll("nav, footer, header, aside, script, style, noscript, #flowengage-root, .flowengage-shell, .flowengage-widget-root, [id*='flowengage'], [class*='flowengage']").forEach((e) => e.remove());
3514
+ let t = e.textContent.replace(/\s+/g, " ").trim();
3515
+ return t.length > 0 ? t.substring(0, 3e3) : null;
3516
+ } catch {
3517
+ return null;
3518
+ }
3519
+ }
3520
+ let Qt = async (e, t = "", n = null, a = {}) => {
3509
3521
  let o = typeof e == "string" ? e.trim() : "";
3510
3522
  if (!o || !j.current || !y || l !== "ready" || Be) return;
3511
3523
  Yt();
@@ -3555,7 +3567,8 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3555
3567
  ...a,
3556
3568
  currentPageUrl: typeof window < "u" ? window.location.href : void 0,
3557
3569
  currentPageTitle: typeof window < "u" ? document.title : void 0,
3558
- currentPagePath: typeof window < "u" ? window.location.pathname : void 0
3570
+ currentPagePath: typeof window < "u" ? window.location.pathname : void 0,
3571
+ currentPageContent: Zt() || void 0
3559
3572
  }), c = s.chat_history || [];
3560
3573
  if (console.log("[FWH Nav Debug] API response fields:", {
3561
3574
  has_navigate: !!s.navigate,
@@ -3613,10 +3626,10 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3613
3626
  Ae(!1), Me("");
3614
3627
  }, ie)) : h(e);
3615
3628
  }
3616
- }, Qt = async (e) => {
3629
+ }, $t = async (e) => {
3617
3630
  if (!j.current || !e) throw Error("Upload is unavailable right now.");
3618
3631
  return j.current.uploadChatFile(e);
3619
- }, $t = async (e) => {
3632
+ }, en = async (e) => {
3620
3633
  if (!(!j.current || !y)) {
3621
3634
  try {
3622
3635
  let t = e ? "voice" : "text";
@@ -3624,7 +3637,7 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3624
3637
  } catch {}
3625
3638
  Fe(e), e && (Tt.current = !1);
3626
3639
  }
3627
- }, en = async (e) => {
3640
+ }, tn = async (e) => {
3628
3641
  if (Tt.current) return;
3629
3642
  if (Tt.current = !0, !j.current || !y || !e?.length) {
3630
3643
  Fe(!1);
@@ -3653,9 +3666,9 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3653
3666
  } finally {
3654
3667
  Fe(!1);
3655
3668
  }
3656
- }, tn = async () => {
3669
+ }, nn = async () => {
3657
3670
  if (!(!j.current || !y)) {
3658
- Pe && !Tt.current && wt.current.length > 0 && await en(wt.current);
3671
+ Pe && !Tt.current && wt.current.length > 0 && await tn(wt.current);
3659
3672
  try {
3660
3673
  await j.current.endConversation(y);
3661
3674
  } catch {
@@ -3700,12 +3713,12 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3700
3713
  window.removeEventListener("pagehide", e), window.removeEventListener("beforeunload", e);
3701
3714
  };
3702
3715
  }, []);
3703
- let nn = o(() => {
3716
+ let rn = o(() => {
3704
3717
  let e = i?.siteId;
3705
3718
  ge(e), at.current = !0, ot.current = null, A.current?.disconnect(), S([]), b(""), it.current = "", Ve(!1), re(!1), D(null), de(null), rt(!0), s((e) => e + 1);
3706
- }, [i?.siteId]), rn = o((e) => {
3719
+ }, [i?.siteId]), an = o((e) => {
3707
3720
  i?.siteId, at.current = !1, ot.current = e, A.current?.disconnect(), S([]), b(""), it.current = "", Ve(!1), re(!1), D(null), de(null), rt(!0), s((e) => e + 1);
3708
- }, [i?.siteId]), an = f(() => ({
3721
+ }, [i?.siteId]), on = f(() => ({
3709
3722
  status: l,
3710
3723
  error: d,
3711
3724
  runtimeConfig: _,
@@ -3753,13 +3766,13 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3753
3766
  }
3754
3767
  Kt({ notifyChatInitiated: !0 });
3755
3768
  },
3756
- sendMessage: Zt,
3757
- uploadChatFile: Qt,
3758
- setVoiceMode: $t,
3759
- onMessageSync: en,
3760
- endConversation: tn,
3761
- startNewChat: nn,
3762
- resumeChat: rn,
3769
+ sendMessage: Qt,
3770
+ uploadChatFile: $t,
3771
+ setVoiceMode: en,
3772
+ onMessageSync: tn,
3773
+ endConversation: nn,
3774
+ startNewChat: rn,
3775
+ resumeChat: an,
3763
3776
  getVisitorChatHistory: () => j.current?.getVisitorChatHistory?.(),
3764
3777
  getVisitorChatThread: (e) => j.current?.getVisitorChatThread?.(e),
3765
3778
  acceptCall: Vt,
@@ -3806,16 +3819,16 @@ function Wr({ siteId: e, config: t, children: n, language: r = "en" }) {
3806
3819
  Wt,
3807
3820
  Gt,
3808
3821
  Kt,
3809
- Zt,
3810
3822
  Qt,
3811
3823
  $t,
3812
3824
  en,
3813
3825
  tn,
3814
3826
  nn,
3827
+ rn,
3815
3828
  jt
3816
3829
  ]);
3817
3830
  return /* @__PURE__ */ g(Pn.Provider, {
3818
- value: an,
3831
+ value: on,
3819
3832
  children: n
3820
3833
  });
3821
3834
  }
@@ -28814,29 +28827,18 @@ function NO() {
28814
28827
  }, 380)));
28815
28828
  }, 220)));
28816
28829
  }
28817
- function PO() {
28818
- typeof document > "u" || document.querySelectorAll(`.${Q}-field-active, .${Q}-field-filled`).forEach((e) => e.classList.remove(`${Q}-field-active`, `${Q}-field-filled`));
28819
- }
28820
- function FO(e) {
28821
- !e || typeof document > "u" || (CO(), PO(), e.classList.add(`${Q}-field-active`));
28822
- }
28823
- function IO(e) {
28824
- e && (e.classList.remove(`${Q}-field-active`), e.classList.add(`${Q}-field-filled`), setTimeout(() => {
28825
- e.isConnected && e.classList.remove(`${Q}-field-filled`);
28826
- }, 1400));
28827
- }
28828
- var LO = `<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22" fill="none">
28830
+ var PO = `<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22" fill="none">
28829
28831
  <filter id="${Q}-csh">
28830
28832
  <feDropShadow dx="1" dy="2" stdDeviation="1.5" flood-color="#00000060"/>
28831
28833
  </filter>
28832
28834
  <path d="M4 2L19 10.5L11 12.8L8 20L4 2Z"
28833
28835
  fill="white" stroke="#1e1b4b" stroke-width="1.6" stroke-linejoin="round"
28834
28836
  filter="url(#${Q}-csh)"/>
28835
- </svg>`, RO = null, zO = !1;
28836
- function BO() {
28837
- return (!RO || !RO.isConnected) && (RO = document.createElement("div"), RO.id = `${Q}-cursor`, RO.innerHTML = LO, document.body.appendChild(RO), zO = !1), RO;
28837
+ </svg>`, FO = null, IO = !1;
28838
+ function LO() {
28839
+ return (!FO || !FO.isConnected) && (FO = document.createElement("div"), FO.id = `${Q}-cursor`, FO.innerHTML = PO, document.body.appendChild(FO), IO = !1), FO;
28838
28840
  }
28839
- async function VO(e) {
28841
+ async function RO(e) {
28840
28842
  if (typeof document > "u" || !e) return;
28841
28843
  CO();
28842
28844
  let t;
@@ -28845,18 +28847,18 @@ async function VO(e) {
28845
28847
  } catch {
28846
28848
  return;
28847
28849
  }
28848
- let n = t.left + Math.min(16, t.width * .2), r = t.top + Math.min(12, t.height * .25), i = BO();
28849
- zO ||= (i.style.transition = "none", i.style.left = `${window.innerWidth / 2}px`, i.style.top = `${window.innerHeight * .4}px`, i.classList.add(`${Q}-cursor-visible`), i.offsetHeight, i.style.transition = "left 0.32s cubic-bezier(0.25,0.46,0.45,0.94), top 0.32s cubic-bezier(0.25,0.46,0.45,0.94), opacity 0.2s ease", !0), i.style.left = `${n}px`, i.style.top = `${r}px`, await GO(360);
28850
+ let n = t.left + Math.min(16, t.width * .2), r = t.top + Math.min(12, t.height * .25), i = LO();
28851
+ IO ||= (i.style.transition = "none", i.style.left = `${window.innerWidth / 2}px`, i.style.top = `${window.innerHeight * .4}px`, i.classList.add(`${Q}-cursor-visible`), i.offsetHeight, i.style.transition = "left 0.32s cubic-bezier(0.25,0.46,0.45,0.94), top 0.32s cubic-bezier(0.25,0.46,0.45,0.94), opacity 0.2s ease", !0), i.style.left = `${n}px`, i.style.top = `${r}px`, await HO(360);
28850
28852
  }
28851
- function HO(e = !1) {
28852
- RO && (e ? (RO.classList.remove(`${Q}-cursor-visible`), zO = !1) : (RO.classList.remove(`${Q}-cursor-visible`), setTimeout(() => {
28853
- zO = !1;
28853
+ function zO(e = !1) {
28854
+ FO && (e ? (FO.classList.remove(`${Q}-cursor-visible`), IO = !1) : (FO.classList.remove(`${Q}-cursor-visible`), setTimeout(() => {
28855
+ IO = !1;
28854
28856
  }, 250)));
28855
28857
  }
28856
- async function UO(e) {
28857
- RO && (RO.classList.add(`${Q}-cursor-click`), await GO(280), RO.classList.remove(`${Q}-cursor-click`));
28858
+ async function BO(e) {
28859
+ FO && (FO.classList.add(`${Q}-cursor-click`), await HO(280), FO.classList.remove(`${Q}-cursor-click`));
28858
28860
  }
28859
- function WO(e) {
28861
+ function VO(e) {
28860
28862
  if (!e || typeof document > "u") return;
28861
28863
  CO();
28862
28864
  let t;
@@ -28884,7 +28886,7 @@ function WO(e) {
28884
28886
  a.remove(), e.style.position = n, e.style.overflow = r;
28885
28887
  }, 650);
28886
28888
  }
28887
- function GO(e) {
28889
+ function HO(e) {
28888
28890
  return new Promise((t) => setTimeout(t, e));
28889
28891
  }
28890
28892
  //#endregion
@@ -28892,17 +28894,14 @@ function GO(e) {
28892
28894
  function $(...e) {
28893
28895
  In() && console.log("[FlowEngage:voice-tools]", ...e);
28894
28896
  }
28895
- function KO(e) {
28896
- return new Promise((t) => setTimeout(t, e));
28897
- }
28898
- function qO(e) {
28897
+ function UO(e) {
28899
28898
  try {
28900
28899
  let t = e.ownerDocument?.defaultView;
28901
28900
  if (t) return t.getComputedStyle(e);
28902
28901
  } catch {}
28903
28902
  return window.getComputedStyle(e);
28904
28903
  }
28905
- function JO(e) {
28904
+ function WO(e) {
28906
28905
  let t = /* @__PURE__ */ new Set();
28907
28906
  function n(r) {
28908
28907
  if (!r || t.has(r)) return;
@@ -28915,10 +28914,10 @@ function JO(e) {
28915
28914
  }
28916
28915
  typeof document < "u" && n(document);
28917
28916
  }
28918
- function YO(e) {
28917
+ function GO(e) {
28919
28918
  return e == null ? null : String(e).replace(/\u00a0/g, " ").replace(/\s*\*+\s*$/u, "").replace(/\s+/g, " ").trim();
28920
28919
  }
28921
- function XO(e) {
28920
+ function KO(e) {
28922
28921
  let t = e.ownerDocument || document, n = e.getAttribute("aria-labelledby");
28923
28922
  if (n) {
28924
28923
  let e = n.trim().split(/\s+/).filter(Boolean), r = [];
@@ -28926,40 +28925,40 @@ function XO(e) {
28926
28925
  let e = t.getElementById(n);
28927
28926
  e?.textContent && r.push(e.textContent.trim());
28928
28927
  } catch {}
28929
- if (r.length) return YO(r.join(" "));
28928
+ if (r.length) return GO(r.join(" "));
28930
28929
  }
28931
- if (e.labels && e.labels.length) return YO(e.labels[0].textContent);
28930
+ if (e.labels && e.labels.length) return GO(e.labels[0].textContent);
28932
28931
  let r = e.id;
28933
28932
  if (r) try {
28934
28933
  let e = t.querySelector(`label[for="${CSS.escape(r)}"]`);
28935
- if (e) return YO(e.textContent);
28934
+ if (e) return GO(e.textContent);
28936
28935
  } catch {
28937
28936
  let e = t.querySelector(`label[for="${r.replace(/"/g, "\\\"")}"]`);
28938
- if (e) return YO(e.textContent);
28937
+ if (e) return GO(e.textContent);
28939
28938
  }
28940
28939
  let i = e.previousElementSibling;
28941
28940
  for (let e = 0; e < 6 && i; e += 1) {
28942
- if (i.tagName === "LABEL") return YO(i.textContent);
28941
+ if (i.tagName === "LABEL") return GO(i.textContent);
28943
28942
  let e = (i.className || "").toString().toLowerCase();
28944
28943
  if (/chakra-form__label|formlabel|field-label|form-label|mui-form-label/.test(e)) {
28945
- let e = YO(i.textContent);
28944
+ let e = GO(i.textContent);
28946
28945
  if (e) return e;
28947
28946
  }
28948
28947
  i = i.previousElementSibling;
28949
28948
  }
28950
28949
  let a = e.parentElement;
28951
28950
  for (let e = 0; e < 5 && a; e += 1) {
28952
- if (a.tagName === "LABEL") return YO(a.textContent);
28951
+ if (a.tagName === "LABEL") return GO(a.textContent);
28953
28952
  let e = a.querySelector?.(":scope > label, :scope > [class*='FormLabel'], :scope > [class*='form__label']");
28954
- if (e?.textContent) return YO(e.textContent);
28953
+ if (e?.textContent) return GO(e.textContent);
28955
28954
  a = a.parentElement;
28956
28955
  }
28957
28956
  let o = e.getAttribute("aria-label");
28958
- return o ? YO(o) : null;
28957
+ return o ? GO(o) : null;
28959
28958
  }
28960
- function ZO() {
28959
+ function qO() {
28961
28960
  let e = [];
28962
- return JO((t) => {
28961
+ return WO((t) => {
28963
28962
  e.push(...Array.from(t.querySelectorAll("input, select, textarea")).filter((e) => {
28964
28963
  if (Hn(e)) return !1;
28965
28964
  let t = (e.type || "").toLowerCase();
@@ -28970,15 +28969,15 @@ function ZO() {
28970
28969
  "image"
28971
28970
  ].includes(t) || e.disabled || e.readOnly) return !1;
28972
28971
  try {
28973
- let t = qO(e);
28972
+ let t = UO(e);
28974
28973
  if (t.display === "none" || t.visibility === "hidden") return !1;
28975
28974
  } catch {}
28976
28975
  return !0;
28977
28976
  }));
28978
28977
  }), e;
28979
28978
  }
28980
- function QO() {
28981
- return ZO().map((e, t) => {
28979
+ function JO() {
28980
+ return qO().map((e, t) => {
28982
28981
  let n = {
28983
28982
  formIndex: 0,
28984
28983
  fieldIndex: t,
@@ -28986,7 +28985,7 @@ function QO() {
28986
28985
  type: e.type || "text",
28987
28986
  name: e.name || null,
28988
28987
  id: e.id || null,
28989
- label: XO(e),
28988
+ label: KO(e),
28990
28989
  placeholder: e.placeholder || null
28991
28990
  };
28992
28991
  return e.tagName === "SELECT" && (n.options = Array.from(e.options).filter((e) => e.value !== "" && !e.disabled).map((e) => ({
@@ -28995,13 +28994,13 @@ function QO() {
28995
28994
  })), n.currentValue = e.value || null), n;
28996
28995
  });
28997
28996
  }
28998
- function $O() {
28997
+ function YO() {
28999
28998
  let e = [];
29000
- return JO((t) => {
28999
+ return WO((t) => {
29001
29000
  e.push(...Array.from(t.querySelectorAll("button, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"]")).filter((e) => {
29002
29001
  if (Hn(e) || e.disabled) return !1;
29003
29002
  try {
29004
- let t = qO(e);
29003
+ let t = UO(e);
29005
29004
  if (t.display === "none" || t.visibility === "hidden") return !1;
29006
29005
  } catch {}
29007
29006
  return !0;
@@ -29013,123 +29012,7 @@ function $O() {
29013
29012
  type: e.type || e.tagName
29014
29013
  }));
29015
29014
  }
29016
- function ek(e) {
29017
- return String(e || "").toLowerCase().replace(/\u00a0/g, " ").replace(/\*/g, "").replace(/\s+/g, " ").trim();
29018
- }
29019
- function tk(e) {
29020
- let t = ek(e);
29021
- return t = t.replace(/\s+field\s*$/i, "").trim(), t;
29022
- }
29023
- function nk(e, t) {
29024
- let n = tk(t);
29025
- if (!n) return 0;
29026
- let r = (e.name || "").toLowerCase(), i = (e.id || "").toLowerCase();
29027
- if (r === "url" && /url|website|domain|site|audit/.test(n) || (i === "url-input" || i.endsWith("-url-input")) && /url|website|domain|site|audit/.test(n)) return 100;
29028
- let a = [
29029
- e.name,
29030
- e.id,
29031
- e.placeholder,
29032
- XO(e),
29033
- e.getAttribute("aria-label"),
29034
- e.getAttribute("title"),
29035
- e.getAttribute("data-testid"),
29036
- e.getAttribute("autocomplete")
29037
- ].filter(Boolean).map((e) => ek(e)), o = 0;
29038
- for (let e of a) {
29039
- if (!e) continue;
29040
- if (e.includes(n) || n.includes(e)) {
29041
- o = Math.max(o, 100);
29042
- continue;
29043
- }
29044
- let t = n.split(/\s+/).filter((e) => e.length > 1);
29045
- if (!t.length) continue;
29046
- let r = 0;
29047
- for (let n of t) e.includes(n) && (r += 1);
29048
- o = Math.max(o, r / t.length * 88);
29049
- }
29050
- return o;
29051
- }
29052
- var rk = 28;
29053
- function ik(e, t) {
29054
- let n = null, r = 0;
29055
- for (let i of e) {
29056
- let e = nk(i, t);
29057
- e > r && (r = e, n = i);
29058
- }
29059
- return !n || r < rk ? null : n;
29060
- }
29061
- function ak(e, t, n) {
29062
- let r = String(t || "").toLowerCase().trim(), i = String(n || "").trim();
29063
- if (!(/^https?:\/\//i.test(i) || /\.\w{2,}(\/|\s|$)/.test(i) || r.includes("url") || r.includes("website") || r.includes("domain") || r.includes("site"))) return null;
29064
- let a = null, o = 0;
29065
- for (let t of e) {
29066
- if (t.tagName !== "INPUT" && t.tagName !== "TEXTAREA") continue;
29067
- let e = (t.type || "").toLowerCase();
29068
- if ([
29069
- "hidden",
29070
- "submit",
29071
- "button",
29072
- "checkbox",
29073
- "radio"
29074
- ].includes(e)) continue;
29075
- let n = 0;
29076
- (e === "url" || e === "text" || e === "search") && (n += 45);
29077
- let r = [
29078
- t.name,
29079
- t.id,
29080
- t.placeholder,
29081
- XO(t),
29082
- t.getAttribute("aria-label"),
29083
- t.getAttribute("autocomplete")
29084
- ].filter(Boolean).join(" ").toLowerCase();
29085
- /(website|url|domain|site\s*url)/.test(r) && (n += 55), n > o && (o = n, a = t);
29086
- }
29087
- return !a || o < 42 ? null : a;
29088
- }
29089
- function ok(e) {
29090
- let t = String(e ?? "").trim();
29091
- return t ? /^https?:\/\//i.test(t) ? !0 : /\.\w{2,}(\/|\s|$)/.test(t) : !1;
29092
- }
29093
- function sk(e) {
29094
- let t = String(e ?? "").toLowerCase().trim();
29095
- return t ? !!(t === "url" || t === "website" || t === "website url" || t === "website_url" || t === "enter website url" || t.includes("website") || t.includes("domain") || /(enter\s+website|site\s*url|page\s*url)/.test(t)) : !1;
29096
- }
29097
- function ck(e) {
29098
- if (!e || e.tagName !== "INPUT" && e.tagName !== "TEXTAREA") return !1;
29099
- let t = (e.type || "").toLowerCase();
29100
- return ![
29101
- "hidden",
29102
- "submit",
29103
- "button",
29104
- "checkbox",
29105
- "radio",
29106
- "file"
29107
- ].includes(t);
29108
- }
29109
- function lk(e) {
29110
- if (!ck(e)) return !1;
29111
- let t = (e.name || "").toLowerCase(), n = (e.id || "").toLowerCase(), r = [
29112
- e.name,
29113
- e.id,
29114
- e.placeholder,
29115
- XO(e),
29116
- e.getAttribute("aria-label")
29117
- ].filter(Boolean).join(" ").toLowerCase();
29118
- return t === "url" || n === "url-input" || n.endsWith("-url-input") || /(website\s*url|enter\s+website|site\s*url)/.test(r) || /(website|domain)/.test(r) && /(url|site)/.test(r);
29119
- }
29120
- function uk(e, t, n) {
29121
- let r = String(t ?? ""), i = String(n ?? ""), a = pk(e, r) || ik(e, r) || ak(e, r, i);
29122
- if (!a) return [];
29123
- let o = new Set([a]);
29124
- if (ok(i) && sk(r)) for (let t of e) t !== a && lk(t) && o.add(t);
29125
- let s = Array.from(o);
29126
- return s.sort((e, t) => {
29127
- if (e === t) return 0;
29128
- let n = e.compareDocumentPosition(t);
29129
- return n & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : n & Node.DOCUMENT_POSITION_PRECEDING ? 1 : 0;
29130
- }), s;
29131
- }
29132
- function dk(e, t) {
29015
+ function XO(e, t) {
29133
29016
  try {
29134
29017
  if (!e?.getBoundingClientRect || !t?.getBoundingClientRect) return Infinity;
29135
29018
  let n = e.getBoundingClientRect(), r = t.getBoundingClientRect(), i = {
@@ -29144,42 +29027,7 @@ function dk(e, t) {
29144
29027
  return Infinity;
29145
29028
  }
29146
29029
  }
29147
- function fk(e) {
29148
- if (!e || typeof e != "string") return null;
29149
- let t = null;
29150
- return JO((n) => {
29151
- try {
29152
- let r = n.getElementById(e);
29153
- r && !Hn(r) && r.matches?.("input, select, textarea") && (t = r);
29154
- } catch {}
29155
- }), t;
29156
- }
29157
- function pk(e, t) {
29158
- let n = String(t ?? "").trim();
29159
- if (!n) return null;
29160
- let r = n.match(/^name:\s*([\w.-]+)$/i);
29161
- if (r) {
29162
- let t = r[1];
29163
- for (let n of e) if (n.name === t) return n;
29164
- }
29165
- let i = n.match(/^id:\s*([\w.-]+)$/i);
29166
- if (i) {
29167
- let e = fk(i[1]);
29168
- if (e) return e;
29169
- }
29170
- let a = n.startsWith("#") ? n.slice(1) : n;
29171
- if (/^[\w-]+$/.test(a)) {
29172
- let e = fk(a);
29173
- if (e) return e;
29174
- }
29175
- let o = n.toLowerCase().replace(/\s+/g, " ");
29176
- if (o === "url" || o === "website" || o === "website url" || o === "website_url" || o === "enter website url") for (let t of e) {
29177
- let e = (t.name || "").toLowerCase(), n = (t.id || "").toLowerCase();
29178
- if (e === "url" || n === "url-input" || n.endsWith("-url-input")) return t;
29179
- }
29180
- return null;
29181
- }
29182
- function mk(e, t) {
29030
+ function ZO(e, t) {
29183
29031
  let n = String(t || "").toLowerCase().trim();
29184
29032
  if (!n) return 0;
29185
29033
  let r = (e.innerText || e.textContent || "").replace(/\s+/g, " ").trim(), i = [
@@ -29197,14 +29045,14 @@ function mk(e, t) {
29197
29045
  for (let e of a) i.includes(e) && (o += 1);
29198
29046
  return o / a.length * 92;
29199
29047
  }
29200
- function hk(e, t) {
29048
+ function QO(e, t) {
29201
29049
  let n = [];
29202
- JO((e) => {
29050
+ WO((e) => {
29203
29051
  let t = Array.from(e.querySelectorAll("button, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"], a[href]"));
29204
29052
  n.push(...t.filter((e) => {
29205
29053
  if (Hn(e) || e.disabled) return !1;
29206
29054
  try {
29207
- let t = qO(e);
29055
+ let t = UO(e);
29208
29056
  if (t.display === "none" || t.visibility === "hidden" || t.opacity === "0") return !1;
29209
29057
  } catch {}
29210
29058
  return !0;
@@ -29212,7 +29060,7 @@ function hk(e, t) {
29212
29060
  });
29213
29061
  let r = 0, i = n.map((t) => ({
29214
29062
  el: t,
29215
- s: mk(t, e)
29063
+ s: ZO(t, e)
29216
29064
  }));
29217
29065
  for (let { s: e } of i) e > r && (r = e);
29218
29066
  if (r < 28) return null;
@@ -29222,14 +29070,14 @@ function hk(e, t) {
29222
29070
  if (o.length) {
29223
29071
  let e = a[0], t = Infinity;
29224
29072
  for (let n of a) for (let r of o) {
29225
- let i = dk(n, r);
29073
+ let i = XO(n, r);
29226
29074
  i < t && (t = i, e = n);
29227
29075
  }
29228
29076
  return e;
29229
29077
  }
29230
29078
  return a[0];
29231
29079
  }
29232
- function gk(e) {
29080
+ function $O(e) {
29233
29081
  if (e == null) return {};
29234
29082
  if (typeof e == "string") {
29235
29083
  let t = e.trim();
@@ -29242,151 +29090,12 @@ function gk(e) {
29242
29090
  }
29243
29091
  return e;
29244
29092
  }
29245
- function _k(e) {
29246
- let t = gk(e);
29247
- if (Array.isArray(t) && t.length > 0) {
29248
- let e = t[0];
29249
- if (e?.field_key != null || e?.fieldKey != null) return t.map((e) => ({
29250
- field_key: e.field_key ?? e.fieldKey,
29251
- value: e.value
29252
- }));
29253
- }
29254
- if (!t || typeof t != "object") return [];
29255
- let n = t.fields ?? t.Fields ?? t.field_list ?? t.fieldList ?? t.data?.fields;
29256
- if (typeof n == "string") try {
29257
- n = JSON.parse(n);
29258
- } catch {
29259
- n = null;
29260
- }
29261
- n && !Array.isArray(n) && typeof n == "object" && (n = Object.values(n)), (!n || n.length === 0) && (t.field_key != null || t.fieldKey != null) && t.value != null && (n = [{
29262
- field_key: t.field_key ?? t.fieldKey,
29263
- value: t.value
29264
- }]);
29265
- let r = t.website_url ?? t.websiteUrl ?? t.url ?? t.website ?? t.domain ?? t.site_url ?? t.siteUrl;
29266
- return (!n || n.length === 0) && r != null && String(r).trim() && (n = [{
29267
- field_key: t.field_key ?? t.fieldKey ?? "url",
29268
- value: String(r).trim()
29269
- }]), Array.isArray(n) ? n.map((e) => ({
29270
- field_key: e?.field_key ?? e?.fieldKey,
29271
- value: e?.value ?? e?.Value
29272
- })) : [];
29273
- }
29274
- function vk(e) {
29275
- if (!e || typeof e != "string") return [];
29276
- let t = e.trim();
29277
- if (!t || /\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i.test(t)) return [];
29278
- let n = t.match(/https?:\/\/[^\s<>"']+/i);
29279
- if (n) return [{
29280
- field_key: "url",
29281
- value: n[0].replace(/[.,;:)]+$/, "")
29282
- }];
29283
- let r = t.match(/\b(?:[\w-]+\.)+[a-z]{2,}\b/i);
29284
- if (r) {
29285
- let e = r[0].replace(/[.,;:)]+$/, "");
29286
- return /^https?:/i.test(e) || (e = `https://${e}`), [{
29287
- field_key: "url",
29288
- value: e
29289
- }];
29290
- }
29291
- return [];
29292
- }
29293
- function yk(e) {
29294
- if (!e || typeof e != "string") return [];
29295
- let t = e.trim();
29296
- if (!t) return [];
29297
- let n = [], r = /* @__PURE__ */ new Set(), i = /\b([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\b/i, a = (e, t) => {
29298
- let i = String(t ?? "").trim().replace(/^["']|["']$/g, "");
29299
- if (!i || i.length > 800) return;
29300
- let a = `${e}\0${i}`;
29301
- r.has(a) || (r.add(a), n.push({
29302
- field_key: e,
29303
- value: i
29304
- }));
29305
- }, o = t.match(/^\s*([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\s*$/i);
29306
- if (o) return a("Email Address", o[1]), n;
29307
- let s = t.match(/\b(?:please\s+)?(?:enter|type|put)\s+(.+?)\s+in(?:to)?\s+(?:the\s+)?(?:full\s*name|full\s*name\s*field|name\s*field)\b/i);
29308
- if (s && a("Full Name", s[1]), s = t.match(/\bfull\s*name,?\s*(?:please\s+)?(?:enter|type|put)\s+(.+?)(?:\.|$|!|\?)/i), s && a("Full Name", s[1]), s = t.match(/\bfull\s*name\s*(?:is|:|please\s+enter|-)\s*(.+?)(?:\.|$|(?=\s+(?:and|my\s+email|email|message))\b)/i), s && a("Full Name", s[1]), s = t.match(/\b(.+?)\s+for\s+(?:the\s+)?full\s*name\b/i), s) {
29309
- let e = s[1].trim();
29310
- e.length > 1 && e.length < 120 && !/@/.test(e) && a("Full Name", e);
29311
- }
29312
- if (s = t.match(/\b(?:email|e-mail)(?:\s*address)?\s*(?:is|:|please\s+use|enter|-)\s*([^\s@]+@[^\s@]+\.[^\s,]+)/i), s && a("Email Address", s[1]), s = t.match(/\b(?:enter|type|put)\s+([^\s@]+@[^\s@]+\.[^\s,]+)\s+in(?:to)?\s+(?:the\s+)?(?:email|e-mail)/i), s && a("Email Address", s[1]), s = t.match(/\b(?:message|comment)\s*(?:is|:|please\s+enter|-)\s*(.+)$/is), s) {
29313
- let e = s[1].trim();
29314
- e.length > 0 && a("Message", e);
29315
- }
29316
- if (!n.some((e) => /email/i.test(String(e.field_key)))) {
29317
- let e = t.match(i);
29318
- if (e) {
29319
- let r = t.replace(e[0], "").trim().replace(/^(please|it's|it is|use|is|my email is|e-?mail is)\s*/i, "").replace(/[.,;:!?]+$/, "").trim();
29320
- if (t.length <= 96 && r.length <= 36) return a("Email Address", e[1]), n;
29321
- }
29322
- }
29323
- if (n.length === 0) {
29324
- let e = t.split(/\s+/).filter(Boolean).length, n = /[.!?]/.test(t) || e >= 6 || t.length >= 24 && e >= 5 || t.length >= 42, r = /^[A-Z][a-z]+\s+[A-Z][a-z]+$/.test(t.trim());
29325
- n && t.length >= 16 && !i.test(t) && !r && a("Message", t);
29326
- }
29327
- return n;
29328
- }
29329
- function bk(e) {
29093
+ function ek(e) {
29330
29094
  if (!e || typeof e != "object") return null;
29331
29095
  let t = e.url ?? e.target_url ?? e.page_url ?? e.pageUrl ?? e.link ?? e.href ?? e.path;
29332
29096
  return t == null ? null : String(t).trim() || null;
29333
29097
  }
29334
- function xk(e, t, n) {
29335
- if (!n?.skipScroll) try {
29336
- e.scrollIntoView({
29337
- block: "center",
29338
- inline: "nearest"
29339
- });
29340
- } catch {
29341
- try {
29342
- e.scrollIntoView(!0);
29343
- } catch {}
29344
- }
29345
- try {
29346
- e.focus({ preventScroll: !0 });
29347
- } catch {
29348
- try {
29349
- e.focus();
29350
- } catch {}
29351
- }
29352
- let r = e.tagName, i = (e.type || "").toLowerCase();
29353
- if (r === "SELECT") return e.value = String(t), e.dispatchEvent(new Event("input", { bubbles: !0 })), e.dispatchEvent(new Event("change", { bubbles: !0 })), !0;
29354
- if (i === "checkbox" || i === "radio") return e.checked = [
29355
- "1",
29356
- "true",
29357
- "yes",
29358
- "on"
29359
- ].includes(String(t).toLowerCase().trim()), e.dispatchEvent(new Event("input", { bubbles: !0 })), e.dispatchEvent(new Event("change", { bubbles: !0 })), !0;
29360
- let a = String(t);
29361
- if (r === "INPUT" || r === "TEXTAREA") {
29362
- let t = e.ownerDocument?.defaultView || window, n = r === "TEXTAREA" ? t.HTMLTextAreaElement.prototype : t.HTMLInputElement.prototype, i = Object.getOwnPropertyDescriptor(n, "value");
29363
- i?.set ? i.set.call(e, a) : e.value = a;
29364
- } else e.value = a;
29365
- let o = {
29366
- bubbles: !0,
29367
- cancelable: !0,
29368
- composed: !0
29369
- };
29370
- try {
29371
- e.dispatchEvent(new InputEvent("input", {
29372
- ...o,
29373
- inputType: "insertText",
29374
- data: a
29375
- }));
29376
- } catch {
29377
- e.dispatchEvent(new Event("input", o));
29378
- }
29379
- e.dispatchEvent(new Event("change", o));
29380
- try {
29381
- queueMicrotask(() => {
29382
- try {
29383
- e.dispatchEvent(new Event("input", o)), e.dispatchEvent(new Event("change", o));
29384
- } catch {}
29385
- });
29386
- } catch {}
29387
- return !0;
29388
- }
29389
- function Sk() {
29098
+ function tk() {
29390
29099
  let e = {};
29391
29100
  document.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach((t) => {
29392
29101
  if (t.id) return;
@@ -29401,7 +29110,7 @@ function Sk() {
29401
29110
  e[r] = !0, t.id = r;
29402
29111
  });
29403
29112
  }
29404
- function Ck() {
29113
+ function nk() {
29405
29114
  let e = (e) => {
29406
29115
  let t = Array.from(e).filter((e) => !e.closest("#flowengage-root, .flowengage-shell, .flowengage-widget-root") && !e.closest("nav, footer, header, aside, .nav, .footer, .header, .sidebar")), n = [], r = 0;
29407
29116
  for (; r < t.length;) {
@@ -29419,9 +29128,11 @@ function Ck() {
29419
29128
  }
29420
29129
  return n;
29421
29130
  }, t = e((document.querySelector("main, [role='main']") || document.body).querySelectorAll("h1, h2, h3"));
29422
- return t.length || (t = e(document.body.querySelectorAll("h1, h2, h3"))), t.length || (t = e(document.body.querySelectorAll("h4, h5"))), [...new Set(t)].slice(0, 15);
29131
+ t.length || (t = e(document.body.querySelectorAll("h1, h2, h3"))), t.length || (t = e(document.body.querySelectorAll("h4, h5")));
29132
+ let n = [...new Set(t)], r = ((typeof document < "u" ? document.title : "") || "").replace(/\s*[-–—|·]\s*.+$/, "").trim().toLowerCase();
29133
+ return (r ? n.filter((e) => e.toLowerCase().trim() !== r) : n).slice(0, 15);
29423
29134
  }
29424
- function wk(e) {
29135
+ function rk(e) {
29425
29136
  if (!e || typeof document > "u") return "";
29426
29137
  let t = new Set([
29427
29138
  "script",
@@ -29492,11 +29203,11 @@ function wk(e) {
29492
29203
  return d.has(t) ? !1 : (d.add(t), !0);
29493
29204
  }).join("\n").replace(/\n{3,}/g, "\n\n").trim();
29494
29205
  }
29495
- function Tk(e) {
29206
+ function ik(e) {
29496
29207
  let t = e.siteId || null, n = (e.apiBaseUrl || "").replace(/\/$/, ""), r = typeof e.getLastUserVoiceText == "function" ? e.getLastUserVoiceText : null, i = [], a = {
29497
29208
  "fwh-navigate-mvp": async (n) => {
29498
29209
  $("fwh-navigate-mvp ▶ raw parameters:", n);
29499
- let i = gk(n), a = bk(i);
29210
+ let i = $O(n), a = ek(i);
29500
29211
  if ($("fwh-navigate-mvp · coerced:", {
29501
29212
  url: a,
29502
29213
  sectionText: i.section_text ?? i.sectionText ?? i.section,
@@ -29562,8 +29273,8 @@ function Tk(e) {
29562
29273
  typeof window < "u" && window.scrollTo(0, 0);
29563
29274
  } catch {}
29564
29275
  let s = [], c = Date.now() + 12e3;
29565
- for (; Date.now() < c && (await new Promise((e) => setTimeout(e, 300)), s = Ck(), !(s.length >= 1)););
29566
- Sk(), $("fwh-navigate-mvp → page headings collected:", s);
29276
+ for (; Date.now() < c && (await new Promise((e) => setTimeout(e, 300)), s = nk(), !(s.length >= 1)););
29277
+ tk(), $("fwh-navigate-mvp → page headings collected:", s);
29567
29278
  let l = s.length ? s.join(" | ") : "none", u = s.length ? "Use ONLY these exact heading strings for fwh-highlight-mvp — never invent or abbreviate." : "No headings collected yet — call fwh-get-current-page-mvp immediately (no speech) to get the live headings before speaking or highlighting.", d = "";
29568
29279
  try {
29569
29280
  if (s.length > 0) {
@@ -29571,7 +29282,7 @@ function Tk(e) {
29571
29282
  for (let n of e) {
29572
29283
  let e = xr(null, n);
29573
29284
  if (e) {
29574
- let r = wk(e).substring(0, 800);
29285
+ let r = rk(e).substring(0, 800);
29575
29286
  r && t.push(`[Section: ${n}] ${r}`);
29576
29287
  }
29577
29288
  }
@@ -29599,34 +29310,34 @@ function Tk(e) {
29599
29310
  },
29600
29311
  "fwh-highlight-mvp": async (e) => {
29601
29312
  $("fwh-highlight-mvp ▶", e);
29602
- let t = gk(e), n = t?.section_id || t?.sectionId, r = t?.section_text || t?.sectionText;
29313
+ let t = $O(e), n = t?.section_id || t?.sectionId, r = t?.section_text || t?.sectionText;
29603
29314
  if (typeof window < "u" && window.__fe_user_nav_during_speech) {
29604
29315
  let e = window.__fe_user_nav_during_speech, t = window.location.pathname;
29605
29316
  if (Date.now() - e.ts >= 3e4) window.__fe_user_nav_during_speech = null;
29606
29317
  else return $("flowengage_highlight ✖ blocked — user navigated during speech", e), `NAV_CHANGED: The visitor navigated from "${e.fromPageName}" to "${e.toPageName}" (current path: ${t}) while you were speaking. STOP the current walkthrough immediately. DO NOT call flowengage_highlight again. Say out loud: "I see you've navigated to the ${e.toPageName} page — do you want me to continue what I was explaining, or shall I guide you through this page?" Wait for the visitor's answer before doing anything else.`;
29607
29318
  }
29608
- Sk();
29319
+ tk();
29609
29320
  let i = ((e) => e && e.replace(/^\d+\.\s*/, "").replace(/^["']|["']$/g, "").trim())(r), a = xr(n || null, i || null);
29610
29321
  if (!a && i) {
29611
29322
  let e = Date.now() + 600;
29612
- for (; !a && Date.now() < e;) await new Promise((e) => setTimeout(e, 50)), Sk(), a = xr(null, i);
29323
+ for (; !a && Date.now() < e;) await new Promise((e) => setTimeout(e, 50)), tk(), a = xr(null, i);
29613
29324
  }
29614
29325
  if (!a) {
29615
29326
  $("fwh-highlight-mvp ✖ no element for:", i || n);
29616
- let e = Ck(), t = e.length ? `Page headings: ${e.map((e) => `"${e}"`).join(" | ")}. Use one of these EXACT strings for section_text — no numbers, no quotes around them.` : "No headings found — skip highlight and continue speaking.";
29327
+ let e = nk(), t = e.length ? `Page headings: ${e.map((e) => `"${e}"`).join(" | ")}. Use one of these EXACT strings for section_text — no numbers, no quotes around them.` : "No headings found — skip highlight and continue speaking.";
29617
29328
  return `HIGHLIGHT_NOT_FOUND: "${i || n}" on the current page. ${t}`;
29618
29329
  }
29619
29330
  return zn(a), $("fwh-highlight-mvp ✓", i || n), `OK_HIGHLIGHT: "${i || n}". WALKTHROUGH: continue immediately to the next section — do NOT pause between sections.`;
29620
29331
  },
29621
29332
  "fwh-read-content-mvp": async (e) => {
29622
29333
  $("fwh-read-content-mvp ▶", e);
29623
- let t = gk(e), n = t?.section_text || t?.sectionText || "";
29334
+ let t = $O(e), n = t?.section_text || t?.sectionText || "";
29624
29335
  try {
29625
29336
  let e = "";
29626
29337
  if (n) {
29627
29338
  let t = xr(null, n);
29628
29339
  if (!t) return `Could not find section "${n}" on the page.`;
29629
- e = wk(t);
29340
+ e = rk(t);
29630
29341
  } else {
29631
29342
  let t = (document.querySelector("main") || document.querySelector("article") || document.querySelector("[role=\"main\"]") || document.querySelector("#content") || document.querySelector(".content") || document.body).cloneNode(!0);
29632
29343
  t.querySelectorAll("nav, footer, header, aside, script, style, noscript, .nav, .footer, .header, .sidebar, #flowengage-root, .flowengage-shell, .flowengage-widget-root").forEach((e) => e.remove()), e = t.textContent.replace(/\s+/g, " ").trim();
@@ -29638,7 +29349,7 @@ function Tk(e) {
29638
29349
  },
29639
29350
  "fwh-page-content-mvp": async (e) => {
29640
29351
  $("fwh-page-content-mvp ▶", e);
29641
- let r = gk(e), i = r?.url || r?.page_url || "";
29352
+ let r = $O(e), i = r?.url || r?.page_url || "";
29642
29353
  if ($("fwh-page-content-mvp · url:", i, "siteId:", t, "apiBase:", n || "(empty)"), !i) return $("fwh-page-content-mvp ✖ missing url"), "Missing url parameter.";
29643
29354
  if (!t) return $("fwh-page-content-mvp ✖ no siteId"), "Site is not configured.";
29644
29355
  if (!n) return $("fwh-page-content-mvp ✖ no api base"), "API base URL is missing; cannot fetch page content.";
@@ -29670,7 +29381,7 @@ function Tk(e) {
29670
29381
  },
29671
29382
  "fwh-search-mvp": async (e) => {
29672
29383
  $("fwh-search-mvp ▶", e);
29673
- let r = gk(e).query;
29384
+ let r = $O(e).query;
29674
29385
  if (!r) return $("fwh-search-mvp ✖ missing query"), "Missing query parameter.";
29675
29386
  if (!t) return $("fwh-search-mvp ✖ no siteId"), "Search unavailable (no siteId configured).";
29676
29387
  if (!n) return $("fwh-search-mvp ✖ no api base"), "Search unavailable (no API base URL).";
@@ -29708,7 +29419,7 @@ function Tk(e) {
29708
29419
  "[class*='menu'] a",
29709
29420
  "[class*='header'] a"
29710
29421
  ];
29711
- if (JO((t) => {
29422
+ if (WO((t) => {
29712
29423
  for (let r of n) try {
29713
29424
  t.querySelectorAll(r).forEach((t) => {
29714
29425
  if (Hn(t)) return;
@@ -29716,7 +29427,7 @@ function Tk(e) {
29716
29427
  if (!r || !n || n === "#" || n.startsWith("javascript:")) return;
29717
29428
  try {
29718
29429
  let e = t.parentElement;
29719
- if (e && qO(e).display === "none" && !e.closest("nav, [role='navigation'], header, [class*='nav'], [class*='menu']")) return;
29430
+ if (e && UO(e).display === "none" && !e.closest("nav, [role='navigation'], header, [class*='nav'], [class*='menu']")) return;
29720
29431
  } catch {}
29721
29432
  let i = r.toLowerCase() + "|" + n;
29722
29433
  e.has(i) || e.set(i, {
@@ -29727,7 +29438,7 @@ function Tk(e) {
29727
29438
  } catch {}
29728
29439
  t.querySelectorAll("select").forEach((t) => {
29729
29440
  if (Hn(t)) return;
29730
- let n = XO(t);
29441
+ let n = KO(t);
29731
29442
  /nav|menu|page|section|go to/i.test(n || t.name || t.id || "") && Array.from(t.options).forEach((r) => {
29732
29443
  if (!r.value || r.disabled) return;
29733
29444
  let i = r.text.trim();
@@ -29748,7 +29459,7 @@ function Tk(e) {
29748
29459
  "fwh-end-session-mvp": async () => ($("fwh-end-session-mvp ▶"), typeof e.requestEndSession == "function" && e.requestEndSession(), "Voice session is ending."),
29749
29460
  "fwh-get-current-page-mvp": async () => {
29750
29461
  if ($("fwh-get-current-page-mvp ▶"), typeof window > "u") return "Cannot determine current page (no browser context).";
29751
- let e = window.location.href, t = window.location.pathname, n = document.title || "", r = Ck();
29462
+ let e = window.location.href, t = window.location.pathname, n = document.title || "", r = nk();
29752
29463
  if ($("fwh-get-current-page-mvp ✓", {
29753
29464
  url: e,
29754
29465
  path: t,
@@ -29758,7 +29469,7 @@ function Tk(e) {
29758
29469
  return `CURRENT_PAGE. URL: ${e} | Title: ${n} | Page sections (${r.length} total): ${i}. *** WALKTHROUGH RULES: (1) For fwh-highlight-mvp, pass the heading text EXACTLY as shown — no numbers, no extra punctuation, no paraphrasing. (2) TIMING IS CRITICAL: the tool fires AFTER the speech that comes before it. This means: put the SHORT TRANSITION (1-5 words) BEFORE the tool call, put the FULL DESCRIPTION AFTER the tool call. Pattern: "Transition phrase." + fwh-highlight-mvp("Heading") + "Full description (3-4 sentences)". NEVER describe a section before calling its highlight tool. (3) DO NOT call this tool again. If the visitor requested a walkthrough: START IT NOW — "Let me walk you through this." + fwh-highlight-mvp("${r[0] || "first heading"}") + "Description..." etc. Cover ALL ${r.length} sections without pausing. ***`;
29759
29470
  },
29760
29471
  "fwh-list-forms-mvp": async () => {
29761
- let e = QO(), t = $O();
29472
+ let e = JO(), t = YO();
29762
29473
  $("fwh-list-forms-mvp ✓", `${e.length} field(s)`, `${t.length} button(s)`);
29763
29474
  let n = e.map((e) => ({
29764
29475
  ...e,
@@ -29770,66 +29481,37 @@ function Tk(e) {
29770
29481
  hint: "field_key: use the label/placeholder/name shown above. CRITICAL: fields with inputCategory='dropdown_select' are SELECT elements — their field_key must match the SELECT's own label (e.g. 'Company Size'), NOT the option text (e.g. 'Small Business') and NOT a nearby text input label. Never fill a SELECT option value into a text input."
29771
29482
  });
29772
29483
  },
29773
- "fwh-fill-form-mvp": async (e) => {
29484
+ "fwh-fill-form-mvp": async () => "FORM_FILLING_DISABLED: Form filling is not available at this time. Tell the visitor what fields are present (use fwh-list-forms-mvp) and ask them to fill the form themselves.",
29485
+ "fwh-save-email-mvp": async (r) => {
29486
+ $("fwh-save-email-mvp ▶", r);
29487
+ let i = ($O(r)?.email || "").trim();
29488
+ if (!i || !i.includes("@")) return "INVALID_EMAIL: The email address is not valid. Ask the visitor to repeat it clearly, or tell them to type it in the field below.";
29489
+ if (!n) return "Cannot save email: API base URL not configured.";
29490
+ let a = e.chatId || null;
29491
+ if (!a) return "Cannot save email: no active chat session.";
29774
29492
  try {
29775
- $("fwh-fill-form-mvp raw:", e), PO();
29776
- let t = _k(e);
29777
- if (!t.length && r) {
29778
- let e = r(), n = vk(e);
29779
- n.length ? $("fwh-fill-form-mvp · inferred URL from last user utterance (model omitted usable fields):", n) : (n = yk(e), n.length && $("fwh-fill-form-mvp · inferred contact fields from last user utterance (empty tool params):", n)), n.length && (t = n);
29780
- }
29781
- if ($("fwh-fill-form-mvp · normalized fields:", t), !t.length) return "No fields provided. Call fwh-list-forms-mvp for field_key strings, then fwh-fill-form-mvp with { \"fields\": [ { \"field_key\": \"<label or placeholder from list>\", \"value\": \"<user value>\" } ] }. Never use empty {}. Pass the value the user just said (email, message, name, URL) in fields.";
29782
- let n = [];
29783
- for (let e of t) {
29784
- let t = e?.field_key, r = e?.value;
29785
- if (t == null || r == null) continue;
29786
- DO(`Filling ${String(t)}...`, { spinner: !0 });
29787
- let a = ZO(), o = (() => {
29788
- let e = ek(r);
29789
- ek(String(t));
29790
- let n = null, i = 0;
29791
- for (let r of a) {
29792
- if (r.tagName !== "SELECT" || !Array.from(r.options).find((t) => ek(t.text) === e || ek(t.value) === e)) continue;
29793
- let a = nk(r, String(t));
29794
- a >= i && (i = a, n = r);
29795
- }
29796
- return n && i >= 0 ? n : null;
29797
- })();
29798
- if (o) {
29799
- $("fwh-fill-form-mvp · SELECT pre-pass matched dropdown:", o.name || o.id || o.getAttribute("aria-label")), FO(o), await VO(o), xk(o, r), IO(o), await KO(120), i = [o], n.push(String(t));
29800
- continue;
29801
- }
29802
- let s = uk(a, String(t), r);
29803
- if (s.length) {
29804
- for (let [e, t] of s.entries()) FO(t), await VO(t), xk(t, r, { skipScroll: e > 0 }), IO(t), await KO(120);
29805
- i = s, n.push(String(t));
29806
- continue;
29807
- }
29808
- let c = pk(a, String(t));
29809
- c ||= ik(a, String(t)), c ||= ak(a, String(t), r), c && (FO(c), await VO(c), xk(c, r), IO(c), await KO(120), i = [c], n.push(String(t)));
29810
- }
29811
- if (!n.length) return $("fwh-fill-form-mvp ✖ no matches"), "Could not match any fields. Call fwh-list-forms-mvp and use field_key values that match placeholder, label, name, or id (e.g. Enter Website URL). Ensure the form is on the page, not the chat panel.";
29812
- let a = `OK_FILLED: ${n.join(", ")}`;
29813
- return $("fwh-fill-form-mvp ✓", a), DO("Form filled", {
29814
- spinner: !1,
29815
- icon: "✅",
29816
- duration: 1100
29817
- }), a;
29493
+ let e = await (await fetch(`${n}/api/voice/save-visitor-email`, {
29494
+ method: "POST",
29495
+ headers: { "Content-Type": "application/json" },
29496
+ body: JSON.stringify({
29497
+ chatId: a,
29498
+ email: i,
29499
+ siteId: t
29500
+ })
29501
+ })).json();
29502
+ if (!e.success) return `Failed to save email: ${e.error || "unknown error"}`;
29503
+ try {
29504
+ typeof window < "u" && window.dispatchEvent(new CustomEvent("fe:voice-email-saved", { detail: { email: i } }));
29505
+ } catch {}
29506
+ return $("fwh-save-email-mvp ✓", i), `EMAIL_SAVED: ${i}. Now answer the visitor's original question.`;
29818
29507
  } catch (e) {
29819
- let t = `FORM_ERROR: ${e?.message || String(e)}`;
29820
- return $("fwh-fill-form-mvp ✖", t), DO("Failed to fill form", {
29821
- spinner: !1,
29822
- icon: "⚠️",
29823
- duration: 1800
29824
- }), t;
29825
- } finally {
29826
- HO(), PO(), OO(700);
29508
+ return $("fwh-save-email-mvp ✖", e.message), `Failed to save email: ${e.message}`;
29827
29509
  }
29828
29510
  },
29829
29511
  "fwh-click-button-mvp": async (e) => {
29830
- let t = gk(e), n = (t.button_text ?? t.buttonText ?? t.text ?? "").trim();
29512
+ let t = $O(e), n = (t.button_text ?? t.buttonText ?? t.text ?? "").trim();
29831
29513
  if ($("fwh-click-button-mvp ▶", n), !n) return "Missing button_text: pass the visible label, e.g. Conduct Audit.";
29832
- let r = hk(n, i);
29514
+ let r = QO(n, i);
29833
29515
  if (!r) return $("fwh-click-button-mvp ✖ no match"), `Could not find a button matching "${n}". Call fwh-list-forms-mvp to see button texts.`;
29834
29516
  try {
29835
29517
  DO(`Clicking ${n}...`, { spinner: !0 });
@@ -29841,7 +29523,7 @@ function Tk(e) {
29841
29523
  } catch {
29842
29524
  r.scrollIntoView(!0);
29843
29525
  }
29844
- await VO(r), r.focus?.(), await UO(r), WO(r), r.click();
29526
+ await RO(r), r.focus?.(), await BO(r), VO(r), r.click();
29845
29527
  let e = (r.textContent || r.value || r.getAttribute("aria-label") || "").trim().slice(0, 80) || "button", t = `OK_CLICK ${e}`;
29846
29528
  return $("fwh-click-button-mvp ✓", t), DO(`Clicked ${e}`, {
29847
29529
  spinner: !1,
@@ -29856,7 +29538,7 @@ function Tk(e) {
29856
29538
  duration: 1800
29857
29539
  }), t;
29858
29540
  } finally {
29859
- HO(), OO(700);
29541
+ zO(), OO(700);
29860
29542
  }
29861
29543
  }
29862
29544
  };
@@ -29872,7 +29554,7 @@ function Tk(e) {
29872
29554
  }
29873
29555
  //#endregion
29874
29556
  //#region src/utils/wrapVoiceToolsForLogging.js
29875
- function Ek(e) {
29557
+ function ak(e) {
29876
29558
  return !e || typeof e != "object" ? e : Object.fromEntries(Object.entries(e).map(([e, t]) => [e, async (n) => {
29877
29559
  let r = In();
29878
29560
  r ? console.log("[FlowEngage:voice-tool] ▶", e, n) : console.info(`[FlowEngage] voice tool » ${e}`);
@@ -29889,7 +29571,7 @@ function Ek(e) {
29889
29571
  }
29890
29572
  //#endregion
29891
29573
  //#region src/components/FlowEngageWidget.jsx
29892
- var Dk = {
29574
+ var ok = {
29893
29575
  blue: "#135bd8",
29894
29576
  red: "#ef334b",
29895
29577
  yellow: "#ffbd2e",
@@ -29897,7 +29579,7 @@ var Dk = {
29897
29579
  highlight: "rgba(255,255,255,0.9)",
29898
29580
  green: "#10b981"
29899
29581
  };
29900
- function Ok(e) {
29582
+ function sk(e) {
29901
29583
  if (!Array.isArray(e) || e.length < 2) return "linear-gradient(145deg, #dce8f022 0%, #e8dff522 45%, #f5e0e022 100%), #f7f8fa";
29902
29584
  let [t, n, r] = e;
29903
29585
  return e.length >= 3 && r ? [
@@ -29911,12 +29593,12 @@ function Ok(e) {
29911
29593
  "#f7f8fa"
29912
29594
  ].join(", ");
29913
29595
  }
29914
- function kk(e) {
29596
+ function ck(e) {
29915
29597
  if (!e || typeof e != "string") return "#1a1a1a";
29916
29598
  let t = e.replace("#", ""), n = t.length === 3 ? t.split("").map((e) => e + e).join("") : t, r = parseInt(n.slice(0, 2), 16) / 255, i = parseInt(n.slice(2, 4), 16) / 255, a = parseInt(n.slice(4, 6), 16) / 255, o = (e) => e <= .04045 ? e / 12.92 : ((e + .055) / 1.055) ** 2.4;
29917
29599
  return .2126 * o(r) + .7152 * o(i) + .0722 * o(a) > .179 ? "#1a1a1a" : "#ffffff";
29918
29600
  }
29919
- function Ak(t) {
29601
+ function lk(t) {
29920
29602
  let [n, r] = e.useState(null), i = typeof t == "string" ? t.trim() : "";
29921
29603
  return e.useEffect(() => {
29922
29604
  if (!i) {
@@ -29934,8 +29616,8 @@ function Ak(t) {
29934
29616
  };
29935
29617
  }, [i]), n;
29936
29618
  }
29937
- function jk({ logo: t, style: n }) {
29938
- let r = Ak(typeof t == "string" ? t : null);
29619
+ function uk({ logo: t, style: n }) {
29620
+ let r = lk(typeof t == "string" ? t : null);
29939
29621
  if (!t) return null;
29940
29622
  if (typeof t == "string") return r ? /* @__PURE__ */ g("img", {
29941
29623
  src: r,
@@ -29960,7 +29642,7 @@ function jk({ logo: t, style: n }) {
29960
29642
  children: i
29961
29643
  }) : null;
29962
29644
  }
29963
- function Mk({ title: e }) {
29645
+ function dk({ title: e }) {
29964
29646
  return /* @__PURE__ */ g("div", {
29965
29647
  style: {
29966
29648
  width: "100%",
@@ -29978,18 +29660,18 @@ function Mk({ title: e }) {
29978
29660
  children: String(e || "FE").split(/\s+/).filter(Boolean).slice(0, 2).map((e) => e[0]?.toUpperCase() || "").join("") || "FE"
29979
29661
  });
29980
29662
  }
29981
- function Nk(e, t) {
29663
+ function fk(e, t) {
29982
29664
  let n = (t || "").trim();
29983
29665
  return n ? !!(/\b(let'?s|let us)\s+(end|stop|finish|wrap up|close)\s+(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n) || /\bend\s+(this\s+)?(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n) || /\b(hang\s+up|disconnect)\b/i.test(n) || e === "bot" && (/\b(that'?s all|we'?re done)\b/i.test(n) || /\b(goodbye|bye)\b/i.test(n) || /\b(I'?ll|I will|Let me|I can|I'?m going to)\s+(end|close)\s+(the\s+)?(voice\s+)?(session|call)\b/i.test(n) || /\b(ending|closing)\s+(the\s+)?(voice\s+)?session\b|\bvoice\s+session\s+(is\s+)?(now\s+)?(ended|over|closing)\b/i.test(n) || /\b(session|call)\s+(is\s+)?(now\s+)?(ended|over)\b/i.test(n) || /\bwe\s+can\s+end\s+(the\s+)?(session|call)?\s*(here|now)\b/i.test(n) || /\b(wrapping\s+up|signing\s+off)\b/i.test(n))) : !1;
29984
29666
  }
29985
- function Pk({ orbColors: e, ...t }) {
29667
+ function pk({ orbColors: e, ...t }) {
29986
29668
  return /* @__PURE__ */ g(pO, {
29987
29669
  colors: e,
29988
29670
  ...t
29989
29671
  });
29990
29672
  }
29991
- function Fk({ copy: e, orbColors: t, primaryColor: n, onYes: r, onLater: i, isMobile: a, isClosing: o }) {
29992
- let s = n || Dk.green, c = kk(s), l = a ? 72 : 94, u = /* @__PURE__ */ _("div", {
29673
+ function mk({ copy: e, orbColors: t, primaryColor: n, onYes: r, onLater: i, isMobile: a, isClosing: o }) {
29674
+ let s = n || ok.green, c = ck(s), l = a ? 72 : 94, u = /* @__PURE__ */ _("div", {
29993
29675
  style: {
29994
29676
  display: "flex",
29995
29677
  alignItems: a ? "flex-end" : "center",
@@ -30115,7 +29797,7 @@ function Fk({ copy: e, orbColors: t, primaryColor: n, onYes: r, onLater: i, isMo
30115
29797
  delay: 0
30116
29798
  },
30117
29799
  style: { flexShrink: 0 },
30118
- children: /* @__PURE__ */ g(Pk, {
29800
+ children: /* @__PURE__ */ g(pk, {
30119
29801
  size: l,
30120
29802
  orbColors: t
30121
29803
  })
@@ -30147,8 +29829,8 @@ function Fk({ copy: e, orbColors: t, primaryColor: n, onYes: r, onLater: i, isMo
30147
29829
  children: u
30148
29830
  })] });
30149
29831
  }
30150
- function Ik({ copy: e, orbColors: t, primaryColor: n, onVoice: r, onText: i, onClose: a, isMobile: o, isClosing: s }) {
30151
- let c = n || Dk.green, l = kk(c);
29832
+ function hk({ copy: e, orbColors: t, primaryColor: n, onVoice: r, onText: i, onClose: a, isMobile: o, isClosing: s }) {
29833
+ let c = n || ok.green, l = ck(c);
30152
29834
  return /* @__PURE__ */ _(Pm.div, {
30153
29835
  initial: {
30154
29836
  scale: 50 / 350,
@@ -30219,7 +29901,7 @@ function Ik({ copy: e, orbColors: t, primaryColor: n, onVoice: r, onText: i, onC
30219
29901
  children: /* @__PURE__ */ g("polyline", { points: "6 9 12 15 18 9" })
30220
29902
  })
30221
29903
  }),
30222
- /* @__PURE__ */ g(Pk, {
29904
+ /* @__PURE__ */ g(pk, {
30223
29905
  size: 72,
30224
29906
  orbColors: t
30225
29907
  }),
@@ -30288,17 +29970,21 @@ function Ik({ copy: e, orbColors: t, primaryColor: n, onVoice: r, onText: i, onC
30288
29970
  ]
30289
29971
  });
30290
29972
  }
30291
- function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i, apiBaseUrl: a, chatId: s, historyRef: l, onMessageSync: u, voiceEndCounter: d, websiteName: f }) {
29973
+ function gk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i, apiBaseUrl: a, chatId: s, historyRef: l, onMessageSync: u, voiceEndCounter: d, websiteName: f, visitorEmail: h }) {
30292
29974
  c(() => (console.log("[FlowEngage:VoiceDebug] 🔵 VoiceMode MOUNTED"), () => console.log("[FlowEngage:VoiceDebug] 🔴 VoiceMode UNMOUNTED")), []);
30293
- let [h, v] = m("idle"), [y, b] = m(!1), [x, S] = m(!1), C = p(null), w = p(""), T = p(async () => {}), ee = p(!1), te = p(!1), ne = p(!1), re = p(!1), E = p("minimized"), ie = p(null), ae = p(null), oe = p(null), D = p(0), se = p(!1), ce = p("idle"), le = p(!1), ue = p(!1), de = p(null), fe = p(null), pe = p(!1), me = o((e = "minimized") => {
29975
+ let [v, y] = m("idle"), [b, x] = m(!1), [S, C] = m(!1), [w, T] = m(!1), [ee, te] = m(""), [ne, re] = m(""), E = p(null), ie = p(""), ae = p(async () => {}), oe = p(!1), D = p(!1), se = p(!1), ce = p(!1), le = p("minimized"), ue = p(null), de = p(null), fe = p(null), pe = p(0), me = p(!1), he = p("idle"), ge = p(h);
29976
+ c(() => {
29977
+ ge.current = h;
29978
+ }, [h]);
29979
+ let _e = p(!1), ve = p(null), ye = p(!1), be = p(!1), xe = p(null), Se = p(null), Ce = p(!1), we = o((e = "minimized") => {
30294
29980
  console.warn("[FlowEngage:VoiceDebug] 🛑 requestSessionShutdown called", {
30295
29981
  destination: e,
30296
29982
  stack: (/* @__PURE__ */ Error()).stack?.split("\n").slice(1, 4).join(" | ")
30297
- }), E.current = e, re.current = !0, queueMicrotask(() => {
30298
- ee.current || (ee.current = !0, T.current?.());
29983
+ }), le.current = e, ce.current = !0, queueMicrotask(() => {
29984
+ oe.current || (oe.current = !0, ae.current?.());
30299
29985
  });
30300
- }, [l]), he = o(async (e) => {
30301
- re.current = !0;
29986
+ }, [l]), Te = o(async (e) => {
29987
+ ce.current = !0;
30302
29988
  try {
30303
29989
  Bn();
30304
29990
  } catch {}
@@ -30306,9 +29992,9 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30306
29992
  Ve(i);
30307
29993
  } catch {}
30308
29994
  try {
30309
- await C.current?.endSession?.();
29995
+ await E.current?.endSession?.();
30310
29996
  } catch {}
30311
- let t = ie.current, n = ae.current;
29997
+ let t = ue.current, n = de.current;
30312
29998
  if (t && s && a) {
30313
29999
  let e = n ? Math.round((Date.now() - n) / 1e3) : 0;
30314
30000
  fetch(`${a}/api/voice/save-chat-recording`, {
@@ -30322,7 +30008,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30322
30008
  })
30323
30009
  }).catch((e) => console.warn("[FlowEngage] save-chat-recording failed:", e.message));
30324
30010
  }
30325
- if (ie.current = null, ae.current = null, C.current = null, v("idle"), b(!1), ee.current = !1, Ir(), i) try {
30011
+ if (ue.current = null, de.current = null, E.current = null, y("idle"), x(!1), T(!1), ve.current &&= (clearTimeout(ve.current), null), oe.current = !1, Ir(), i) try {
30326
30012
  je(i);
30327
30013
  } catch {}
30328
30014
  typeof u == "function" && await u(l.current), e?.();
@@ -30333,26 +30019,26 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30333
30019
  s,
30334
30020
  a
30335
30021
  ]);
30336
- return T.current = () => he(E.current === "chat" ? t : n), c(() => {
30337
- te.current = y;
30338
- }, [y]), c(() => {
30339
- d && me("chat");
30022
+ ae.current = () => Te(le.current === "chat" ? t : n), c(() => {
30023
+ D.current = b;
30024
+ }, [b]), c(() => {
30025
+ d && we("chat");
30340
30026
  }, [d]), c(() => {
30341
30027
  let e = !1, o = null, c = null, d = null;
30342
30028
  return (async () => {
30343
30029
  if (!r) {
30344
- v("error");
30030
+ y("error");
30345
30031
  return;
30346
30032
  }
30347
30033
  try {
30348
30034
  if ((await navigator.mediaDevices.getUserMedia({ audio: !0 })).getTracks().forEach((e) => e.stop()), e) return;
30349
- l.current = [], w.current = "", ee.current = !1, ne.current = !1, re.current = !1, E.current = "minimized", Fr({ onBeforeNavigate: () => {
30035
+ l.current = [], ie.current = "", oe.current = !1, se.current = !1, ce.current = !1, le.current = "minimized", Fr({ onBeforeNavigate: () => {
30350
30036
  if (i && l.current.length > 0) try {
30351
30037
  let e = SO(l.current);
30352
30038
  e && O(i, e);
30353
30039
  } catch {}
30354
30040
  if (!or()) {
30355
- let e = ie.current, t = ae.current;
30041
+ let e = ue.current, t = de.current;
30356
30042
  if (e && s && a) try {
30357
30043
  let n = t ? Math.round((Date.now() - t) / 1e3) : 0, r = JSON.stringify({
30358
30044
  chatId: s,
@@ -30365,25 +30051,26 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30365
30051
  headers: { "Content-Type": "application/json" },
30366
30052
  body: r,
30367
30053
  keepalive: !0
30368
- }).catch(() => {}), ie.current = null, ae.current = null;
30054
+ }).catch(() => {}), ue.current = null, de.current = null;
30369
30055
  } catch {}
30370
30056
  }
30371
30057
  Ne();
30372
30058
  } });
30373
- let t = Ek(Tk({
30059
+ let t = ak(ik({
30374
30060
  siteId: i || null,
30375
30061
  apiBaseUrl: a || null,
30376
- getLastUserVoiceText: () => w.current,
30062
+ chatId: s || null,
30063
+ getLastUserVoiceText: () => ie.current,
30377
30064
  requestEndSession: () => {
30378
- se.current = !0;
30065
+ me.current = !0;
30379
30066
  }
30380
- })), n = i ? Ae(i) : null, u = !!n?.transcript, p = i ? Ve(i) : null, m = !!p, h = typeof window < "u" ? window.location.pathname : "/", g = typeof document < "u" ? document.title : "", _ = h.replace(/^\/[a-z]{2}(?:-[a-z]{2})?(?=\/|$)/i, "") || "/", y = _ === "/" || _ === "", x = null;
30067
+ })), n = i ? Ae(i) : null, u = !!n?.transcript, p = i ? Ve(i) : null, m = !!p, h = typeof window < "u" ? window.location.pathname : "/", g = typeof document < "u" ? document.title : "", _ = h.replace(/^\/[a-z]{2}(?:-[a-z]{2})?(?=\/|$)/i, "") || "/", v = _ === "/" || _ === "", b = null;
30381
30068
  try {
30382
30069
  let e = await fetch(`${a}/api/voice/signed-url?siteId=${encodeURIComponent(i || "")}`, {
30383
30070
  method: "GET",
30384
30071
  headers: { "Content-Type": "application/json" }
30385
30072
  });
30386
- if (e.ok) x = (await e.json()).signedUrl || null, x && console.log("[FlowEngage] ✅ Using signed ElevenLabs URL");
30073
+ if (e.ok) b = (await e.json()).signedUrl || null, b && console.log("[FlowEngage] ✅ Using signed ElevenLabs URL");
30387
30074
  else if (e.status === 429) {
30388
30075
  let t = await e.json().catch(() => ({}));
30389
30076
  throw Error(t.message || "Too many voice sessions started. Please wait a minute before trying again.");
@@ -30396,51 +30083,51 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30396
30083
  clientTools: t,
30397
30084
  connectionType: "websocket",
30398
30085
  minSpeechDurationMs: 50,
30399
- ...x ? { signedUrl: x } : { agentId: r }
30400
- }, T = (h.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()), oe = "";
30401
- g && g.includes("|") && (oe = g.split("|").map((e) => e.trim()).filter(Boolean).reduce((e, t) => e.length <= t.length ? e : t));
30402
- let he = oe || T || "this page";
30403
- if (x) if (m) {
30404
- let e = p?.pageName || he;
30086
+ ...b ? { signedUrl: b } : { agentId: r }
30087
+ }, C = (h.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()), w = "";
30088
+ g && g.includes("|") && (w = g.split("|").map((e) => e.trim()).filter(Boolean).reduce((e, t) => e.length <= t.length ? e : t));
30089
+ let ee = w || C || "this page";
30090
+ if (b) if (m) {
30091
+ let e = p?.pageName || ee;
30405
30092
  S.overrides = { agent: { firstMessage: `I have navigated you on ${e} page. Do you want to know about any specific section or want a complete overview?` } }, console.log(`[FlowEngage] 🔄 Agent-nav resume: firstMessage set for "${e}" (${h})`);
30406
30093
  } else if (u) S.overrides = { agent: { firstMessage: "I'm still here. Go ahead!" } };
30407
30094
  else {
30408
30095
  let e = f || "";
30409
- S.overrides = { agent: { firstMessage: y ? e ? `Hi, welcome to ${e}!` : "Hi, welcome!" : `Welcome to the ${he} page!` } }, y || console.log(`[FlowEngage] 🏠 Page-context override: "${he}" for ${h}`);
30096
+ S.overrides = { agent: { firstMessage: v ? e ? `Hi, welcome to ${e}!` : "Hi, welcome!" : `Welcome to the ${ee} page!` } }, v || console.log(`[FlowEngage] 🏠 Page-context override: "${ee}" for ${h}`);
30410
30097
  }
30411
30098
  else u && (S.overrides = { agent: { firstMessage: "" } });
30412
- let ge = !1, _e = m ? `NAVIGATION COMPLETE — The exact phrase "I have navigated you on [page] page. Do you want to know about any specific section or want a complete overview?" has already been spoken as your firstMessage. DO NOT repeat it. PRIOR CONVERSATION CONTEXT:\n${n?.transcript ? `Prior transcript:\n${n.transcript}\n` : "(no prior transcript)"}\nNow STOP — wait silently for the visitor's reply. Do NOT speak, do NOT call any tool until the visitor responds. When they reply: if they name a specific section → call fwh-get-current-page-mvp then answer immediately; if they say "overview" or anything non-specific → call fwh-get-current-page-mvp (zero speech) then do a full highlighted walkthrough.` : null, ve = !1, ye = !m && !u ? "Your greeting has been spoken. Wait for the visitor to ask a question or tell you what they need. Do NOT auto-start a walkthrough or highlight any sections — let the visitor lead." : null, be = await ED.startSession({
30099
+ let te = !1, ne = m ? `NAVIGATION COMPLETE — The exact phrase "I have navigated you on [page] page. Do you want to know about any specific section or want a complete overview?" has already been spoken as your firstMessage. DO NOT repeat it. PRIOR CONVERSATION CONTEXT:\n${n?.transcript ? `Prior transcript:\n${n.transcript}\n` : "(no prior transcript)"}\nNow STOP — wait silently for the visitor's reply. Do NOT speak, do NOT call any tool until the visitor responds. When they reply: if they name a specific section → call fwh-get-current-page-mvp then answer immediately; if they say "overview" or anything non-specific → call fwh-get-current-page-mvp (zero speech) then do a full highlighted walkthrough.` : null, re = !1, ae = !m && !u ? "Your greeting has been spoken. Wait for the visitor to ask a question or tell you what they need. Do NOT auto-start a walkthrough or highlight any sections — let the visitor lead." : null, fe = await ED.startSession({
30413
30100
  ...S,
30414
30101
  onConnect: ({ conversationId: e }) => {
30415
- ie.current = e, ae.current = Date.now(), console.log("[FlowEngage] 🎙️ AI chat session connected:", e);
30102
+ ue.current = e, de.current = Date.now(), console.log("[FlowEngage] 🎙️ AI chat session connected:", e);
30416
30103
  },
30417
30104
  onUnhandledClientToolCall: (e) => console.error("[FlowEngage] Unhandled tool:", e?.tool_name),
30418
30105
  onModeChange: ({ mode: t }) => {
30419
30106
  if (!e) {
30420
30107
  if (t === "speaking") {
30421
- fe.current &&= (clearTimeout(fe.current), null), v("speaking"), ce.current = "speaking", le.current = !0, pe.current = !1, de.current &&= (clearTimeout(de.current), null);
30108
+ Se.current &&= (clearTimeout(Se.current), null), y("speaking"), he.current = "speaking", ye.current = !0, Ce.current = !1, xe.current &&= (clearTimeout(xe.current), null);
30422
30109
  return;
30423
30110
  }
30424
- if (ce.current = "listening", se.current) {
30425
- se.current = !1, me();
30111
+ if (he.current = "listening", me.current) {
30112
+ me.current = !1, we();
30426
30113
  return;
30427
30114
  }
30428
- if (_e && !ge) {
30429
- ge = !0;
30115
+ if (ne && !te) {
30116
+ te = !0;
30430
30117
  try {
30431
- C.current?.sendContextualUpdate?.(_e);
30118
+ E.current?.sendContextualUpdate?.(ne);
30432
30119
  } catch {}
30433
30120
  }
30434
- if (ye && !ve) {
30435
- ve = !0;
30121
+ if (ae && !re) {
30122
+ re = !0;
30436
30123
  try {
30437
- C.current?.sendContextualUpdate?.(ye);
30124
+ E.current?.sendContextualUpdate?.(ae);
30438
30125
  } catch {}
30439
30126
  }
30440
- fe.current && clearTimeout(fe.current), fe.current = setTimeout(() => {
30441
- e || ce.current !== "speaking" && (pe.current || (fe.current = null, ce.current = "listening", v("listening"), le.current && ue.current && !te.current && (de.current && clearTimeout(de.current), de.current = setTimeout(() => {
30442
- if (!e && ce.current === "listening" && !te.current) try {
30443
- C.current?.sendContextualUpdate?.("The visitor has been silent for a while. Ask one short, natural question to re-engage — for example: 'Is there anything specific you'd like to know more about?' or 'What else can I help you with today?' Keep it to one sentence.");
30127
+ Se.current && clearTimeout(Se.current), Se.current = setTimeout(() => {
30128
+ e || he.current !== "speaking" && (Ce.current || (Se.current = null, he.current = "listening", y("listening"), ye.current && be.current && !D.current && (xe.current && clearTimeout(xe.current), xe.current = setTimeout(() => {
30129
+ if (!e && he.current === "listening" && !D.current) try {
30130
+ E.current?.sendContextualUpdate?.("The visitor has been silent for a while. Ask one short, natural question to re-engage — for example: 'Is there anything specific you'd like to know more about?' or 'What else can I help you with today?' Keep it to one sentence.");
30444
30131
  } catch {}
30445
30132
  }, 15e3))));
30446
30133
  }, 1200);
@@ -30451,10 +30138,22 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30451
30138
  let n = t.role === "user" ? "user" : "bot", r = t.message || t.text || t.content || "";
30452
30139
  if (r) {
30453
30140
  if (n === "user") {
30454
- w.current = r, pe.current = !0, ue.current = !0, fe.current &&= (clearTimeout(fe.current), null), de.current &&= (clearTimeout(de.current), null);
30141
+ ie.current = r, Ce.current = !0, be.current = !0, Se.current &&= (clearTimeout(Se.current), null), xe.current &&= (clearTimeout(xe.current), null);
30455
30142
  try {
30456
30143
  Bn();
30457
30144
  } catch {}
30145
+ if (!ge.current && !_e.current) {
30146
+ _e.current = !0;
30147
+ try {
30148
+ E.current?.sendContextualUpdate?.("COLLECT_EMAIL: Before answering the visitor's question, you MUST first ask for their email address. Say: 'Before I answer, could I get your email address? You can also type it in the field below.' Do NOT answer their question yet — wait for the email first.");
30149
+ } catch {}
30150
+ T(!0), ve.current && clearTimeout(ve.current), ve.current = setTimeout(() => {
30151
+ ve.current = null;
30152
+ try {
30153
+ E.current?.sendContextualUpdate?.("The visitor has not provided their email for 1 minute and appears to have left. Say exactly: 'I feel like you are not active, so I'm ending this session. You can connect with me anytime.' Then immediately call the fwh-end-session-mvp tool to end the voice session.");
30154
+ } catch {}
30155
+ }, 6e4);
30156
+ }
30458
30157
  }
30459
30158
  if (l.current = [...l.current, {
30460
30159
  sender: n,
@@ -30464,51 +30163,51 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30464
30163
  let e = SO(l.current);
30465
30164
  e && O(i, e);
30466
30165
  } catch {}
30467
- if (Nk(n, r)) {
30468
- se.current = !0;
30166
+ if (fk(n, r)) {
30167
+ me.current = !0;
30469
30168
  return;
30470
30169
  }
30471
- if (te.current && n === "bot" && /are you still there|still there\??|hello\?|anyone there|checking in|you there|are you available|is anyone|did you step away/i.test(r)) if (D.current += 1, D.current === 2) try {
30472
- C.current?.sendContextualUpdate?.("IMPORTANT: The visitor is muted and has not responded to your last 2 checks. Make exactly ONE more check. If there is still no response, say: 'I feel like you are not active, so I'm ending this session. You can connect with me anytime.' then immediately call the fwh-end-session-mvp tool to end the voice session. Do NOT ask again after that.");
30170
+ if (D.current && n === "bot" && /are you still there|still there\??|hello\?|anyone there|checking in|you there|are you available|is anyone|did you step away/i.test(r)) if (pe.current += 1, pe.current === 2) try {
30171
+ E.current?.sendContextualUpdate?.("IMPORTANT: The visitor is muted and has not responded to your last 2 checks. Make exactly ONE more check. If there is still no response, say: 'I feel like you are not active, so I'm ending this session. You can connect with me anytime.' then immediately call the fwh-end-session-mvp tool to end the voice session. Do NOT ask again after that.");
30473
30172
  } catch {}
30474
- else D.current >= 5 && me("minimized");
30173
+ else pe.current >= 5 && we("minimized");
30475
30174
  }
30476
30175
  },
30477
30176
  onError: (t) => {
30478
- if (!e && !re.current && !ne.current && !Re()) {
30479
- ne.current = !0, console.error("[FlowEngageVoiceCall] session:error", {
30177
+ if (!e && !ce.current && !se.current && !Re()) {
30178
+ se.current = !0, console.error("[FlowEngageVoiceCall] session:error", {
30480
30179
  message: t?.message,
30481
30180
  name: t?.name,
30482
30181
  raw: t
30483
30182
  });
30484
30183
  try {
30485
- C.current?.setMicMuted?.(!0);
30184
+ E.current?.setMicMuted?.(!0);
30486
30185
  } catch {}
30487
- b(!0), v("error"), me("chat");
30186
+ x(!0), y("error"), we("chat");
30488
30187
  }
30489
30188
  },
30490
30189
  onDisconnect: (t) => {
30491
- if (e || re.current || ne.current || Re()) return;
30190
+ if (e || ce.current || se.current || Re()) return;
30492
30191
  let n = l.current?.length || 0;
30493
30192
  console.warn("[FlowEngageVoiceCall] session:disconnected", {
30494
30193
  historyCount: n,
30495
30194
  reason: t?.reason,
30496
30195
  closeCode: t?.context?.code,
30497
30196
  closeReason: t?.context?.reason || t?.message,
30498
- lastUserText: w.current || "",
30499
- wasMuted: te.current
30500
- }), ne.current = !0;
30197
+ lastUserText: ie.current || "",
30198
+ wasMuted: D.current
30199
+ }), se.current = !0;
30501
30200
  try {
30502
- C.current?.setMicMuted?.(!0);
30201
+ E.current?.setMicMuted?.(!0);
30503
30202
  } catch {}
30504
- b(!0), me("chat");
30203
+ x(!0), we("chat");
30505
30204
  }
30506
30205
  });
30507
30206
  if (e) {
30508
- console.warn("[FlowEngage:VoiceDebug] ❌ cancelled=true after startSession resolved — killing session immediately"), be.endSession().catch(() => {});
30207
+ console.warn("[FlowEngage:VoiceDebug] ❌ cancelled=true after startSession resolved — killing session immediately"), fe.endSession().catch(() => {});
30509
30208
  return;
30510
30209
  }
30511
- o = be, C.current = be, v("listening");
30210
+ o = fe, E.current = fe, y("listening");
30512
30211
  try {
30513
30212
  let e = typeof window < "u" ? window.location.href : "", r = "[]";
30514
30213
  try {
@@ -30520,7 +30219,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30520
30219
  n.length || (n = Array.from(document.body.querySelectorAll("h1, h2, h3")).filter((t) => !t.closest(e)).map((e) => e.textContent.replace(/\s+/g, " ").trim()).filter((e) => e.length > 2 && e.length < 200)), n.length && (a = [...new Set(n)].slice(0, 15).join(" | "));
30521
30220
  } catch {}
30522
30221
  let o = u && !m ? `RESUMING PRIOR SESSION — DO NOT GREET. The visitor is continuing the same conversation after a page reload. Do not introduce yourself or re-state your capabilities. Wait silently until the visitor speaks; if you must speak first, briefly acknowledge where you left off in one short sentence.\nPrior transcript:\n${n?.transcript || ""}\n\n` : "";
30523
- be.sendContextualUpdate(`${o}SESSION_CONTEXT (NOT a tool result — do NOT treat as CURRENT_PAGE): Visitor is on: ${e} | Approx headings for awareness only: ${a}. SiteId: ${i || "unknown"}. Forms: ${r}. The visitor is ALREADY on this page — do NOT offer to navigate there. WALKTHROUGH RULE: When the visitor asks for a walkthrough or overview of this page, you MUST IMMEDIATELY call fwh-get-current-page-mvp (zero speech — call it silently with NO words before it) to get the exact highlightable headings. The approximate headings above are for routing awareness ONLY — they are NOT precise enough for fwh-highlight-mvp. Do NOT skip fwh-get-current-page-mvp. Voice: call end_voice_session or say you are ending the session to stop.`);
30222
+ fe.sendContextualUpdate(`${o}SESSION_CONTEXT (NOT a tool result — do NOT treat as CURRENT_PAGE): Visitor is on: ${e} | Approx headings for awareness only: ${a}. SiteId: ${i || "unknown"}. Forms: ${r}. The visitor is ALREADY on this page — do NOT offer to navigate there. WALKTHROUGH RULE: When the visitor asks for a walkthrough or overview of this page, you MUST IMMEDIATELY call fwh-get-current-page-mvp (zero speech — call it silently with NO words before it) to get the exact highlightable headings. The approximate headings above are for routing awareness ONLY — they are NOT precise enough for fwh-highlight-mvp. Do NOT skip fwh-get-current-page-mvp. Voice: call end_voice_session or say you are ending the session to stop.`);
30524
30223
  } catch {}
30525
30224
  if (typeof window < "u") {
30526
30225
  let t = window.location.pathname, n = () => {
@@ -30549,7 +30248,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30549
30248
  ts: Date.now()
30550
30249
  });
30551
30250
  try {
30552
- C.current?.sendUserMessage?.(`[SYSTEM: I navigated away mid-walkthrough — I am now on the "${l}" page (${i}). Page title: "${a}". Sections: ${JSON.stringify(o)}. STOP everything. Do NOT describe the new page. Say EXACTLY: "I see you've navigated to the ${l} page — would you like me to continue what I was explaining, or shall I walk you through this page?" Then wait for my answer. IF I say continue/yes/carry on: resume speaking verbally from where you left off — do NOT call flowengage_navigate, do NOT call flowengage_highlight, the visitor will navigate themselves if needed. IF I want to hear about this page: call flowengage_highlight for sections of "${l}" only.]`);
30251
+ E.current?.sendUserMessage?.(`[SYSTEM: I navigated away mid-walkthrough — I am now on the "${l}" page (${i}). Page title: "${a}". Sections: ${JSON.stringify(o)}. STOP everything. Do NOT describe the new page. Say EXACTLY: "I see you've navigated to the ${l} page — would you like me to continue what I was explaining, or shall I walk you through this page?" Then wait for my answer. IF I say continue/yes/carry on: resume speaking verbally from where you left off — do NOT call flowengage_navigate, do NOT call flowengage_highlight, the visitor will navigate themselves if needed. IF I want to hear about this page: call flowengage_highlight for sections of "${l}" only.]`);
30553
30252
  } catch {}
30554
30253
  };
30555
30254
  c = window.history.pushState.bind(window.history), window.history.pushState = (...e) => {
@@ -30557,7 +30256,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30557
30256
  }, d = () => setTimeout(n, 50), window.addEventListener("popstate", d);
30558
30257
  }
30559
30258
  } catch (r) {
30560
- e || (console.error("[FlowEngage] startSession failed", r), r.message && r.message.includes("Too many voice sessions") ? (alert(r.message), n && n("minimized")) : (v("error"), E.current = "chat", window.setTimeout(() => {
30259
+ e || (console.error("[FlowEngage] startSession failed", r), r.message && r.message.includes("Too many voice sessions") ? (alert(r.message), n && n("minimized")) : (y("error"), le.current = "chat", window.setTimeout(() => {
30561
30260
  e || t?.();
30562
30261
  }, 0)));
30563
30262
  }
@@ -30566,15 +30265,15 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30566
30265
  agentId: r,
30567
30266
  siteId: i,
30568
30267
  apiBaseUrl: a
30569
- }), e = !0, re.current = !0;
30268
+ }), e = !0, ce.current = !0;
30570
30269
  try {
30571
30270
  Bn();
30572
30271
  } catch {}
30573
30272
  if (i) try {
30574
30273
  Ve(i);
30575
30274
  } catch {}
30576
- typeof window < "u" && (window.__fe_user_nav_during_speech = null), Ir(), de.current &&= (clearTimeout(de.current), null), fe.current &&= (clearTimeout(fe.current), null), le.current = !1, pe.current = !1, ce.current = "idle", c && typeof window < "u" && (window.history.pushState = c), d && typeof window < "u" && window.removeEventListener("popstate", d);
30577
- let t = o || C.current, n = ie.current, f = ae.current;
30275
+ typeof window < "u" && (window.__fe_user_nav_during_speech = null), Ir(), xe.current &&= (clearTimeout(xe.current), null), Se.current &&= (clearTimeout(Se.current), null), ye.current = !1, Ce.current = !1, he.current = "idle", ve.current &&= (clearTimeout(ve.current), null), c && typeof window < "u" && (window.history.pushState = c), d && typeof window < "u" && window.removeEventListener("popstate", d);
30276
+ let t = o || E.current, n = ue.current, f = de.current;
30578
30277
  if (t?.endSession?.().catch(() => {}), n && s && a) {
30579
30278
  let e = f ? Math.round((Date.now() - f) / 1e3) : 0, t = JSON.stringify({
30580
30279
  chatId: s,
@@ -30587,7 +30286,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30587
30286
  headers: { "Content-Type": "application/json" },
30588
30287
  body: t,
30589
30288
  keepalive: !0
30590
- }).catch(() => {}), ie.current = null, ae.current = null;
30289
+ }).catch(() => {}), ue.current = null, de.current = null;
30591
30290
  }
30592
30291
  typeof u == "function" && l.current.length > 0 && u(l.current).catch?.(() => {});
30593
30292
  };
@@ -30595,16 +30294,50 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30595
30294
  r,
30596
30295
  i,
30597
30296
  a,
30598
- me
30297
+ we
30599
30298
  ]), c(() => {
30600
- if (!x) return;
30299
+ if (!S) return;
30601
30300
  let e = (e) => {
30602
30301
  let t = e.composedPath?.()?.[0] || e.target;
30603
- oe.current && !oe.current.contains(t) && S(!1);
30302
+ fe.current && !fe.current.contains(t) && C(!1);
30604
30303
  };
30605
30304
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
30606
- }, [x]), /* @__PURE__ */ _("div", {
30607
- ref: oe,
30305
+ }, [S]), c(() => {
30306
+ let e = (e) => {
30307
+ ve.current &&= (clearTimeout(ve.current), null), e?.detail?.email && (ge.current = e.detail.email), T(!1), te(""), re("");
30308
+ };
30309
+ return window.addEventListener("fe:voice-email-saved", e), () => window.removeEventListener("fe:voice-email-saved", e);
30310
+ }, []);
30311
+ let Ee = async () => {
30312
+ let e = ee.trim();
30313
+ if (!e || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)) {
30314
+ re("Please enter a valid email address.");
30315
+ return;
30316
+ }
30317
+ re("");
30318
+ try {
30319
+ if (!(await (await fetch(`${a}/api/voice/save-visitor-email`, {
30320
+ method: "POST",
30321
+ headers: { "Content-Type": "application/json" },
30322
+ body: JSON.stringify({
30323
+ chatId: s,
30324
+ email: e,
30325
+ siteId: i
30326
+ })
30327
+ })).json()).success) {
30328
+ re("Could not save email. Please try again.");
30329
+ return;
30330
+ }
30331
+ window.dispatchEvent(new CustomEvent("fe:voice-email-saved", { detail: { email: e } }));
30332
+ try {
30333
+ E.current?.sendContextualUpdate?.(`EMAIL_SAVED: ${e}. The visitor has typed their email in the widget. Now answer their original question.`);
30334
+ } catch {}
30335
+ } catch {
30336
+ re("Could not save email. Please try again.");
30337
+ }
30338
+ };
30339
+ return /* @__PURE__ */ _("div", {
30340
+ ref: fe,
30608
30341
  style: {
30609
30342
  position: "relative",
30610
30343
  display: "flex",
@@ -30617,7 +30350,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30617
30350
  /* @__PURE__ */ _("div", {
30618
30351
  style: { position: "relative" },
30619
30352
  children: [
30620
- h === "listening" && !y && /* @__PURE__ */ g("span", {
30353
+ v === "listening" && !b && /* @__PURE__ */ g("span", {
30621
30354
  style: {
30622
30355
  position: "absolute",
30623
30356
  right: "100%",
@@ -30633,7 +30366,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30633
30366
  },
30634
30367
  children: "Listening..."
30635
30368
  }),
30636
- y && /* @__PURE__ */ g("span", {
30369
+ b && /* @__PURE__ */ g("span", {
30637
30370
  style: {
30638
30371
  position: "absolute",
30639
30372
  right: "100%",
@@ -30649,15 +30382,15 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30649
30382
  },
30650
30383
  children: "Muted"
30651
30384
  }),
30652
- /* @__PURE__ */ g(Pk, {
30385
+ /* @__PURE__ */ g(pk, {
30653
30386
  size: 72,
30654
- voiceState: h,
30655
- isMuted: y,
30387
+ voiceState: v,
30388
+ isMuted: b,
30656
30389
  orbColors: e
30657
30390
  })
30658
30391
  ]
30659
30392
  }),
30660
- h === "error" && /* @__PURE__ */ g("span", {
30393
+ v === "error" && /* @__PURE__ */ g("span", {
30661
30394
  style: {
30662
30395
  color: "#f87171",
30663
30396
  fontSize: "13px",
@@ -30665,6 +30398,82 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30665
30398
  },
30666
30399
  children: "Could not start voice session."
30667
30400
  }),
30401
+ w && /* @__PURE__ */ _("div", {
30402
+ style: {
30403
+ background: "rgba(15,22,36,0.92)",
30404
+ backdropFilter: "blur(12px)",
30405
+ WebkitBackdropFilter: "blur(12px)",
30406
+ border: "1px solid rgba(255,255,255,0.15)",
30407
+ borderRadius: "12px",
30408
+ padding: "10px 12px",
30409
+ display: "flex",
30410
+ flexDirection: "column",
30411
+ gap: "6px",
30412
+ width: "240px"
30413
+ },
30414
+ children: [
30415
+ /* @__PURE__ */ g("span", {
30416
+ style: {
30417
+ color: "rgba(255,255,255,0.7)",
30418
+ fontSize: "11px",
30419
+ fontWeight: 500
30420
+ },
30421
+ children: "Type your email to continue"
30422
+ }),
30423
+ /* @__PURE__ */ _("div", {
30424
+ style: {
30425
+ display: "flex",
30426
+ gap: "6px",
30427
+ alignItems: "center"
30428
+ },
30429
+ children: [/* @__PURE__ */ g("input", {
30430
+ type: "email",
30431
+ value: ee,
30432
+ onChange: (e) => {
30433
+ te(e.target.value), re("");
30434
+ },
30435
+ onKeyDown: (e) => {
30436
+ e.key === "Enter" && Ee();
30437
+ },
30438
+ placeholder: "you@example.com",
30439
+ style: {
30440
+ flex: 1,
30441
+ background: "rgba(255,255,255,0.08)",
30442
+ border: "1px solid rgba(255,255,255,0.2)",
30443
+ borderRadius: "8px",
30444
+ color: "white",
30445
+ fontSize: "13px",
30446
+ padding: "6px 10px",
30447
+ outline: "none"
30448
+ }
30449
+ }), /* @__PURE__ */ g("button", {
30450
+ onClick: Ee,
30451
+ style: {
30452
+ width: "30px",
30453
+ height: "30px",
30454
+ borderRadius: "8px",
30455
+ background: "#2563eb",
30456
+ border: "none",
30457
+ color: "white",
30458
+ fontSize: "16px",
30459
+ cursor: "pointer",
30460
+ display: "flex",
30461
+ alignItems: "center",
30462
+ justifyContent: "center",
30463
+ flexShrink: 0
30464
+ },
30465
+ children: "→"
30466
+ })]
30467
+ }),
30468
+ ne && /* @__PURE__ */ g("span", {
30469
+ style: {
30470
+ color: "#f87171",
30471
+ fontSize: "11px"
30472
+ },
30473
+ children: ne
30474
+ })
30475
+ ]
30476
+ }),
30668
30477
  /* @__PURE__ */ _("div", {
30669
30478
  style: {
30670
30479
  display: "flex",
@@ -30673,38 +30482,38 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30673
30482
  },
30674
30483
  children: [/* @__PURE__ */ g("button", {
30675
30484
  onClick: async () => {
30676
- if (C.current) try {
30677
- if (y) {
30678
- D.current = 0, await C.current.setMicMuted?.(!1), b(!1);
30485
+ if (E.current) try {
30486
+ if (b) {
30487
+ pe.current = 0, await E.current.setMicMuted?.(!1), x(!1);
30679
30488
  try {
30680
- C.current.sendContextualUpdate?.("The visitor has unmuted. Resume normal interaction and wait for them to speak.");
30489
+ E.current.sendContextualUpdate?.("The visitor has unmuted. Resume normal interaction and wait for them to speak.");
30681
30490
  } catch {}
30682
30491
  } else {
30683
- D.current = 0, await C.current.setMicMuted?.(!0), b(!0);
30492
+ pe.current = 0, await E.current.setMicMuted?.(!0), x(!0);
30684
30493
  try {
30685
- C.current.sendContextualUpdate?.("The visitor has muted their microphone. Do NOT speak, ask if they are there, or prompt them in any way. Stay completely silent until they unmute.");
30494
+ E.current.sendContextualUpdate?.("The visitor has muted their microphone. Do NOT speak, ask if they are there, or prompt them in any way. Stay completely silent until they unmute.");
30686
30495
  } catch {}
30687
30496
  }
30688
30497
  } catch {}
30689
30498
  },
30690
- title: y ? "Unmute" : "Mute",
30499
+ title: b ? "Unmute" : "Mute",
30691
30500
  style: {
30692
30501
  width: "24px",
30693
30502
  height: "24px",
30694
30503
  borderRadius: "50%",
30695
- background: y ? "#7f1d1d" : "#1f2937",
30696
- border: y ? "1.5px solid #ef4444" : "1.5px solid #4b5563",
30504
+ background: b ? "#7f1d1d" : "#1f2937",
30505
+ border: b ? "1.5px solid #ef4444" : "1.5px solid #4b5563",
30697
30506
  display: "flex",
30698
30507
  alignItems: "center",
30699
30508
  justifyContent: "center",
30700
30509
  cursor: "pointer",
30701
- color: y ? "#f87171" : "white",
30510
+ color: b ? "#f87171" : "white",
30702
30511
  transition: "all 0.2s ease",
30703
30512
  boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30704
30513
  padding: 0,
30705
30514
  flexShrink: 0
30706
30515
  },
30707
- children: y ? /* @__PURE__ */ _("svg", {
30516
+ children: b ? /* @__PURE__ */ _("svg", {
30708
30517
  width: "16",
30709
30518
  height: "16",
30710
30519
  viewBox: "0 0 24 24",
@@ -30740,7 +30549,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30740
30549
  color: "currentColor"
30741
30550
  })
30742
30551
  }), /* @__PURE__ */ g("button", {
30743
- onClick: () => S((e) => !e),
30552
+ onClick: () => C((e) => !e),
30744
30553
  style: {
30745
30554
  width: "24px",
30746
30555
  height: "24px",
@@ -30763,7 +30572,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30763
30572
  })
30764
30573
  })]
30765
30574
  }),
30766
- x && /* @__PURE__ */ _("div", {
30575
+ S && /* @__PURE__ */ _("div", {
30767
30576
  style: {
30768
30577
  position: "absolute",
30769
30578
  bottom: 0,
@@ -30781,7 +30590,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30781
30590
  children: [
30782
30591
  /* @__PURE__ */ _("button", {
30783
30592
  onClick: () => {
30784
- S(!1), E.current = "chat", he(t);
30593
+ C(!1), le.current = "chat", Te(t);
30785
30594
  },
30786
30595
  style: {
30787
30596
  display: "flex",
@@ -30810,7 +30619,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30810
30619
  }),
30811
30620
  /* @__PURE__ */ _("button", {
30812
30621
  onClick: () => {
30813
- S(!1), E.current = "minimized", he(n);
30622
+ C(!1), le.current = "minimized", Te(n);
30814
30623
  },
30815
30624
  style: {
30816
30625
  display: "flex",
@@ -30838,7 +30647,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30838
30647
  children: [/* @__PURE__ */ g(LD, {}), "End Conversation"]
30839
30648
  }),
30840
30649
  /* @__PURE__ */ g("button", {
30841
- onClick: () => S(!1),
30650
+ onClick: () => C(!1),
30842
30651
  style: {
30843
30652
  position: "absolute",
30844
30653
  bottom: "8px",
@@ -30887,7 +30696,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30887
30696
  ]
30888
30697
  });
30889
30698
  }
30890
- function Rk({ orbColors: e }) {
30699
+ function _k({ orbColors: e }) {
30891
30700
  let t = Array.isArray(e) && e.length > 0 ? e : [
30892
30701
  "#135bd8",
30893
30702
  "#ef334b",
@@ -30906,7 +30715,7 @@ function Rk({ orbColors: e }) {
30906
30715
  `.replace(/\s+/g, " ").trim()
30907
30716
  } });
30908
30717
  }
30909
- var zk = () => /* @__PURE__ */ g("div", {
30718
+ var vk = () => /* @__PURE__ */ g("div", {
30910
30719
  style: {
30911
30720
  display: "flex",
30912
30721
  marginBottom: "12px",
@@ -30936,7 +30745,7 @@ var zk = () => /* @__PURE__ */ g("div", {
30936
30745
  } }, e))
30937
30746
  })
30938
30747
  });
30939
- function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i, quickChatOptions: a, onQuickChatSelect: o, isMobile: s, chatHistory: l, isAiTyping: u, isAgentTyping: d, activeScreen: f, agentName: v, agentHeadshot: y, fallbackAgentName: b, input: x, setInput: S, onSubmit: C, isConversationEnded: w, isLoading: T, isRateLimited: ee, rateLimitMessage: te, selectedFile: ne, onFileSelect: re, onRemoveSelectedFile: E, attachmentError: ie, isUploadingAttachment: ae, requiresEmail: oe, emailInput: D, setEmailInput: se, emailError: ce, emailCaptureSuccess: le, replyContext: ue, setReplyContext: de, webRTCError: fe, micError: pe, setMicError: me, dismissCallError: he, activeCallId: ge, isCallMuted: _e, toggleCallMute: ve, endWebRTCCall: ye, formatCallDuration: be, callDurationSeconds: xe, isCallMinimized: Se, onExpand: Ce, onCollapse: we, onStartVoice: Te, voiceEnabled: Ee, headerBgColor: De, onNewChat: Oe, showPoweredBy: ke, privacyPolicyUrl: O, getVisitorChatHistory: Ae, resumeChat: je, isSessionRestoring: Me, isClosing: Ne }) {
30748
+ function yk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i, quickChatOptions: a, onQuickChatSelect: o, isMobile: s, chatHistory: l, isAiTyping: u, isAgentTyping: d, activeScreen: f, agentName: v, agentHeadshot: y, fallbackAgentName: b, input: x, setInput: S, onSubmit: C, isConversationEnded: w, isLoading: T, isRateLimited: ee, rateLimitMessage: te, selectedFile: ne, onFileSelect: re, onRemoveSelectedFile: E, attachmentError: ie, isUploadingAttachment: ae, requiresEmail: oe, emailInput: D, setEmailInput: se, emailError: ce, emailCaptureSuccess: le, replyContext: ue, setReplyContext: de, webRTCError: fe, micError: pe, setMicError: me, dismissCallError: he, activeCallId: ge, isCallMuted: _e, toggleCallMute: ve, endWebRTCCall: ye, formatCallDuration: be, callDurationSeconds: xe, isCallMinimized: Se, onExpand: Ce, onCollapse: we, onStartVoice: Te, voiceEnabled: Ee, headerBgColor: De, onNewChat: Oe, showPoweredBy: ke, privacyPolicyUrl: O, getVisitorChatHistory: Ae, resumeChat: je, isSessionRestoring: Me, isClosing: Ne }) {
30940
30749
  let Pe = l.length > 0, Fe = T || ee || w, Ie = !!ge, [Le, Re] = m(!1), [ze, Be] = m(!1), [Ve, k] = m([]), [He, Ue] = m(!1), We = p(null), [Ge, Ke] = m(() => typeof window < "u" ? window.visualViewport?.height ?? window.innerHeight : 600), [qe, Je] = m(0);
30941
30750
  c(() => {
30942
30751
  if (!s) return;
@@ -31076,7 +30885,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31076
30885
  justifyContent: "center",
31077
30886
  height: "40px"
31078
30887
  },
31079
- children: i ? /* @__PURE__ */ g(jk, {
30888
+ children: i ? /* @__PURE__ */ g(uk, {
31080
30889
  logo: i,
31081
30890
  style: {
31082
30891
  height: "34px",
@@ -31089,7 +30898,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31089
30898
  height: "40px",
31090
30899
  flexShrink: 0
31091
30900
  },
31092
- children: /* @__PURE__ */ g(Mk, { title: e.chatTitle })
30901
+ children: /* @__PURE__ */ g(dk, { title: e.chatTitle })
31093
30902
  })
31094
30903
  }), o && /* @__PURE__ */ g("div", {
31095
30904
  style: {
@@ -31520,11 +31329,11 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31520
31329
  isLoading: T,
31521
31330
  isAgentTyping: d,
31522
31331
  setReplyContext: de,
31523
- TypingDots: zk,
31332
+ TypingDots: vk,
31524
31333
  primaryColor: n,
31525
31334
  agentHeadshot: y,
31526
31335
  agentDisplayName: v || b,
31527
- botAvatarNode: /* @__PURE__ */ g(Rk, { orbColors: t })
31336
+ botAvatarNode: /* @__PURE__ */ g(_k, { orbColors: t })
31528
31337
  }) : Me ? /* @__PURE__ */ _("div", {
31529
31338
  style: {
31530
31339
  flex: 1,
@@ -31565,7 +31374,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31565
31374
  padding: "28px 24px"
31566
31375
  },
31567
31376
  children: [
31568
- /* @__PURE__ */ g(Pk, {
31377
+ /* @__PURE__ */ g(pk, {
31569
31378
  size: 94,
31570
31379
  orbColors: t
31571
31380
  }),
@@ -31730,7 +31539,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31730
31539
  ]
31731
31540
  });
31732
31541
  }
31733
- function Vk() {
31542
+ function bk() {
31734
31543
  let { status: e, runtimeConfig: t, resolvedConfig: n, chatHistory: r, isOpen: i, activeScreen: a, isHumanHandled: s, agentName: l, agentHeadshot: u, visitorEmail: h, isAgentTyping: v, isAiTyping: y, isLoading: b, isRateLimited: x, rateLimitMessage: S, isConversationEnded: C, incomingCall: w, activeCallId: T, callConnectionState: ee, callConnectedAt: te, isCallMuted: ne, webRTCError: re, language: E, chatId: ie, historyRef: ae, onMessageSync: oe, sendMessage: D, uploadChatFile: se, openWidget: ce, captureVisitorEmail: le, setVoiceMode: ue, endConversation: de, startNewChat: me, acceptCall: he, rejectCall: ge, endWebRTCCall: _e, toggleCallMute: ve, dismissCallError: ye, startTyping: be, stopTyping: xe, updateTypingDraft: Se, getVisitorChatHistory: Ce, resumeChat: we, isSessionRestoring: Te, openToChatCounter: Ee, voiceEndCounter: De } = Fn();
31735
31544
  c(() => {
31736
31545
  try {
@@ -31738,7 +31547,13 @@ function Vk() {
31738
31547
  } catch {}
31739
31548
  }, []), c(() => {
31740
31549
  Ee && M !== "voice_mode" && M !== "text_chat" && M !== "call_screen" && (ue?.(!1), dt("text_chat"));
31741
- }, [Ee]);
31550
+ }, [Ee]), c(() => {
31551
+ let e = (e) => {
31552
+ let t = e?.detail?.email;
31553
+ t && typeof le == "function" && le(t);
31554
+ };
31555
+ return window.addEventListener("fe:voice-email-saved", e), () => window.removeEventListener("fe:voice-email-saved", e);
31556
+ }, [le]);
31742
31557
  let Oe = t?.widgetSettings || {}, ke = n?.widgetSettings || {}, O = {
31743
31558
  ...Oe.branding || {},
31744
31559
  ...ke.branding || {}
@@ -31752,7 +31567,7 @@ function Vk() {
31752
31567
  small: 50,
31753
31568
  medium: 64,
31754
31569
  large: 80
31755
- }, Be = ze[Me.orbSize] || ze.small, Ve = Me.position || "bottom-right", k = O.fallbackAgentName || "Agent", He = Ok(Ie ?? Me.chatBgColors), Ue = O.logo || O.logoUrl || null, We = E || "en", Ge = Oe.recommendations?.[We] || [], Ke = (ke.recommendations?.[We] ?? Ge).filter((e) => String(e?.label ?? "").trim()).map((e, t) => ({
31570
+ }, Be = ze[Me.orbSize] || ze.small, Ve = Me.position || "bottom-right", k = O.fallbackAgentName || "Agent", He = sk(Ie ?? Me.chatBgColors), Ue = O.logo || O.logoUrl || null, We = E || "en", Ge = Oe.recommendations?.[We] || [], Ke = (ke.recommendations?.[We] ?? Ge).filter((e) => String(e?.label ?? "").trim()).map((e, t) => ({
31756
31571
  id: e.key || `qr-${t}`,
31757
31572
  label: e.label,
31758
31573
  message: e.label,
@@ -32041,7 +31856,7 @@ function Vk() {
32041
31856
  onWheel: (e) => e.stopPropagation(),
32042
31857
  onTouchMove: (e) => e.stopPropagation(),
32043
31858
  children: [
32044
- M === "entry_prompt" && /* @__PURE__ */ g(Fk, {
31859
+ M === "entry_prompt" && /* @__PURE__ */ g(mk, {
32045
31860
  copy: A,
32046
31861
  orbColors: Ie,
32047
31862
  primaryColor: Re,
@@ -32124,13 +31939,13 @@ function Vk() {
32124
31939
  children: ee === "connected" ? `${qt(xt)} with ${ot}` : `Tap to return to ${ot}`
32125
31940
  })]
32126
31941
  })]
32127
- }), /* @__PURE__ */ g(Pk, {
31942
+ }), /* @__PURE__ */ g(pk, {
32128
31943
  size: Be,
32129
31944
  orbColors: Ie,
32130
31945
  onClick: T ? Ht : Fe ? Zt : $t
32131
31946
  })]
32132
31947
  }),
32133
- M === "connection_modal" && /* @__PURE__ */ g(Ik, {
31948
+ M === "connection_modal" && /* @__PURE__ */ g(hk, {
32134
31949
  copy: A,
32135
31950
  orbColors: Ie,
32136
31951
  primaryColor: Re,
@@ -32140,7 +31955,7 @@ function Vk() {
32140
31955
  isMobile: Rt,
32141
31956
  isClosing: Nt
32142
31957
  }),
32143
- M === "voice_mode" && /* @__PURE__ */ g(Lk, {
31958
+ M === "voice_mode" && /* @__PURE__ */ g(gk, {
32144
31959
  orbColors: Ie,
32145
31960
  onEnterChat: $t,
32146
31961
  onEndChat: en,
@@ -32151,7 +31966,8 @@ function Vk() {
32151
31966
  historyRef: ae,
32152
31967
  onMessageSync: oe,
32153
31968
  voiceEndCounter: De,
32154
- websiteName: t?.websiteName
31969
+ websiteName: t?.websiteName,
31970
+ visitorEmail: h
32155
31971
  }, "voice"),
32156
31972
  M === "call_screen" && /* @__PURE__ */ g(bO, {
32157
31973
  incomingCall: w,
@@ -32172,7 +31988,7 @@ function Vk() {
32172
31988
  orbColors: Ie,
32173
31989
  chatHistory: r
32174
31990
  }),
32175
- M === "text_chat" && /* @__PURE__ */ g(Bk, {
31991
+ M === "text_chat" && /* @__PURE__ */ g(yk, {
32176
31992
  isClosing: Nt,
32177
31993
  copy: A,
32178
31994
  orbColors: Ie,
@@ -32238,7 +32054,7 @@ function Vk() {
32238
32054
  }
32239
32055
  //#endregion
32240
32056
  //#region src/components/ErrorBoundary.jsx
32241
- var Hk = class extends e.Component {
32057
+ var xk = class extends e.Component {
32242
32058
  constructor(e) {
32243
32059
  super(e), this.state = { hasError: !1 };
32244
32060
  }
@@ -32253,4 +32069,4 @@ var Hk = class extends e.Component {
32253
32069
  }
32254
32070
  };
32255
32071
  //#endregion
32256
- export { pO as AnimatedOrb, Hk as ErrorBoundary, Wr as FlowEngageProvider, Vk as FlowEngageWidget, Fn as useFlowEngage };
32072
+ export { pO as AnimatedOrb, xk as ErrorBoundary, Wr as FlowEngageProvider, bk as FlowEngageWidget, Fn as useFlowEngage };