@flowengage/react-chatbot 6.0.17 → 6.0.19

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.
@@ -2119,13 +2119,11 @@ function er() {
2119
2119
  if (window.__sveltekit_data || document.querySelector("[data-sveltekit-hydrate]")) return "sveltekit";
2120
2120
  if (document.querySelector("[data-astro-transition]")) return "astro";
2121
2121
  if (window.__vite_plugin_react_preamble_installed__) return "vite-react-spa";
2122
- let e = Array.from(document.body.children).filter((e) => {
2123
- let t = e.tagName?.toUpperCase();
2124
- return !(t === "SCRIPT" || t === "NOSCRIPT" || t === "LINK" || t === "STYLE" || e.id === "flowengage-root");
2125
- });
2126
- if (e.length === 1) {
2127
- let t = e[0], n = !!t.querySelector("[data-reactroot]") || !!t._reactRootContainer, r = Object.keys(t).some((e) => e.startsWith("__reactFiber$") || e.startsWith("__reactContainer$"));
2128
- if (n || r || t.__vue_app__) return "generic-spa";
2122
+ let e = Array.from(document.body.children);
2123
+ for (let t of e) {
2124
+ if (t.id === "flowengage-root") continue;
2125
+ let e = t.tagName?.toUpperCase();
2126
+ if (!(e === "SCRIPT" || e === "NOSCRIPT" || e === "LINK" || e === "STYLE") && (t.querySelector?.("[data-reactroot]") || t._reactRootContainer || t.__vue_app__ || !(Array.from(t.childNodes).filter((e) => e.nodeType === 3).map((e) => e.textContent.trim()).join("").length > 200) && Object.getOwnPropertyNames(t).some((e) => e.startsWith("__reactFiber$") || e.startsWith("__reactContainer$")))) return "generic-spa";
2129
2127
  }
2130
2128
  return null;
2131
2129
  }
@@ -3359,7 +3357,10 @@ function Rr({ siteId: e, config: t, children: n, language: r = "en" }) {
3359
3357
  }), await Rt({
3360
3358
  ...r,
3361
3359
  callId: r.callId || O.callId
3362
- })), await k.current.acceptCall(O.callId, y), mt.current = O.callId, Je(O.callId), Xe((e) => e === "connected" || j.current ? "connected" : "connecting"), Ue(null), w(!0);
3360
+ })), await k.current.acceptCall(O.callId, y), at.current?.emit("call:accepted", {
3361
+ callId: O.callId,
3362
+ chatId: y
3363
+ }), mt.current = O.callId, Je(O.callId), Xe((e) => e === "connected" || j.current ? "connected" : "connecting"), Ue(null), w(!0);
3363
3364
  } catch (e) {
3364
3365
  if (ht.current = null, Pt("accept_call_failed"), e?.status === 404 || e?.status === 409 || e?.status === 422) {
3365
3366
  nt(Pr(e, "This visitor call is no longer available."));
@@ -3382,9 +3383,14 @@ function Rr({ siteId: e, config: t, children: n, language: r = "en" }) {
3382
3383
  Pt("reject_call_without_server_context");
3383
3384
  return;
3384
3385
  }
3385
- Mt(), jt();
3386
+ let e = O.callId;
3387
+ Mt(), jt(), at.current?.emit("call:rejected", {
3388
+ callId: e,
3389
+ chatId: y,
3390
+ reason: "visitor_declined"
3391
+ });
3386
3392
  try {
3387
- await k.current.rejectCall(O.callId, y);
3393
+ await k.current.rejectCall(e, y);
3388
3394
  } catch (e) {
3389
3395
  nt(Pr(e, "We couldn't decline the call cleanly."));
3390
3396
  } finally {
@@ -29414,6 +29420,11 @@ function Ck(e) {
29414
29420
  flowengage_highlight: async (e) => {
29415
29421
  $("flowengage_highlight ▶", e);
29416
29422
  let t = mk(e), n = t?.section_id || t?.sectionId, r = t?.section_text || t?.sectionText;
29423
+ if (typeof window < "u" && window.__fe_user_nav_during_speech) {
29424
+ let e = window.__fe_user_nav_during_speech, t = window.location.pathname;
29425
+ if (e.toPath === t && Date.now() - e.ts < 3e4) return window.__fe_user_nav_during_speech = null, $("flowengage_highlight ✖ blocked — user navigated during speech", e), `NAV_CHANGED: The visitor navigated from "${e.fromPageName}" to "${e.toPageName}" while you were speaking. DO NOT highlight anything yet. Ask the visitor: "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?" Only call flowengage_highlight after the visitor confirms they want to explore this page.`;
29426
+ window.__fe_user_nav_during_speech = null;
29427
+ }
29417
29428
  xk();
29418
29429
  let i = hr(n || null, r || null);
29419
29430
  if (!i && r) {
@@ -30134,7 +30145,7 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30134
30145
  let v = {
30135
30146
  clientTools: t,
30136
30147
  connectionType: "websocket",
30137
- minSpeechDurationMs: 100,
30148
+ minSpeechDurationMs: 50,
30138
30149
  ..._ ? { signedUrl: _ } : { agentId: r }
30139
30150
  }, b = (p.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()), x = "";
30140
30151
  m && m.includes("|") && (x = m.split("|").map((e) => e.trim()).filter(Boolean).reduce((e, t) => e.length <= t.length ? e : t));
@@ -30245,13 +30256,25 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30245
30256
  t = n;
30246
30257
  return;
30247
30258
  }
30259
+ let r = t;
30248
30260
  t = n;
30249
- let r = window.location.href, i = typeof document < "u" ? document.title : "", a = typeof document < "u" ? Array.from(document.querySelectorAll("h1, h2, h3, h4")).filter((e) => !e.closest("#flowengage-root, .flowengage-shell")).map((e) => ({
30261
+ let i = window.location.href, a = typeof document < "u" ? document.title : "", o = typeof document < "u" ? Array.from(document.querySelectorAll("h1, h2, h3, h4")).filter((e) => !e.closest("#flowengage-root, .flowengage-shell")).map((e) => ({
30250
30262
  tag: e.tagName,
30251
30263
  text: e.textContent.trim()
30252
30264
  })).filter((e) => e.text.length > 0 && e.text.length < 200).slice(0, 20) : [];
30253
30265
  try {
30254
- S.current?.sendContextualUpdate?.(`PAGE CHANGED — visitor navigated manually. Current URL is now: ${r}. Page title: "${i}". Sections on this page: ${JSON.stringify(a)}. When the visitor asks about "this page", "current page", or "what page am I on", refer to this new URL — not any previously mentioned page.`);
30266
+ SD();
30267
+ } catch {}
30268
+ let s = (e) => (e.split("/").filter(Boolean).pop() || "").replace(/[-_]/g, " ").replace(/\b\w/g, (e) => e.toUpperCase()) || "Home", c = s(r), l = s(n);
30269
+ typeof window < "u" && (window.__fe_user_nav_during_speech = {
30270
+ fromPath: r,
30271
+ toPath: n,
30272
+ fromPageName: c,
30273
+ toPageName: l,
30274
+ ts: Date.now()
30275
+ });
30276
+ try {
30277
+ S.current?.sendContextualUpdate?.(`IMPORTANT — VISITOR NAVIGATED WHILE YOU WERE SPEAKING. You were explaining "${c}". The visitor has now moved to "${l}" (${i}). Page title: "${a}". Sections on this page: ${JSON.stringify(o)}. STOP your current explanation immediately. Say exactly: "I see you've navigated to the ${l} page — do you want me to continue what I was explaining, or would you like to know about this page?" If the visitor says "continue": resume your explanation verbally BUT do NOT call flowengage_highlight — you are no longer on the page you were describing so highlights would be wrong. If they want to learn about this new page: proceed with flowengage_highlight on sections of "${l}". Do NOT highlight anything until the visitor answers this question.`);
30255
30278
  } catch {}
30256
30279
  };
30257
30280
  c = window.history.pushState.bind(window.history), window.history.pushState = (...e) => {
@@ -30271,7 +30294,7 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30271
30294
  if (i) try {
30272
30295
  He(i);
30273
30296
  } catch {}
30274
- Ar(), le.current &&= (clearTimeout(le.current), null), ue.current &&= (clearTimeout(ue.current), null), ce.current = !1, de.current = !1, se.current = "idle", c && typeof window < "u" && (window.history.pushState = c), d && typeof window < "u" && window.removeEventListener("popstate", d);
30297
+ typeof window < "u" && (window.__fe_user_nav_during_speech = null), Ar(), le.current &&= (clearTimeout(le.current), null), ue.current &&= (clearTimeout(ue.current), null), ce.current = !1, de.current = !1, se.current = "idle", c && typeof window < "u" && (window.history.pushState = c), d && typeof window < "u" && window.removeEventListener("popstate", d);
30275
30298
  let t = o || S.current, n = E.current, r = ie.current;
30276
30299
  if (t?.endSession?.().catch(() => {}), n && s && a) {
30277
30300
  let e = r ? Math.round((Date.now() - r) / 1e3) : 0, t = JSON.stringify({
@@ -30369,97 +30392,138 @@ function Fk({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30369
30392
  gap: "12px",
30370
30393
  alignItems: "center"
30371
30394
  },
30372
- children: [/* @__PURE__ */ g("button", {
30373
- onClick: async () => {
30374
- if (S.current) try {
30375
- if (v) {
30376
- oe.current = 0, await S.current.setMicMuted?.(!1), y(!1);
30377
- try {
30378
- S.current.sendContextualUpdate?.("The visitor has unmuted. Resume normal interaction and wait for them to speak.");
30379
- } catch {}
30380
- } else {
30381
- oe.current = 0, await S.current.setMicMuted?.(!0), y(!0);
30382
- try {
30383
- S.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.");
30384
- } catch {}
30385
- }
30386
- } catch {}
30387
- },
30388
- title: v ? "Unmute" : "Mute",
30389
- style: {
30390
- width: "24px",
30391
- height: "24px",
30392
- borderRadius: "50%",
30393
- background: v ? "#7f1d1d" : "#1f2937",
30394
- border: v ? "1.5px solid #ef4444" : "1.5px solid #4b5563",
30395
- display: "flex",
30396
- alignItems: "center",
30397
- justifyContent: "center",
30398
- cursor: "pointer",
30399
- color: v ? "#f87171" : "white",
30400
- transition: "all 0.2s ease",
30401
- boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30402
- padding: 0,
30403
- flexShrink: 0
30404
- },
30405
- children: v ? /* @__PURE__ */ _("svg", {
30406
- width: "16",
30407
- height: "16",
30408
- viewBox: "0 0 24 24",
30409
- fill: "none",
30410
- stroke: "currentColor",
30411
- strokeWidth: "2",
30412
- strokeLinecap: "round",
30413
- strokeLinejoin: "round",
30414
- children: [
30415
- /* @__PURE__ */ g("line", {
30416
- x1: "1",
30417
- y1: "1",
30418
- x2: "23",
30419
- y2: "23"
30420
- }),
30421
- /* @__PURE__ */ g("path", { d: "M9 9v3a3 3 0 005.12 2.12M15 9.34V4a3 3 0 00-5.94-.6" }),
30422
- /* @__PURE__ */ g("path", { d: "M17 16.95A7 7 0 015 12v-2m14 0v2a7 7 0 01-.11 1.23" }),
30423
- /* @__PURE__ */ g("line", {
30424
- x1: "12",
30425
- y1: "19",
30426
- x2: "12",
30427
- y2: "23"
30428
- }),
30429
- /* @__PURE__ */ g("line", {
30430
- x1: "8",
30431
- y1: "23",
30432
- x2: "16",
30433
- y2: "23"
30395
+ children: [
30396
+ f === "speaking" && /* @__PURE__ */ _("button", {
30397
+ onClick: () => {
30398
+ if (S.current) try {
30399
+ S.current.sendUserMessage?.("stop");
30400
+ } catch {}
30401
+ },
30402
+ title: "Stop agent",
30403
+ style: {
30404
+ height: "24px",
30405
+ borderRadius: "999px",
30406
+ background: "rgba(239,68,68,0.15)",
30407
+ border: "1.5px solid #ef4444",
30408
+ display: "flex",
30409
+ alignItems: "center",
30410
+ gap: "4px",
30411
+ padding: "0 8px",
30412
+ cursor: "pointer",
30413
+ color: "#f87171",
30414
+ fontSize: "11px",
30415
+ fontWeight: 600,
30416
+ transition: "all 0.2s ease",
30417
+ boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30418
+ flexShrink: 0
30419
+ },
30420
+ children: [/* @__PURE__ */ g("svg", {
30421
+ width: "10",
30422
+ height: "10",
30423
+ viewBox: "0 0 24 24",
30424
+ fill: "currentColor",
30425
+ children: /* @__PURE__ */ g("rect", {
30426
+ x: "4",
30427
+ y: "4",
30428
+ width: "16",
30429
+ height: "16",
30430
+ rx: "2"
30434
30431
  })
30435
- ]
30436
- }) : /* @__PURE__ */ g(CD, {
30437
- size: 16,
30438
- color: "currentColor"
30439
- })
30440
- }), /* @__PURE__ */ g("button", {
30441
- onClick: () => x((e) => !e),
30442
- style: {
30443
- width: "24px",
30444
- height: "24px",
30445
- borderRadius: "50%",
30446
- background: "#1f2937",
30447
- border: "1.5px solid #4b5563",
30448
- display: "flex",
30449
- alignItems: "center",
30450
- justifyContent: "center",
30451
- cursor: "pointer",
30452
- color: "white",
30453
- transition: "background 0.2s ease",
30454
- boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30455
- padding: 0,
30456
- flexShrink: 0
30457
- },
30458
- children: /* @__PURE__ */ g(jD, {
30459
- size: 16,
30460
- color: "currentColor"
30432
+ }), "Stop"]
30433
+ }),
30434
+ /* @__PURE__ */ g("button", {
30435
+ onClick: async () => {
30436
+ if (S.current) try {
30437
+ if (v) {
30438
+ oe.current = 0, await S.current.setMicMuted?.(!1), y(!1);
30439
+ try {
30440
+ S.current.sendContextualUpdate?.("The visitor has unmuted. Resume normal interaction and wait for them to speak.");
30441
+ } catch {}
30442
+ } else {
30443
+ oe.current = 0, await S.current.setMicMuted?.(!0), y(!0);
30444
+ try {
30445
+ S.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.");
30446
+ } catch {}
30447
+ }
30448
+ } catch {}
30449
+ },
30450
+ title: v ? "Unmute" : "Mute",
30451
+ style: {
30452
+ width: "24px",
30453
+ height: "24px",
30454
+ borderRadius: "50%",
30455
+ background: v ? "#7f1d1d" : "#1f2937",
30456
+ border: v ? "1.5px solid #ef4444" : "1.5px solid #4b5563",
30457
+ display: "flex",
30458
+ alignItems: "center",
30459
+ justifyContent: "center",
30460
+ cursor: "pointer",
30461
+ color: v ? "#f87171" : "white",
30462
+ transition: "all 0.2s ease",
30463
+ boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30464
+ padding: 0,
30465
+ flexShrink: 0
30466
+ },
30467
+ children: v ? /* @__PURE__ */ _("svg", {
30468
+ width: "16",
30469
+ height: "16",
30470
+ viewBox: "0 0 24 24",
30471
+ fill: "none",
30472
+ stroke: "currentColor",
30473
+ strokeWidth: "2",
30474
+ strokeLinecap: "round",
30475
+ strokeLinejoin: "round",
30476
+ children: [
30477
+ /* @__PURE__ */ g("line", {
30478
+ x1: "1",
30479
+ y1: "1",
30480
+ x2: "23",
30481
+ y2: "23"
30482
+ }),
30483
+ /* @__PURE__ */ g("path", { d: "M9 9v3a3 3 0 005.12 2.12M15 9.34V4a3 3 0 00-5.94-.6" }),
30484
+ /* @__PURE__ */ g("path", { d: "M17 16.95A7 7 0 015 12v-2m14 0v2a7 7 0 01-.11 1.23" }),
30485
+ /* @__PURE__ */ g("line", {
30486
+ x1: "12",
30487
+ y1: "19",
30488
+ x2: "12",
30489
+ y2: "23"
30490
+ }),
30491
+ /* @__PURE__ */ g("line", {
30492
+ x1: "8",
30493
+ y1: "23",
30494
+ x2: "16",
30495
+ y2: "23"
30496
+ })
30497
+ ]
30498
+ }) : /* @__PURE__ */ g(CD, {
30499
+ size: 16,
30500
+ color: "currentColor"
30501
+ })
30502
+ }),
30503
+ /* @__PURE__ */ g("button", {
30504
+ onClick: () => x((e) => !e),
30505
+ style: {
30506
+ width: "24px",
30507
+ height: "24px",
30508
+ borderRadius: "50%",
30509
+ background: "#1f2937",
30510
+ border: "1.5px solid #4b5563",
30511
+ display: "flex",
30512
+ alignItems: "center",
30513
+ justifyContent: "center",
30514
+ cursor: "pointer",
30515
+ color: "white",
30516
+ transition: "background 0.2s ease",
30517
+ boxShadow: "0 2px 8px rgba(0,0,0,0.4)",
30518
+ padding: 0,
30519
+ flexShrink: 0
30520
+ },
30521
+ children: /* @__PURE__ */ g(jD, {
30522
+ size: 16,
30523
+ color: "currentColor"
30524
+ })
30461
30525
  })
30462
- })]
30526
+ ]
30463
30527
  }),
30464
30528
  b && /* @__PURE__ */ _("div", {
30465
30529
  style: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowengage/react-chatbot",
3
- "version": "6.0.17",
3
+ "version": "6.0.19",
4
4
  "description": "Embeddable AI chat widget for React — powered by FlowEngage. Drop it in with a single siteId.",
5
5
  "keywords": [
6
6
  "chatbot",