@flowengage/react-chatbot 8.0.12 → 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.
@@ -28827,29 +28827,18 @@ function NO() {
28827
28827
  }, 380)));
28828
28828
  }, 220)));
28829
28829
  }
28830
- function PO() {
28831
- typeof document > "u" || document.querySelectorAll(`.${Q}-field-active, .${Q}-field-filled`).forEach((e) => e.classList.remove(`${Q}-field-active`, `${Q}-field-filled`));
28832
- }
28833
- function FO(e) {
28834
- !e || typeof document > "u" || (CO(), PO(), e.classList.add(`${Q}-field-active`));
28835
- }
28836
- function IO(e) {
28837
- e && (e.classList.remove(`${Q}-field-active`), e.classList.add(`${Q}-field-filled`), setTimeout(() => {
28838
- e.isConnected && e.classList.remove(`${Q}-field-filled`);
28839
- }, 1400));
28840
- }
28841
- 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">
28842
28831
  <filter id="${Q}-csh">
28843
28832
  <feDropShadow dx="1" dy="2" stdDeviation="1.5" flood-color="#00000060"/>
28844
28833
  </filter>
28845
28834
  <path d="M4 2L19 10.5L11 12.8L8 20L4 2Z"
28846
28835
  fill="white" stroke="#1e1b4b" stroke-width="1.6" stroke-linejoin="round"
28847
28836
  filter="url(#${Q}-csh)"/>
28848
- </svg>`, RO = null, zO = !1;
28849
- function BO() {
28850
- 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;
28851
28840
  }
28852
- async function VO(e) {
28841
+ async function RO(e) {
28853
28842
  if (typeof document > "u" || !e) return;
28854
28843
  CO();
28855
28844
  let t;
@@ -28858,18 +28847,18 @@ async function VO(e) {
28858
28847
  } catch {
28859
28848
  return;
28860
28849
  }
28861
- let n = t.left + Math.min(16, t.width * .2), r = t.top + Math.min(12, t.height * .25), i = BO();
28862
- 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);
28863
28852
  }
28864
- function HO(e = !1) {
28865
- RO && (e ? (RO.classList.remove(`${Q}-cursor-visible`), zO = !1) : (RO.classList.remove(`${Q}-cursor-visible`), setTimeout(() => {
28866
- 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;
28867
28856
  }, 250)));
28868
28857
  }
28869
- async function UO(e) {
28870
- 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`));
28871
28860
  }
28872
- function WO(e) {
28861
+ function VO(e) {
28873
28862
  if (!e || typeof document > "u") return;
28874
28863
  CO();
28875
28864
  let t;
@@ -28897,7 +28886,7 @@ function WO(e) {
28897
28886
  a.remove(), e.style.position = n, e.style.overflow = r;
28898
28887
  }, 650);
28899
28888
  }
28900
- function GO(e) {
28889
+ function HO(e) {
28901
28890
  return new Promise((t) => setTimeout(t, e));
28902
28891
  }
28903
28892
  //#endregion
@@ -28905,17 +28894,14 @@ function GO(e) {
28905
28894
  function $(...e) {
28906
28895
  In() && console.log("[FlowEngage:voice-tools]", ...e);
28907
28896
  }
28908
- function KO(e) {
28909
- return new Promise((t) => setTimeout(t, e));
28910
- }
28911
- function qO(e) {
28897
+ function UO(e) {
28912
28898
  try {
28913
28899
  let t = e.ownerDocument?.defaultView;
28914
28900
  if (t) return t.getComputedStyle(e);
28915
28901
  } catch {}
28916
28902
  return window.getComputedStyle(e);
28917
28903
  }
28918
- function JO(e) {
28904
+ function WO(e) {
28919
28905
  let t = /* @__PURE__ */ new Set();
28920
28906
  function n(r) {
28921
28907
  if (!r || t.has(r)) return;
@@ -28928,10 +28914,10 @@ function JO(e) {
28928
28914
  }
28929
28915
  typeof document < "u" && n(document);
28930
28916
  }
28931
- function YO(e) {
28917
+ function GO(e) {
28932
28918
  return e == null ? null : String(e).replace(/\u00a0/g, " ").replace(/\s*\*+\s*$/u, "").replace(/\s+/g, " ").trim();
28933
28919
  }
28934
- function XO(e) {
28920
+ function KO(e) {
28935
28921
  let t = e.ownerDocument || document, n = e.getAttribute("aria-labelledby");
28936
28922
  if (n) {
28937
28923
  let e = n.trim().split(/\s+/).filter(Boolean), r = [];
@@ -28939,40 +28925,40 @@ function XO(e) {
28939
28925
  let e = t.getElementById(n);
28940
28926
  e?.textContent && r.push(e.textContent.trim());
28941
28927
  } catch {}
28942
- if (r.length) return YO(r.join(" "));
28928
+ if (r.length) return GO(r.join(" "));
28943
28929
  }
28944
- 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);
28945
28931
  let r = e.id;
28946
28932
  if (r) try {
28947
28933
  let e = t.querySelector(`label[for="${CSS.escape(r)}"]`);
28948
- if (e) return YO(e.textContent);
28934
+ if (e) return GO(e.textContent);
28949
28935
  } catch {
28950
28936
  let e = t.querySelector(`label[for="${r.replace(/"/g, "\\\"")}"]`);
28951
- if (e) return YO(e.textContent);
28937
+ if (e) return GO(e.textContent);
28952
28938
  }
28953
28939
  let i = e.previousElementSibling;
28954
28940
  for (let e = 0; e < 6 && i; e += 1) {
28955
- if (i.tagName === "LABEL") return YO(i.textContent);
28941
+ if (i.tagName === "LABEL") return GO(i.textContent);
28956
28942
  let e = (i.className || "").toString().toLowerCase();
28957
28943
  if (/chakra-form__label|formlabel|field-label|form-label|mui-form-label/.test(e)) {
28958
- let e = YO(i.textContent);
28944
+ let e = GO(i.textContent);
28959
28945
  if (e) return e;
28960
28946
  }
28961
28947
  i = i.previousElementSibling;
28962
28948
  }
28963
28949
  let a = e.parentElement;
28964
28950
  for (let e = 0; e < 5 && a; e += 1) {
28965
- if (a.tagName === "LABEL") return YO(a.textContent);
28951
+ if (a.tagName === "LABEL") return GO(a.textContent);
28966
28952
  let e = a.querySelector?.(":scope > label, :scope > [class*='FormLabel'], :scope > [class*='form__label']");
28967
- if (e?.textContent) return YO(e.textContent);
28953
+ if (e?.textContent) return GO(e.textContent);
28968
28954
  a = a.parentElement;
28969
28955
  }
28970
28956
  let o = e.getAttribute("aria-label");
28971
- return o ? YO(o) : null;
28957
+ return o ? GO(o) : null;
28972
28958
  }
28973
- function ZO() {
28959
+ function qO() {
28974
28960
  let e = [];
28975
- return JO((t) => {
28961
+ return WO((t) => {
28976
28962
  e.push(...Array.from(t.querySelectorAll("input, select, textarea")).filter((e) => {
28977
28963
  if (Hn(e)) return !1;
28978
28964
  let t = (e.type || "").toLowerCase();
@@ -28983,15 +28969,15 @@ function ZO() {
28983
28969
  "image"
28984
28970
  ].includes(t) || e.disabled || e.readOnly) return !1;
28985
28971
  try {
28986
- let t = qO(e);
28972
+ let t = UO(e);
28987
28973
  if (t.display === "none" || t.visibility === "hidden") return !1;
28988
28974
  } catch {}
28989
28975
  return !0;
28990
28976
  }));
28991
28977
  }), e;
28992
28978
  }
28993
- function QO() {
28994
- return ZO().map((e, t) => {
28979
+ function JO() {
28980
+ return qO().map((e, t) => {
28995
28981
  let n = {
28996
28982
  formIndex: 0,
28997
28983
  fieldIndex: t,
@@ -28999,7 +28985,7 @@ function QO() {
28999
28985
  type: e.type || "text",
29000
28986
  name: e.name || null,
29001
28987
  id: e.id || null,
29002
- label: XO(e),
28988
+ label: KO(e),
29003
28989
  placeholder: e.placeholder || null
29004
28990
  };
29005
28991
  return e.tagName === "SELECT" && (n.options = Array.from(e.options).filter((e) => e.value !== "" && !e.disabled).map((e) => ({
@@ -29008,13 +28994,13 @@ function QO() {
29008
28994
  })), n.currentValue = e.value || null), n;
29009
28995
  });
29010
28996
  }
29011
- function $O() {
28997
+ function YO() {
29012
28998
  let e = [];
29013
- return JO((t) => {
28999
+ return WO((t) => {
29014
29000
  e.push(...Array.from(t.querySelectorAll("button, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"]")).filter((e) => {
29015
29001
  if (Hn(e) || e.disabled) return !1;
29016
29002
  try {
29017
- let t = qO(e);
29003
+ let t = UO(e);
29018
29004
  if (t.display === "none" || t.visibility === "hidden") return !1;
29019
29005
  } catch {}
29020
29006
  return !0;
@@ -29026,123 +29012,7 @@ function $O() {
29026
29012
  type: e.type || e.tagName
29027
29013
  }));
29028
29014
  }
29029
- function ek(e) {
29030
- return String(e || "").toLowerCase().replace(/\u00a0/g, " ").replace(/\*/g, "").replace(/\s+/g, " ").trim();
29031
- }
29032
- function tk(e) {
29033
- let t = ek(e);
29034
- return t = t.replace(/\s+field\s*$/i, "").trim(), t;
29035
- }
29036
- function nk(e, t) {
29037
- let n = tk(t);
29038
- if (!n) return 0;
29039
- let r = (e.name || "").toLowerCase(), i = (e.id || "").toLowerCase();
29040
- 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;
29041
- let a = [
29042
- e.name,
29043
- e.id,
29044
- e.placeholder,
29045
- XO(e),
29046
- e.getAttribute("aria-label"),
29047
- e.getAttribute("title"),
29048
- e.getAttribute("data-testid"),
29049
- e.getAttribute("autocomplete")
29050
- ].filter(Boolean).map((e) => ek(e)), o = 0;
29051
- for (let e of a) {
29052
- if (!e) continue;
29053
- if (e.includes(n) || n.includes(e)) {
29054
- o = Math.max(o, 100);
29055
- continue;
29056
- }
29057
- let t = n.split(/\s+/).filter((e) => e.length > 1);
29058
- if (!t.length) continue;
29059
- let r = 0;
29060
- for (let n of t) e.includes(n) && (r += 1);
29061
- o = Math.max(o, r / t.length * 88);
29062
- }
29063
- return o;
29064
- }
29065
- var rk = 28;
29066
- function ik(e, t) {
29067
- let n = null, r = 0;
29068
- for (let i of e) {
29069
- let e = nk(i, t);
29070
- e > r && (r = e, n = i);
29071
- }
29072
- return !n || r < rk ? null : n;
29073
- }
29074
- function ak(e, t, n) {
29075
- let r = String(t || "").toLowerCase().trim(), i = String(n || "").trim();
29076
- if (!(/^https?:\/\//i.test(i) || /\.\w{2,}(\/|\s|$)/.test(i) || r.includes("url") || r.includes("website") || r.includes("domain") || r.includes("site"))) return null;
29077
- let a = null, o = 0;
29078
- for (let t of e) {
29079
- if (t.tagName !== "INPUT" && t.tagName !== "TEXTAREA") continue;
29080
- let e = (t.type || "").toLowerCase();
29081
- if ([
29082
- "hidden",
29083
- "submit",
29084
- "button",
29085
- "checkbox",
29086
- "radio"
29087
- ].includes(e)) continue;
29088
- let n = 0;
29089
- (e === "url" || e === "text" || e === "search") && (n += 45);
29090
- let r = [
29091
- t.name,
29092
- t.id,
29093
- t.placeholder,
29094
- XO(t),
29095
- t.getAttribute("aria-label"),
29096
- t.getAttribute("autocomplete")
29097
- ].filter(Boolean).join(" ").toLowerCase();
29098
- /(website|url|domain|site\s*url)/.test(r) && (n += 55), n > o && (o = n, a = t);
29099
- }
29100
- return !a || o < 42 ? null : a;
29101
- }
29102
- function ok(e) {
29103
- let t = String(e ?? "").trim();
29104
- return t ? /^https?:\/\//i.test(t) ? !0 : /\.\w{2,}(\/|\s|$)/.test(t) : !1;
29105
- }
29106
- function sk(e) {
29107
- let t = String(e ?? "").toLowerCase().trim();
29108
- 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;
29109
- }
29110
- function ck(e) {
29111
- if (!e || e.tagName !== "INPUT" && e.tagName !== "TEXTAREA") return !1;
29112
- let t = (e.type || "").toLowerCase();
29113
- return ![
29114
- "hidden",
29115
- "submit",
29116
- "button",
29117
- "checkbox",
29118
- "radio",
29119
- "file"
29120
- ].includes(t);
29121
- }
29122
- function lk(e) {
29123
- if (!ck(e)) return !1;
29124
- let t = (e.name || "").toLowerCase(), n = (e.id || "").toLowerCase(), r = [
29125
- e.name,
29126
- e.id,
29127
- e.placeholder,
29128
- XO(e),
29129
- e.getAttribute("aria-label")
29130
- ].filter(Boolean).join(" ").toLowerCase();
29131
- 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);
29132
- }
29133
- function uk(e, t, n) {
29134
- let r = String(t ?? ""), i = String(n ?? ""), a = pk(e, r) || ik(e, r) || ak(e, r, i);
29135
- if (!a) return [];
29136
- let o = new Set([a]);
29137
- if (ok(i) && sk(r)) for (let t of e) t !== a && lk(t) && o.add(t);
29138
- let s = Array.from(o);
29139
- return s.sort((e, t) => {
29140
- if (e === t) return 0;
29141
- let n = e.compareDocumentPosition(t);
29142
- return n & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : n & Node.DOCUMENT_POSITION_PRECEDING ? 1 : 0;
29143
- }), s;
29144
- }
29145
- function dk(e, t) {
29015
+ function XO(e, t) {
29146
29016
  try {
29147
29017
  if (!e?.getBoundingClientRect || !t?.getBoundingClientRect) return Infinity;
29148
29018
  let n = e.getBoundingClientRect(), r = t.getBoundingClientRect(), i = {
@@ -29157,42 +29027,7 @@ function dk(e, t) {
29157
29027
  return Infinity;
29158
29028
  }
29159
29029
  }
29160
- function fk(e) {
29161
- if (!e || typeof e != "string") return null;
29162
- let t = null;
29163
- return JO((n) => {
29164
- try {
29165
- let r = n.getElementById(e);
29166
- r && !Hn(r) && r.matches?.("input, select, textarea") && (t = r);
29167
- } catch {}
29168
- }), t;
29169
- }
29170
- function pk(e, t) {
29171
- let n = String(t ?? "").trim();
29172
- if (!n) return null;
29173
- let r = n.match(/^name:\s*([\w.-]+)$/i);
29174
- if (r) {
29175
- let t = r[1];
29176
- for (let n of e) if (n.name === t) return n;
29177
- }
29178
- let i = n.match(/^id:\s*([\w.-]+)$/i);
29179
- if (i) {
29180
- let e = fk(i[1]);
29181
- if (e) return e;
29182
- }
29183
- let a = n.startsWith("#") ? n.slice(1) : n;
29184
- if (/^[\w-]+$/.test(a)) {
29185
- let e = fk(a);
29186
- if (e) return e;
29187
- }
29188
- let o = n.toLowerCase().replace(/\s+/g, " ");
29189
- if (o === "url" || o === "website" || o === "website url" || o === "website_url" || o === "enter website url") for (let t of e) {
29190
- let e = (t.name || "").toLowerCase(), n = (t.id || "").toLowerCase();
29191
- if (e === "url" || n === "url-input" || n.endsWith("-url-input")) return t;
29192
- }
29193
- return null;
29194
- }
29195
- function mk(e, t) {
29030
+ function ZO(e, t) {
29196
29031
  let n = String(t || "").toLowerCase().trim();
29197
29032
  if (!n) return 0;
29198
29033
  let r = (e.innerText || e.textContent || "").replace(/\s+/g, " ").trim(), i = [
@@ -29210,14 +29045,14 @@ function mk(e, t) {
29210
29045
  for (let e of a) i.includes(e) && (o += 1);
29211
29046
  return o / a.length * 92;
29212
29047
  }
29213
- function hk(e, t) {
29048
+ function QO(e, t) {
29214
29049
  let n = [];
29215
- JO((e) => {
29050
+ WO((e) => {
29216
29051
  let t = Array.from(e.querySelectorAll("button, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"], a[href]"));
29217
29052
  n.push(...t.filter((e) => {
29218
29053
  if (Hn(e) || e.disabled) return !1;
29219
29054
  try {
29220
- let t = qO(e);
29055
+ let t = UO(e);
29221
29056
  if (t.display === "none" || t.visibility === "hidden" || t.opacity === "0") return !1;
29222
29057
  } catch {}
29223
29058
  return !0;
@@ -29225,7 +29060,7 @@ function hk(e, t) {
29225
29060
  });
29226
29061
  let r = 0, i = n.map((t) => ({
29227
29062
  el: t,
29228
- s: mk(t, e)
29063
+ s: ZO(t, e)
29229
29064
  }));
29230
29065
  for (let { s: e } of i) e > r && (r = e);
29231
29066
  if (r < 28) return null;
@@ -29235,14 +29070,14 @@ function hk(e, t) {
29235
29070
  if (o.length) {
29236
29071
  let e = a[0], t = Infinity;
29237
29072
  for (let n of a) for (let r of o) {
29238
- let i = dk(n, r);
29073
+ let i = XO(n, r);
29239
29074
  i < t && (t = i, e = n);
29240
29075
  }
29241
29076
  return e;
29242
29077
  }
29243
29078
  return a[0];
29244
29079
  }
29245
- function gk(e) {
29080
+ function $O(e) {
29246
29081
  if (e == null) return {};
29247
29082
  if (typeof e == "string") {
29248
29083
  let t = e.trim();
@@ -29255,151 +29090,12 @@ function gk(e) {
29255
29090
  }
29256
29091
  return e;
29257
29092
  }
29258
- function _k(e) {
29259
- let t = gk(e);
29260
- if (Array.isArray(t) && t.length > 0) {
29261
- let e = t[0];
29262
- if (e?.field_key != null || e?.fieldKey != null) return t.map((e) => ({
29263
- field_key: e.field_key ?? e.fieldKey,
29264
- value: e.value
29265
- }));
29266
- }
29267
- if (!t || typeof t != "object") return [];
29268
- let n = t.fields ?? t.Fields ?? t.field_list ?? t.fieldList ?? t.data?.fields;
29269
- if (typeof n == "string") try {
29270
- n = JSON.parse(n);
29271
- } catch {
29272
- n = null;
29273
- }
29274
- 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 = [{
29275
- field_key: t.field_key ?? t.fieldKey,
29276
- value: t.value
29277
- }]);
29278
- let r = t.website_url ?? t.websiteUrl ?? t.url ?? t.website ?? t.domain ?? t.site_url ?? t.siteUrl;
29279
- return (!n || n.length === 0) && r != null && String(r).trim() && (n = [{
29280
- field_key: t.field_key ?? t.fieldKey ?? "url",
29281
- value: String(r).trim()
29282
- }]), Array.isArray(n) ? n.map((e) => ({
29283
- field_key: e?.field_key ?? e?.fieldKey,
29284
- value: e?.value ?? e?.Value
29285
- })) : [];
29286
- }
29287
- function vk(e) {
29288
- if (!e || typeof e != "string") return [];
29289
- let t = e.trim();
29290
- if (!t || /\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i.test(t)) return [];
29291
- let n = t.match(/https?:\/\/[^\s<>"']+/i);
29292
- if (n) return [{
29293
- field_key: "url",
29294
- value: n[0].replace(/[.,;:)]+$/, "")
29295
- }];
29296
- let r = t.match(/\b(?:[\w-]+\.)+[a-z]{2,}\b/i);
29297
- if (r) {
29298
- let e = r[0].replace(/[.,;:)]+$/, "");
29299
- return /^https?:/i.test(e) || (e = `https://${e}`), [{
29300
- field_key: "url",
29301
- value: e
29302
- }];
29303
- }
29304
- return [];
29305
- }
29306
- function yk(e) {
29307
- if (!e || typeof e != "string") return [];
29308
- let t = e.trim();
29309
- if (!t) return [];
29310
- let n = [], r = /* @__PURE__ */ new Set(), i = /\b([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\b/i, a = (e, t) => {
29311
- let i = String(t ?? "").trim().replace(/^["']|["']$/g, "");
29312
- if (!i || i.length > 800) return;
29313
- let a = `${e}\0${i}`;
29314
- r.has(a) || (r.add(a), n.push({
29315
- field_key: e,
29316
- value: i
29317
- }));
29318
- }, o = t.match(/^\s*([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\s*$/i);
29319
- if (o) return a("Email Address", o[1]), n;
29320
- 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);
29321
- 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) {
29322
- let e = s[1].trim();
29323
- e.length > 1 && e.length < 120 && !/@/.test(e) && a("Full Name", e);
29324
- }
29325
- 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) {
29326
- let e = s[1].trim();
29327
- e.length > 0 && a("Message", e);
29328
- }
29329
- if (!n.some((e) => /email/i.test(String(e.field_key)))) {
29330
- let e = t.match(i);
29331
- if (e) {
29332
- 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();
29333
- if (t.length <= 96 && r.length <= 36) return a("Email Address", e[1]), n;
29334
- }
29335
- }
29336
- if (n.length === 0) {
29337
- 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());
29338
- n && t.length >= 16 && !i.test(t) && !r && a("Message", t);
29339
- }
29340
- return n;
29341
- }
29342
- function bk(e) {
29093
+ function ek(e) {
29343
29094
  if (!e || typeof e != "object") return null;
29344
29095
  let t = e.url ?? e.target_url ?? e.page_url ?? e.pageUrl ?? e.link ?? e.href ?? e.path;
29345
29096
  return t == null ? null : String(t).trim() || null;
29346
29097
  }
29347
- function xk(e, t, n) {
29348
- if (!n?.skipScroll) try {
29349
- e.scrollIntoView({
29350
- block: "center",
29351
- inline: "nearest"
29352
- });
29353
- } catch {
29354
- try {
29355
- e.scrollIntoView(!0);
29356
- } catch {}
29357
- }
29358
- try {
29359
- e.focus({ preventScroll: !0 });
29360
- } catch {
29361
- try {
29362
- e.focus();
29363
- } catch {}
29364
- }
29365
- let r = e.tagName, i = (e.type || "").toLowerCase();
29366
- if (r === "SELECT") return e.value = String(t), e.dispatchEvent(new Event("input", { bubbles: !0 })), e.dispatchEvent(new Event("change", { bubbles: !0 })), !0;
29367
- if (i === "checkbox" || i === "radio") return e.checked = [
29368
- "1",
29369
- "true",
29370
- "yes",
29371
- "on"
29372
- ].includes(String(t).toLowerCase().trim()), e.dispatchEvent(new Event("input", { bubbles: !0 })), e.dispatchEvent(new Event("change", { bubbles: !0 })), !0;
29373
- let a = String(t);
29374
- if (r === "INPUT" || r === "TEXTAREA") {
29375
- let t = e.ownerDocument?.defaultView || window, n = r === "TEXTAREA" ? t.HTMLTextAreaElement.prototype : t.HTMLInputElement.prototype, i = Object.getOwnPropertyDescriptor(n, "value");
29376
- i?.set ? i.set.call(e, a) : e.value = a;
29377
- } else e.value = a;
29378
- let o = {
29379
- bubbles: !0,
29380
- cancelable: !0,
29381
- composed: !0
29382
- };
29383
- try {
29384
- e.dispatchEvent(new InputEvent("input", {
29385
- ...o,
29386
- inputType: "insertText",
29387
- data: a
29388
- }));
29389
- } catch {
29390
- e.dispatchEvent(new Event("input", o));
29391
- }
29392
- e.dispatchEvent(new Event("change", o));
29393
- try {
29394
- queueMicrotask(() => {
29395
- try {
29396
- e.dispatchEvent(new Event("input", o)), e.dispatchEvent(new Event("change", o));
29397
- } catch {}
29398
- });
29399
- } catch {}
29400
- return !0;
29401
- }
29402
- function Sk() {
29098
+ function tk() {
29403
29099
  let e = {};
29404
29100
  document.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach((t) => {
29405
29101
  if (t.id) return;
@@ -29414,7 +29110,7 @@ function Sk() {
29414
29110
  e[r] = !0, t.id = r;
29415
29111
  });
29416
29112
  }
29417
- function Ck() {
29113
+ function nk() {
29418
29114
  let e = (e) => {
29419
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;
29420
29116
  for (; r < t.length;) {
@@ -29432,9 +29128,11 @@ function Ck() {
29432
29128
  }
29433
29129
  return n;
29434
29130
  }, t = e((document.querySelector("main, [role='main']") || document.body).querySelectorAll("h1, h2, h3"));
29435
- 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);
29436
29134
  }
29437
- function wk(e) {
29135
+ function rk(e) {
29438
29136
  if (!e || typeof document > "u") return "";
29439
29137
  let t = new Set([
29440
29138
  "script",
@@ -29505,11 +29203,11 @@ function wk(e) {
29505
29203
  return d.has(t) ? !1 : (d.add(t), !0);
29506
29204
  }).join("\n").replace(/\n{3,}/g, "\n\n").trim();
29507
29205
  }
29508
- function Tk(e) {
29206
+ function ik(e) {
29509
29207
  let t = e.siteId || null, n = (e.apiBaseUrl || "").replace(/\/$/, ""), r = typeof e.getLastUserVoiceText == "function" ? e.getLastUserVoiceText : null, i = [], a = {
29510
29208
  "fwh-navigate-mvp": async (n) => {
29511
29209
  $("fwh-navigate-mvp ▶ raw parameters:", n);
29512
- let i = gk(n), a = bk(i);
29210
+ let i = $O(n), a = ek(i);
29513
29211
  if ($("fwh-navigate-mvp · coerced:", {
29514
29212
  url: a,
29515
29213
  sectionText: i.section_text ?? i.sectionText ?? i.section,
@@ -29575,8 +29273,8 @@ function Tk(e) {
29575
29273
  typeof window < "u" && window.scrollTo(0, 0);
29576
29274
  } catch {}
29577
29275
  let s = [], c = Date.now() + 12e3;
29578
- for (; Date.now() < c && (await new Promise((e) => setTimeout(e, 300)), s = Ck(), !(s.length >= 1)););
29579
- 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);
29580
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 = "";
29581
29279
  try {
29582
29280
  if (s.length > 0) {
@@ -29584,7 +29282,7 @@ function Tk(e) {
29584
29282
  for (let n of e) {
29585
29283
  let e = xr(null, n);
29586
29284
  if (e) {
29587
- let r = wk(e).substring(0, 800);
29285
+ let r = rk(e).substring(0, 800);
29588
29286
  r && t.push(`[Section: ${n}] ${r}`);
29589
29287
  }
29590
29288
  }
@@ -29612,34 +29310,34 @@ function Tk(e) {
29612
29310
  },
29613
29311
  "fwh-highlight-mvp": async (e) => {
29614
29312
  $("fwh-highlight-mvp ▶", e);
29615
- 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;
29616
29314
  if (typeof window < "u" && window.__fe_user_nav_during_speech) {
29617
29315
  let e = window.__fe_user_nav_during_speech, t = window.location.pathname;
29618
29316
  if (Date.now() - e.ts >= 3e4) window.__fe_user_nav_during_speech = null;
29619
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.`;
29620
29318
  }
29621
- Sk();
29319
+ tk();
29622
29320
  let i = ((e) => e && e.replace(/^\d+\.\s*/, "").replace(/^["']|["']$/g, "").trim())(r), a = xr(n || null, i || null);
29623
29321
  if (!a && i) {
29624
29322
  let e = Date.now() + 600;
29625
- 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);
29626
29324
  }
29627
29325
  if (!a) {
29628
29326
  $("fwh-highlight-mvp ✖ no element for:", i || n);
29629
- 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.";
29630
29328
  return `HIGHLIGHT_NOT_FOUND: "${i || n}" on the current page. ${t}`;
29631
29329
  }
29632
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.`;
29633
29331
  },
29634
29332
  "fwh-read-content-mvp": async (e) => {
29635
29333
  $("fwh-read-content-mvp ▶", e);
29636
- let t = gk(e), n = t?.section_text || t?.sectionText || "";
29334
+ let t = $O(e), n = t?.section_text || t?.sectionText || "";
29637
29335
  try {
29638
29336
  let e = "";
29639
29337
  if (n) {
29640
29338
  let t = xr(null, n);
29641
29339
  if (!t) return `Could not find section "${n}" on the page.`;
29642
- e = wk(t);
29340
+ e = rk(t);
29643
29341
  } else {
29644
29342
  let t = (document.querySelector("main") || document.querySelector("article") || document.querySelector("[role=\"main\"]") || document.querySelector("#content") || document.querySelector(".content") || document.body).cloneNode(!0);
29645
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();
@@ -29651,7 +29349,7 @@ function Tk(e) {
29651
29349
  },
29652
29350
  "fwh-page-content-mvp": async (e) => {
29653
29351
  $("fwh-page-content-mvp ▶", e);
29654
- let r = gk(e), i = r?.url || r?.page_url || "";
29352
+ let r = $O(e), i = r?.url || r?.page_url || "";
29655
29353
  if ($("fwh-page-content-mvp · url:", i, "siteId:", t, "apiBase:", n || "(empty)"), !i) return $("fwh-page-content-mvp ✖ missing url"), "Missing url parameter.";
29656
29354
  if (!t) return $("fwh-page-content-mvp ✖ no siteId"), "Site is not configured.";
29657
29355
  if (!n) return $("fwh-page-content-mvp ✖ no api base"), "API base URL is missing; cannot fetch page content.";
@@ -29683,7 +29381,7 @@ function Tk(e) {
29683
29381
  },
29684
29382
  "fwh-search-mvp": async (e) => {
29685
29383
  $("fwh-search-mvp ▶", e);
29686
- let r = gk(e).query;
29384
+ let r = $O(e).query;
29687
29385
  if (!r) return $("fwh-search-mvp ✖ missing query"), "Missing query parameter.";
29688
29386
  if (!t) return $("fwh-search-mvp ✖ no siteId"), "Search unavailable (no siteId configured).";
29689
29387
  if (!n) return $("fwh-search-mvp ✖ no api base"), "Search unavailable (no API base URL).";
@@ -29721,7 +29419,7 @@ function Tk(e) {
29721
29419
  "[class*='menu'] a",
29722
29420
  "[class*='header'] a"
29723
29421
  ];
29724
- if (JO((t) => {
29422
+ if (WO((t) => {
29725
29423
  for (let r of n) try {
29726
29424
  t.querySelectorAll(r).forEach((t) => {
29727
29425
  if (Hn(t)) return;
@@ -29729,7 +29427,7 @@ function Tk(e) {
29729
29427
  if (!r || !n || n === "#" || n.startsWith("javascript:")) return;
29730
29428
  try {
29731
29429
  let e = t.parentElement;
29732
- 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;
29733
29431
  } catch {}
29734
29432
  let i = r.toLowerCase() + "|" + n;
29735
29433
  e.has(i) || e.set(i, {
@@ -29740,7 +29438,7 @@ function Tk(e) {
29740
29438
  } catch {}
29741
29439
  t.querySelectorAll("select").forEach((t) => {
29742
29440
  if (Hn(t)) return;
29743
- let n = XO(t);
29441
+ let n = KO(t);
29744
29442
  /nav|menu|page|section|go to/i.test(n || t.name || t.id || "") && Array.from(t.options).forEach((r) => {
29745
29443
  if (!r.value || r.disabled) return;
29746
29444
  let i = r.text.trim();
@@ -29761,7 +29459,7 @@ function Tk(e) {
29761
29459
  "fwh-end-session-mvp": async () => ($("fwh-end-session-mvp ▶"), typeof e.requestEndSession == "function" && e.requestEndSession(), "Voice session is ending."),
29762
29460
  "fwh-get-current-page-mvp": async () => {
29763
29461
  if ($("fwh-get-current-page-mvp ▶"), typeof window > "u") return "Cannot determine current page (no browser context).";
29764
- 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();
29765
29463
  if ($("fwh-get-current-page-mvp ✓", {
29766
29464
  url: e,
29767
29465
  path: t,
@@ -29771,7 +29469,7 @@ function Tk(e) {
29771
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. ***`;
29772
29470
  },
29773
29471
  "fwh-list-forms-mvp": async () => {
29774
- let e = QO(), t = $O();
29472
+ let e = JO(), t = YO();
29775
29473
  $("fwh-list-forms-mvp ✓", `${e.length} field(s)`, `${t.length} button(s)`);
29776
29474
  let n = e.map((e) => ({
29777
29475
  ...e,
@@ -29783,66 +29481,37 @@ function Tk(e) {
29783
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."
29784
29482
  });
29785
29483
  },
29786
- "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.";
29787
29492
  try {
29788
- $("fwh-fill-form-mvp raw:", e), PO();
29789
- let t = _k(e);
29790
- if (!t.length && r) {
29791
- let e = r(), n = vk(e);
29792
- 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);
29793
- }
29794
- 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.";
29795
- let n = [];
29796
- for (let e of t) {
29797
- let t = e?.field_key, r = e?.value;
29798
- if (t == null || r == null) continue;
29799
- DO(`Filling ${String(t)}...`, { spinner: !0 });
29800
- let a = ZO(), o = (() => {
29801
- let e = ek(r);
29802
- ek(String(t));
29803
- let n = null, i = 0;
29804
- for (let r of a) {
29805
- if (r.tagName !== "SELECT" || !Array.from(r.options).find((t) => ek(t.text) === e || ek(t.value) === e)) continue;
29806
- let a = nk(r, String(t));
29807
- a >= i && (i = a, n = r);
29808
- }
29809
- return n && i >= 0 ? n : null;
29810
- })();
29811
- if (o) {
29812
- $("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));
29813
- continue;
29814
- }
29815
- let s = uk(a, String(t), r);
29816
- if (s.length) {
29817
- for (let [e, t] of s.entries()) FO(t), await VO(t), xk(t, r, { skipScroll: e > 0 }), IO(t), await KO(120);
29818
- i = s, n.push(String(t));
29819
- continue;
29820
- }
29821
- let c = pk(a, String(t));
29822
- 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)));
29823
- }
29824
- 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.";
29825
- let a = `OK_FILLED: ${n.join(", ")}`;
29826
- return $("fwh-fill-form-mvp ✓", a), DO("Form filled", {
29827
- spinner: !1,
29828
- icon: "✅",
29829
- duration: 1100
29830
- }), 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.`;
29831
29507
  } catch (e) {
29832
- let t = `FORM_ERROR: ${e?.message || String(e)}`;
29833
- return $("fwh-fill-form-mvp ✖", t), DO("Failed to fill form", {
29834
- spinner: !1,
29835
- icon: "⚠️",
29836
- duration: 1800
29837
- }), t;
29838
- } finally {
29839
- HO(), PO(), OO(700);
29508
+ return $("fwh-save-email-mvp ✖", e.message), `Failed to save email: ${e.message}`;
29840
29509
  }
29841
29510
  },
29842
29511
  "fwh-click-button-mvp": async (e) => {
29843
- 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();
29844
29513
  if ($("fwh-click-button-mvp ▶", n), !n) return "Missing button_text: pass the visible label, e.g. Conduct Audit.";
29845
- let r = hk(n, i);
29514
+ let r = QO(n, i);
29846
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.`;
29847
29516
  try {
29848
29517
  DO(`Clicking ${n}...`, { spinner: !0 });
@@ -29854,7 +29523,7 @@ function Tk(e) {
29854
29523
  } catch {
29855
29524
  r.scrollIntoView(!0);
29856
29525
  }
29857
- 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();
29858
29527
  let e = (r.textContent || r.value || r.getAttribute("aria-label") || "").trim().slice(0, 80) || "button", t = `OK_CLICK ${e}`;
29859
29528
  return $("fwh-click-button-mvp ✓", t), DO(`Clicked ${e}`, {
29860
29529
  spinner: !1,
@@ -29869,7 +29538,7 @@ function Tk(e) {
29869
29538
  duration: 1800
29870
29539
  }), t;
29871
29540
  } finally {
29872
- HO(), OO(700);
29541
+ zO(), OO(700);
29873
29542
  }
29874
29543
  }
29875
29544
  };
@@ -29885,7 +29554,7 @@ function Tk(e) {
29885
29554
  }
29886
29555
  //#endregion
29887
29556
  //#region src/utils/wrapVoiceToolsForLogging.js
29888
- function Ek(e) {
29557
+ function ak(e) {
29889
29558
  return !e || typeof e != "object" ? e : Object.fromEntries(Object.entries(e).map(([e, t]) => [e, async (n) => {
29890
29559
  let r = In();
29891
29560
  r ? console.log("[FlowEngage:voice-tool] ▶", e, n) : console.info(`[FlowEngage] voice tool » ${e}`);
@@ -29902,7 +29571,7 @@ function Ek(e) {
29902
29571
  }
29903
29572
  //#endregion
29904
29573
  //#region src/components/FlowEngageWidget.jsx
29905
- var Dk = {
29574
+ var ok = {
29906
29575
  blue: "#135bd8",
29907
29576
  red: "#ef334b",
29908
29577
  yellow: "#ffbd2e",
@@ -29910,7 +29579,7 @@ var Dk = {
29910
29579
  highlight: "rgba(255,255,255,0.9)",
29911
29580
  green: "#10b981"
29912
29581
  };
29913
- function Ok(e) {
29582
+ function sk(e) {
29914
29583
  if (!Array.isArray(e) || e.length < 2) return "linear-gradient(145deg, #dce8f022 0%, #e8dff522 45%, #f5e0e022 100%), #f7f8fa";
29915
29584
  let [t, n, r] = e;
29916
29585
  return e.length >= 3 && r ? [
@@ -29924,12 +29593,12 @@ function Ok(e) {
29924
29593
  "#f7f8fa"
29925
29594
  ].join(", ");
29926
29595
  }
29927
- function kk(e) {
29596
+ function ck(e) {
29928
29597
  if (!e || typeof e != "string") return "#1a1a1a";
29929
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;
29930
29599
  return .2126 * o(r) + .7152 * o(i) + .0722 * o(a) > .179 ? "#1a1a1a" : "#ffffff";
29931
29600
  }
29932
- function Ak(t) {
29601
+ function lk(t) {
29933
29602
  let [n, r] = e.useState(null), i = typeof t == "string" ? t.trim() : "";
29934
29603
  return e.useEffect(() => {
29935
29604
  if (!i) {
@@ -29947,8 +29616,8 @@ function Ak(t) {
29947
29616
  };
29948
29617
  }, [i]), n;
29949
29618
  }
29950
- function jk({ logo: t, style: n }) {
29951
- let r = Ak(typeof t == "string" ? t : null);
29619
+ function uk({ logo: t, style: n }) {
29620
+ let r = lk(typeof t == "string" ? t : null);
29952
29621
  if (!t) return null;
29953
29622
  if (typeof t == "string") return r ? /* @__PURE__ */ g("img", {
29954
29623
  src: r,
@@ -29973,7 +29642,7 @@ function jk({ logo: t, style: n }) {
29973
29642
  children: i
29974
29643
  }) : null;
29975
29644
  }
29976
- function Mk({ title: e }) {
29645
+ function dk({ title: e }) {
29977
29646
  return /* @__PURE__ */ g("div", {
29978
29647
  style: {
29979
29648
  width: "100%",
@@ -29991,18 +29660,18 @@ function Mk({ title: e }) {
29991
29660
  children: String(e || "FE").split(/\s+/).filter(Boolean).slice(0, 2).map((e) => e[0]?.toUpperCase() || "").join("") || "FE"
29992
29661
  });
29993
29662
  }
29994
- function Nk(e, t) {
29663
+ function fk(e, t) {
29995
29664
  let n = (t || "").trim();
29996
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;
29997
29666
  }
29998
- function Pk({ orbColors: e, ...t }) {
29667
+ function pk({ orbColors: e, ...t }) {
29999
29668
  return /* @__PURE__ */ g(pO, {
30000
29669
  colors: e,
30001
29670
  ...t
30002
29671
  });
30003
29672
  }
30004
- function Fk({ copy: e, orbColors: t, primaryColor: n, onYes: r, onLater: i, isMobile: a, isClosing: o }) {
30005
- 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", {
30006
29675
  style: {
30007
29676
  display: "flex",
30008
29677
  alignItems: a ? "flex-end" : "center",
@@ -30128,7 +29797,7 @@ function Fk({ copy: e, orbColors: t, primaryColor: n, onYes: r, onLater: i, isMo
30128
29797
  delay: 0
30129
29798
  },
30130
29799
  style: { flexShrink: 0 },
30131
- children: /* @__PURE__ */ g(Pk, {
29800
+ children: /* @__PURE__ */ g(pk, {
30132
29801
  size: l,
30133
29802
  orbColors: t
30134
29803
  })
@@ -30160,8 +29829,8 @@ function Fk({ copy: e, orbColors: t, primaryColor: n, onYes: r, onLater: i, isMo
30160
29829
  children: u
30161
29830
  })] });
30162
29831
  }
30163
- function Ik({ copy: e, orbColors: t, primaryColor: n, onVoice: r, onText: i, onClose: a, isMobile: o, isClosing: s }) {
30164
- 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);
30165
29834
  return /* @__PURE__ */ _(Pm.div, {
30166
29835
  initial: {
30167
29836
  scale: 50 / 350,
@@ -30232,7 +29901,7 @@ function Ik({ copy: e, orbColors: t, primaryColor: n, onVoice: r, onText: i, onC
30232
29901
  children: /* @__PURE__ */ g("polyline", { points: "6 9 12 15 18 9" })
30233
29902
  })
30234
29903
  }),
30235
- /* @__PURE__ */ g(Pk, {
29904
+ /* @__PURE__ */ g(pk, {
30236
29905
  size: 72,
30237
29906
  orbColors: t
30238
29907
  }),
@@ -30301,17 +29970,21 @@ function Ik({ copy: e, orbColors: t, primaryColor: n, onVoice: r, onText: i, onC
30301
29970
  ]
30302
29971
  });
30303
29972
  }
30304
- 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 }) {
30305
29974
  c(() => (console.log("[FlowEngage:VoiceDebug] 🔵 VoiceMode MOUNTED"), () => console.log("[FlowEngage:VoiceDebug] 🔴 VoiceMode UNMOUNTED")), []);
30306
- 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") => {
30307
29980
  console.warn("[FlowEngage:VoiceDebug] 🛑 requestSessionShutdown called", {
30308
29981
  destination: e,
30309
29982
  stack: (/* @__PURE__ */ Error()).stack?.split("\n").slice(1, 4).join(" | ")
30310
- }), E.current = e, re.current = !0, queueMicrotask(() => {
30311
- ee.current || (ee.current = !0, T.current?.());
29983
+ }), le.current = e, ce.current = !0, queueMicrotask(() => {
29984
+ oe.current || (oe.current = !0, ae.current?.());
30312
29985
  });
30313
- }, [l]), he = o(async (e) => {
30314
- re.current = !0;
29986
+ }, [l]), Te = o(async (e) => {
29987
+ ce.current = !0;
30315
29988
  try {
30316
29989
  Bn();
30317
29990
  } catch {}
@@ -30319,9 +29992,9 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30319
29992
  Ve(i);
30320
29993
  } catch {}
30321
29994
  try {
30322
- await C.current?.endSession?.();
29995
+ await E.current?.endSession?.();
30323
29996
  } catch {}
30324
- let t = ie.current, n = ae.current;
29997
+ let t = ue.current, n = de.current;
30325
29998
  if (t && s && a) {
30326
29999
  let e = n ? Math.round((Date.now() - n) / 1e3) : 0;
30327
30000
  fetch(`${a}/api/voice/save-chat-recording`, {
@@ -30335,7 +30008,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30335
30008
  })
30336
30009
  }).catch((e) => console.warn("[FlowEngage] save-chat-recording failed:", e.message));
30337
30010
  }
30338
- 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 {
30339
30012
  je(i);
30340
30013
  } catch {}
30341
30014
  typeof u == "function" && await u(l.current), e?.();
@@ -30346,26 +30019,26 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30346
30019
  s,
30347
30020
  a
30348
30021
  ]);
30349
- return T.current = () => he(E.current === "chat" ? t : n), c(() => {
30350
- te.current = y;
30351
- }, [y]), c(() => {
30352
- d && me("chat");
30022
+ ae.current = () => Te(le.current === "chat" ? t : n), c(() => {
30023
+ D.current = b;
30024
+ }, [b]), c(() => {
30025
+ d && we("chat");
30353
30026
  }, [d]), c(() => {
30354
30027
  let e = !1, o = null, c = null, d = null;
30355
30028
  return (async () => {
30356
30029
  if (!r) {
30357
- v("error");
30030
+ y("error");
30358
30031
  return;
30359
30032
  }
30360
30033
  try {
30361
30034
  if ((await navigator.mediaDevices.getUserMedia({ audio: !0 })).getTracks().forEach((e) => e.stop()), e) return;
30362
- 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: () => {
30363
30036
  if (i && l.current.length > 0) try {
30364
30037
  let e = SO(l.current);
30365
30038
  e && O(i, e);
30366
30039
  } catch {}
30367
30040
  if (!or()) {
30368
- let e = ie.current, t = ae.current;
30041
+ let e = ue.current, t = de.current;
30369
30042
  if (e && s && a) try {
30370
30043
  let n = t ? Math.round((Date.now() - t) / 1e3) : 0, r = JSON.stringify({
30371
30044
  chatId: s,
@@ -30378,25 +30051,26 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30378
30051
  headers: { "Content-Type": "application/json" },
30379
30052
  body: r,
30380
30053
  keepalive: !0
30381
- }).catch(() => {}), ie.current = null, ae.current = null;
30054
+ }).catch(() => {}), ue.current = null, de.current = null;
30382
30055
  } catch {}
30383
30056
  }
30384
30057
  Ne();
30385
30058
  } });
30386
- let t = Ek(Tk({
30059
+ let t = ak(ik({
30387
30060
  siteId: i || null,
30388
30061
  apiBaseUrl: a || null,
30389
- getLastUserVoiceText: () => w.current,
30062
+ chatId: s || null,
30063
+ getLastUserVoiceText: () => ie.current,
30390
30064
  requestEndSession: () => {
30391
- se.current = !0;
30065
+ me.current = !0;
30392
30066
  }
30393
- })), 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;
30394
30068
  try {
30395
30069
  let e = await fetch(`${a}/api/voice/signed-url?siteId=${encodeURIComponent(i || "")}`, {
30396
30070
  method: "GET",
30397
30071
  headers: { "Content-Type": "application/json" }
30398
30072
  });
30399
- 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");
30400
30074
  else if (e.status === 429) {
30401
30075
  let t = await e.json().catch(() => ({}));
30402
30076
  throw Error(t.message || "Too many voice sessions started. Please wait a minute before trying again.");
@@ -30409,51 +30083,51 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30409
30083
  clientTools: t,
30410
30084
  connectionType: "websocket",
30411
30085
  minSpeechDurationMs: 50,
30412
- ...x ? { signedUrl: x } : { agentId: r }
30413
- }, T = (h.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()), oe = "";
30414
- g && g.includes("|") && (oe = g.split("|").map((e) => e.trim()).filter(Boolean).reduce((e, t) => e.length <= t.length ? e : t));
30415
- let he = oe || T || "this page";
30416
- if (x) if (m) {
30417
- 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;
30418
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})`);
30419
30093
  } else if (u) S.overrides = { agent: { firstMessage: "I'm still here. Go ahead!" } };
30420
30094
  else {
30421
30095
  let e = f || "";
30422
- 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}`);
30423
30097
  }
30424
30098
  else u && (S.overrides = { agent: { firstMessage: "" } });
30425
- 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({
30426
30100
  ...S,
30427
30101
  onConnect: ({ conversationId: e }) => {
30428
- 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);
30429
30103
  },
30430
30104
  onUnhandledClientToolCall: (e) => console.error("[FlowEngage] Unhandled tool:", e?.tool_name),
30431
30105
  onModeChange: ({ mode: t }) => {
30432
30106
  if (!e) {
30433
30107
  if (t === "speaking") {
30434
- 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);
30435
30109
  return;
30436
30110
  }
30437
- if (ce.current = "listening", se.current) {
30438
- se.current = !1, me();
30111
+ if (he.current = "listening", me.current) {
30112
+ me.current = !1, we();
30439
30113
  return;
30440
30114
  }
30441
- if (_e && !ge) {
30442
- ge = !0;
30115
+ if (ne && !te) {
30116
+ te = !0;
30443
30117
  try {
30444
- C.current?.sendContextualUpdate?.(_e);
30118
+ E.current?.sendContextualUpdate?.(ne);
30445
30119
  } catch {}
30446
30120
  }
30447
- if (ye && !ve) {
30448
- ve = !0;
30121
+ if (ae && !re) {
30122
+ re = !0;
30449
30123
  try {
30450
- C.current?.sendContextualUpdate?.(ye);
30124
+ E.current?.sendContextualUpdate?.(ae);
30451
30125
  } catch {}
30452
30126
  }
30453
- fe.current && clearTimeout(fe.current), fe.current = setTimeout(() => {
30454
- 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(() => {
30455
- if (!e && ce.current === "listening" && !te.current) try {
30456
- 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.");
30457
30131
  } catch {}
30458
30132
  }, 15e3))));
30459
30133
  }, 1200);
@@ -30464,10 +30138,22 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30464
30138
  let n = t.role === "user" ? "user" : "bot", r = t.message || t.text || t.content || "";
30465
30139
  if (r) {
30466
30140
  if (n === "user") {
30467
- 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);
30468
30142
  try {
30469
30143
  Bn();
30470
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
+ }
30471
30157
  }
30472
30158
  if (l.current = [...l.current, {
30473
30159
  sender: n,
@@ -30477,51 +30163,51 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30477
30163
  let e = SO(l.current);
30478
30164
  e && O(i, e);
30479
30165
  } catch {}
30480
- if (Nk(n, r)) {
30481
- se.current = !0;
30166
+ if (fk(n, r)) {
30167
+ me.current = !0;
30482
30168
  return;
30483
30169
  }
30484
- 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 {
30485
- 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.");
30486
30172
  } catch {}
30487
- else D.current >= 5 && me("minimized");
30173
+ else pe.current >= 5 && we("minimized");
30488
30174
  }
30489
30175
  },
30490
30176
  onError: (t) => {
30491
- if (!e && !re.current && !ne.current && !Re()) {
30492
- 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", {
30493
30179
  message: t?.message,
30494
30180
  name: t?.name,
30495
30181
  raw: t
30496
30182
  });
30497
30183
  try {
30498
- C.current?.setMicMuted?.(!0);
30184
+ E.current?.setMicMuted?.(!0);
30499
30185
  } catch {}
30500
- b(!0), v("error"), me("chat");
30186
+ x(!0), y("error"), we("chat");
30501
30187
  }
30502
30188
  },
30503
30189
  onDisconnect: (t) => {
30504
- if (e || re.current || ne.current || Re()) return;
30190
+ if (e || ce.current || se.current || Re()) return;
30505
30191
  let n = l.current?.length || 0;
30506
30192
  console.warn("[FlowEngageVoiceCall] session:disconnected", {
30507
30193
  historyCount: n,
30508
30194
  reason: t?.reason,
30509
30195
  closeCode: t?.context?.code,
30510
30196
  closeReason: t?.context?.reason || t?.message,
30511
- lastUserText: w.current || "",
30512
- wasMuted: te.current
30513
- }), ne.current = !0;
30197
+ lastUserText: ie.current || "",
30198
+ wasMuted: D.current
30199
+ }), se.current = !0;
30514
30200
  try {
30515
- C.current?.setMicMuted?.(!0);
30201
+ E.current?.setMicMuted?.(!0);
30516
30202
  } catch {}
30517
- b(!0), me("chat");
30203
+ x(!0), we("chat");
30518
30204
  }
30519
30205
  });
30520
30206
  if (e) {
30521
- 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(() => {});
30522
30208
  return;
30523
30209
  }
30524
- o = be, C.current = be, v("listening");
30210
+ o = fe, E.current = fe, y("listening");
30525
30211
  try {
30526
30212
  let e = typeof window < "u" ? window.location.href : "", r = "[]";
30527
30213
  try {
@@ -30533,7 +30219,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30533
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(" | "));
30534
30220
  } catch {}
30535
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` : "";
30536
- 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.`);
30537
30223
  } catch {}
30538
30224
  if (typeof window < "u") {
30539
30225
  let t = window.location.pathname, n = () => {
@@ -30562,7 +30248,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30562
30248
  ts: Date.now()
30563
30249
  });
30564
30250
  try {
30565
- 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.]`);
30566
30252
  } catch {}
30567
30253
  };
30568
30254
  c = window.history.pushState.bind(window.history), window.history.pushState = (...e) => {
@@ -30570,7 +30256,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30570
30256
  }, d = () => setTimeout(n, 50), window.addEventListener("popstate", d);
30571
30257
  }
30572
30258
  } catch (r) {
30573
- 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(() => {
30574
30260
  e || t?.();
30575
30261
  }, 0)));
30576
30262
  }
@@ -30579,15 +30265,15 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30579
30265
  agentId: r,
30580
30266
  siteId: i,
30581
30267
  apiBaseUrl: a
30582
- }), e = !0, re.current = !0;
30268
+ }), e = !0, ce.current = !0;
30583
30269
  try {
30584
30270
  Bn();
30585
30271
  } catch {}
30586
30272
  if (i) try {
30587
30273
  Ve(i);
30588
30274
  } catch {}
30589
- 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);
30590
- 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;
30591
30277
  if (t?.endSession?.().catch(() => {}), n && s && a) {
30592
30278
  let e = f ? Math.round((Date.now() - f) / 1e3) : 0, t = JSON.stringify({
30593
30279
  chatId: s,
@@ -30600,7 +30286,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30600
30286
  headers: { "Content-Type": "application/json" },
30601
30287
  body: t,
30602
30288
  keepalive: !0
30603
- }).catch(() => {}), ie.current = null, ae.current = null;
30289
+ }).catch(() => {}), ue.current = null, de.current = null;
30604
30290
  }
30605
30291
  typeof u == "function" && l.current.length > 0 && u(l.current).catch?.(() => {});
30606
30292
  };
@@ -30608,16 +30294,50 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30608
30294
  r,
30609
30295
  i,
30610
30296
  a,
30611
- me
30297
+ we
30612
30298
  ]), c(() => {
30613
- if (!x) return;
30299
+ if (!S) return;
30614
30300
  let e = (e) => {
30615
30301
  let t = e.composedPath?.()?.[0] || e.target;
30616
- oe.current && !oe.current.contains(t) && S(!1);
30302
+ fe.current && !fe.current.contains(t) && C(!1);
30617
30303
  };
30618
30304
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
30619
- }, [x]), /* @__PURE__ */ _("div", {
30620
- 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,
30621
30341
  style: {
30622
30342
  position: "relative",
30623
30343
  display: "flex",
@@ -30630,7 +30350,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30630
30350
  /* @__PURE__ */ _("div", {
30631
30351
  style: { position: "relative" },
30632
30352
  children: [
30633
- h === "listening" && !y && /* @__PURE__ */ g("span", {
30353
+ v === "listening" && !b && /* @__PURE__ */ g("span", {
30634
30354
  style: {
30635
30355
  position: "absolute",
30636
30356
  right: "100%",
@@ -30646,7 +30366,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30646
30366
  },
30647
30367
  children: "Listening..."
30648
30368
  }),
30649
- y && /* @__PURE__ */ g("span", {
30369
+ b && /* @__PURE__ */ g("span", {
30650
30370
  style: {
30651
30371
  position: "absolute",
30652
30372
  right: "100%",
@@ -30662,15 +30382,15 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30662
30382
  },
30663
30383
  children: "Muted"
30664
30384
  }),
30665
- /* @__PURE__ */ g(Pk, {
30385
+ /* @__PURE__ */ g(pk, {
30666
30386
  size: 72,
30667
- voiceState: h,
30668
- isMuted: y,
30387
+ voiceState: v,
30388
+ isMuted: b,
30669
30389
  orbColors: e
30670
30390
  })
30671
30391
  ]
30672
30392
  }),
30673
- h === "error" && /* @__PURE__ */ g("span", {
30393
+ v === "error" && /* @__PURE__ */ g("span", {
30674
30394
  style: {
30675
30395
  color: "#f87171",
30676
30396
  fontSize: "13px",
@@ -30678,6 +30398,82 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30678
30398
  },
30679
30399
  children: "Could not start voice session."
30680
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
+ }),
30681
30477
  /* @__PURE__ */ _("div", {
30682
30478
  style: {
30683
30479
  display: "flex",
@@ -30686,38 +30482,38 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30686
30482
  },
30687
30483
  children: [/* @__PURE__ */ g("button", {
30688
30484
  onClick: async () => {
30689
- if (C.current) try {
30690
- if (y) {
30691
- 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);
30692
30488
  try {
30693
- 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.");
30694
30490
  } catch {}
30695
30491
  } else {
30696
- D.current = 0, await C.current.setMicMuted?.(!0), b(!0);
30492
+ pe.current = 0, await E.current.setMicMuted?.(!0), x(!0);
30697
30493
  try {
30698
- 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.");
30699
30495
  } catch {}
30700
30496
  }
30701
30497
  } catch {}
30702
30498
  },
30703
- title: y ? "Unmute" : "Mute",
30499
+ title: b ? "Unmute" : "Mute",
30704
30500
  style: {
30705
30501
  width: "24px",
30706
30502
  height: "24px",
30707
30503
  borderRadius: "50%",
30708
- background: y ? "#7f1d1d" : "#1f2937",
30709
- 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",
30710
30506
  display: "flex",
30711
30507
  alignItems: "center",
30712
30508
  justifyContent: "center",
30713
30509
  cursor: "pointer",
30714
- color: y ? "#f87171" : "white",
30510
+ color: b ? "#f87171" : "white",
30715
30511
  transition: "all 0.2s ease",
30716
30512
  boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30717
30513
  padding: 0,
30718
30514
  flexShrink: 0
30719
30515
  },
30720
- children: y ? /* @__PURE__ */ _("svg", {
30516
+ children: b ? /* @__PURE__ */ _("svg", {
30721
30517
  width: "16",
30722
30518
  height: "16",
30723
30519
  viewBox: "0 0 24 24",
@@ -30753,7 +30549,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30753
30549
  color: "currentColor"
30754
30550
  })
30755
30551
  }), /* @__PURE__ */ g("button", {
30756
- onClick: () => S((e) => !e),
30552
+ onClick: () => C((e) => !e),
30757
30553
  style: {
30758
30554
  width: "24px",
30759
30555
  height: "24px",
@@ -30776,7 +30572,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30776
30572
  })
30777
30573
  })]
30778
30574
  }),
30779
- x && /* @__PURE__ */ _("div", {
30575
+ S && /* @__PURE__ */ _("div", {
30780
30576
  style: {
30781
30577
  position: "absolute",
30782
30578
  bottom: 0,
@@ -30794,7 +30590,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30794
30590
  children: [
30795
30591
  /* @__PURE__ */ _("button", {
30796
30592
  onClick: () => {
30797
- S(!1), E.current = "chat", he(t);
30593
+ C(!1), le.current = "chat", Te(t);
30798
30594
  },
30799
30595
  style: {
30800
30596
  display: "flex",
@@ -30823,7 +30619,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30823
30619
  }),
30824
30620
  /* @__PURE__ */ _("button", {
30825
30621
  onClick: () => {
30826
- S(!1), E.current = "minimized", he(n);
30622
+ C(!1), le.current = "minimized", Te(n);
30827
30623
  },
30828
30624
  style: {
30829
30625
  display: "flex",
@@ -30851,7 +30647,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30851
30647
  children: [/* @__PURE__ */ g(LD, {}), "End Conversation"]
30852
30648
  }),
30853
30649
  /* @__PURE__ */ g("button", {
30854
- onClick: () => S(!1),
30650
+ onClick: () => C(!1),
30855
30651
  style: {
30856
30652
  position: "absolute",
30857
30653
  bottom: "8px",
@@ -30900,7 +30696,7 @@ function Lk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30900
30696
  ]
30901
30697
  });
30902
30698
  }
30903
- function Rk({ orbColors: e }) {
30699
+ function _k({ orbColors: e }) {
30904
30700
  let t = Array.isArray(e) && e.length > 0 ? e : [
30905
30701
  "#135bd8",
30906
30702
  "#ef334b",
@@ -30919,7 +30715,7 @@ function Rk({ orbColors: e }) {
30919
30715
  `.replace(/\s+/g, " ").trim()
30920
30716
  } });
30921
30717
  }
30922
- var zk = () => /* @__PURE__ */ g("div", {
30718
+ var vk = () => /* @__PURE__ */ g("div", {
30923
30719
  style: {
30924
30720
  display: "flex",
30925
30721
  marginBottom: "12px",
@@ -30949,7 +30745,7 @@ var zk = () => /* @__PURE__ */ g("div", {
30949
30745
  } }, e))
30950
30746
  })
30951
30747
  });
30952
- 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 }) {
30953
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);
30954
30750
  c(() => {
30955
30751
  if (!s) return;
@@ -31089,7 +30885,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31089
30885
  justifyContent: "center",
31090
30886
  height: "40px"
31091
30887
  },
31092
- children: i ? /* @__PURE__ */ g(jk, {
30888
+ children: i ? /* @__PURE__ */ g(uk, {
31093
30889
  logo: i,
31094
30890
  style: {
31095
30891
  height: "34px",
@@ -31102,7 +30898,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31102
30898
  height: "40px",
31103
30899
  flexShrink: 0
31104
30900
  },
31105
- children: /* @__PURE__ */ g(Mk, { title: e.chatTitle })
30901
+ children: /* @__PURE__ */ g(dk, { title: e.chatTitle })
31106
30902
  })
31107
30903
  }), o && /* @__PURE__ */ g("div", {
31108
30904
  style: {
@@ -31533,11 +31329,11 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31533
31329
  isLoading: T,
31534
31330
  isAgentTyping: d,
31535
31331
  setReplyContext: de,
31536
- TypingDots: zk,
31332
+ TypingDots: vk,
31537
31333
  primaryColor: n,
31538
31334
  agentHeadshot: y,
31539
31335
  agentDisplayName: v || b,
31540
- botAvatarNode: /* @__PURE__ */ g(Rk, { orbColors: t })
31336
+ botAvatarNode: /* @__PURE__ */ g(_k, { orbColors: t })
31541
31337
  }) : Me ? /* @__PURE__ */ _("div", {
31542
31338
  style: {
31543
31339
  flex: 1,
@@ -31578,7 +31374,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31578
31374
  padding: "28px 24px"
31579
31375
  },
31580
31376
  children: [
31581
- /* @__PURE__ */ g(Pk, {
31377
+ /* @__PURE__ */ g(pk, {
31582
31378
  size: 94,
31583
31379
  orbColors: t
31584
31380
  }),
@@ -31743,7 +31539,7 @@ function Bk({ copy: e, orbColors: t, primaryColor: n, chatBgGradient: r, logo: i
31743
31539
  ]
31744
31540
  });
31745
31541
  }
31746
- function Vk() {
31542
+ function bk() {
31747
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();
31748
31544
  c(() => {
31749
31545
  try {
@@ -31751,7 +31547,13 @@ function Vk() {
31751
31547
  } catch {}
31752
31548
  }, []), c(() => {
31753
31549
  Ee && M !== "voice_mode" && M !== "text_chat" && M !== "call_screen" && (ue?.(!1), dt("text_chat"));
31754
- }, [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]);
31755
31557
  let Oe = t?.widgetSettings || {}, ke = n?.widgetSettings || {}, O = {
31756
31558
  ...Oe.branding || {},
31757
31559
  ...ke.branding || {}
@@ -31765,7 +31567,7 @@ function Vk() {
31765
31567
  small: 50,
31766
31568
  medium: 64,
31767
31569
  large: 80
31768
- }, 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) => ({
31769
31571
  id: e.key || `qr-${t}`,
31770
31572
  label: e.label,
31771
31573
  message: e.label,
@@ -32054,7 +31856,7 @@ function Vk() {
32054
31856
  onWheel: (e) => e.stopPropagation(),
32055
31857
  onTouchMove: (e) => e.stopPropagation(),
32056
31858
  children: [
32057
- M === "entry_prompt" && /* @__PURE__ */ g(Fk, {
31859
+ M === "entry_prompt" && /* @__PURE__ */ g(mk, {
32058
31860
  copy: A,
32059
31861
  orbColors: Ie,
32060
31862
  primaryColor: Re,
@@ -32137,13 +31939,13 @@ function Vk() {
32137
31939
  children: ee === "connected" ? `${qt(xt)} with ${ot}` : `Tap to return to ${ot}`
32138
31940
  })]
32139
31941
  })]
32140
- }), /* @__PURE__ */ g(Pk, {
31942
+ }), /* @__PURE__ */ g(pk, {
32141
31943
  size: Be,
32142
31944
  orbColors: Ie,
32143
31945
  onClick: T ? Ht : Fe ? Zt : $t
32144
31946
  })]
32145
31947
  }),
32146
- M === "connection_modal" && /* @__PURE__ */ g(Ik, {
31948
+ M === "connection_modal" && /* @__PURE__ */ g(hk, {
32147
31949
  copy: A,
32148
31950
  orbColors: Ie,
32149
31951
  primaryColor: Re,
@@ -32153,7 +31955,7 @@ function Vk() {
32153
31955
  isMobile: Rt,
32154
31956
  isClosing: Nt
32155
31957
  }),
32156
- M === "voice_mode" && /* @__PURE__ */ g(Lk, {
31958
+ M === "voice_mode" && /* @__PURE__ */ g(gk, {
32157
31959
  orbColors: Ie,
32158
31960
  onEnterChat: $t,
32159
31961
  onEndChat: en,
@@ -32164,7 +31966,8 @@ function Vk() {
32164
31966
  historyRef: ae,
32165
31967
  onMessageSync: oe,
32166
31968
  voiceEndCounter: De,
32167
- websiteName: t?.websiteName
31969
+ websiteName: t?.websiteName,
31970
+ visitorEmail: h
32168
31971
  }, "voice"),
32169
31972
  M === "call_screen" && /* @__PURE__ */ g(bO, {
32170
31973
  incomingCall: w,
@@ -32185,7 +31988,7 @@ function Vk() {
32185
31988
  orbColors: Ie,
32186
31989
  chatHistory: r
32187
31990
  }),
32188
- M === "text_chat" && /* @__PURE__ */ g(Bk, {
31991
+ M === "text_chat" && /* @__PURE__ */ g(yk, {
32189
31992
  isClosing: Nt,
32190
31993
  copy: A,
32191
31994
  orbColors: Ie,
@@ -32251,7 +32054,7 @@ function Vk() {
32251
32054
  }
32252
32055
  //#endregion
32253
32056
  //#region src/components/ErrorBoundary.jsx
32254
- var Hk = class extends e.Component {
32057
+ var xk = class extends e.Component {
32255
32058
  constructor(e) {
32256
32059
  super(e), this.state = { hasError: !1 };
32257
32060
  }
@@ -32266,4 +32069,4 @@ var Hk = class extends e.Component {
32266
32069
  }
32267
32070
  };
32268
32071
  //#endregion
32269
- 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 };