@flowengage/react-chatbot 7.0.12 → 7.0.15

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.
@@ -3485,19 +3485,14 @@ function Br({ siteId: e, config: t, children: n, language: r = "en" }) {
3485
3485
  let o = typeof e == "string" ? e.trim() : "";
3486
3486
  if (!o || !k.current || !y || l !== "ready" || Ve) return;
3487
3487
  Xt();
3488
- let s = /^\s*(yes|yeah|sure|ok|okay|go ahead|take me(?: there)?|navigate(?: me)?|yep|absolutely|please do|do it|let'?s go|go there|show me|go to it|bring me there|navigate me there)\b/i;
3488
+ let s = /^\s*(yes|yeah|sure|ok|okay|go ahead|take me(?: there)?(?!\s+to\s+(?!there\b|it\b))|navigate(?: me)?(?!\s+to\s+\w)|yep|absolutely|please do|do it|let'?s go|go there|show me(?!\s+(?:the|a|an)\s+\w)|go to it|bring me there|navigate me there)\b/i;
3489
3489
  if (pt.current && s.test(o)) {
3490
3490
  let { url: e, section: t } = pt.current;
3491
- pt.current = null, console.log("[FWH Nav] Client-side nav firing →", e), Sr(e, {
3492
- siteId: i?.siteId,
3493
- apiBaseUrl: i?.apiBaseUrl
3494
- }).then((n) => {
3495
- n && Or(e, { voiceActive: Dt.current }).then((e) => {
3496
- t && setTimeout(() => {
3497
- let e = _r(null, t);
3498
- e && vr(e);
3499
- }, e ? 300 : 150);
3500
- });
3491
+ pt.current = null, console.log("[FWH Nav] Client-side nav firing →", e), Or(e, { voiceActive: Dt.current }).then((e) => {
3492
+ t && setTimeout(() => {
3493
+ let e = _r(null, t);
3494
+ e && vr(e);
3495
+ }, e ? 300 : 150);
3501
3496
  });
3502
3497
  } else s.test(o) || (pt.current = null);
3503
3498
  let c = `pending-user-${Date.now()}`, u = {
@@ -29398,18 +29393,21 @@ function wk(e) {
29398
29393
  let t = e.siteId || null, n = (e.apiBaseUrl || "").replace(/\/$/, ""), r = typeof e.getLastUserVoiceText == "function" ? e.getLastUserVoiceText : null, i = [], a = {
29399
29394
  "fwh-navigate-mvp": async (n) => {
29400
29395
  $("fwh-navigate-mvp ▶ raw parameters:", n);
29401
- let i = gk(n), a = bk(i), o = i.section_text ?? i.sectionText ?? i.section, s = Array.isArray(i.expected_landmarks) ? i.expected_landmarks : Array.isArray(i.expectedLandmarks) ? i.expectedLandmarks : [];
29396
+ let i = gk(n), a = bk(i);
29402
29397
  if ($("fwh-navigate-mvp · coerced:", {
29403
29398
  url: a,
29404
- sectionText: o,
29405
- expectedLandmarks: s
29399
+ sectionText: i.section_text ?? i.sectionText ?? i.section,
29400
+ expectedLandmarks: Array.isArray(i.expected_landmarks) ? i.expected_landmarks : Array.isArray(i.expectedLandmarks) ? i.expectedLandmarks : []
29406
29401
  }), !a) {
29407
29402
  let e = "Missing url: pass a string url, path like /pricing, or JSON with a url field.";
29408
29403
  return $("fwh-navigate-mvp ✖", e), e;
29409
29404
  }
29410
29405
  if (typeof window < "u") try {
29411
29406
  let e = new URL(a, window.location.href);
29412
- e.origin !== window.location.origin && /^https?:$/i.test(e.protocol) && (a = e.pathname + e.search + e.hash, $("fwh-navigate-mvp · normalized cross-origin URL to path:", a));
29407
+ if (e.origin !== window.location.origin && /^https?:$/i.test(e.protocol)) {
29408
+ let t = e.hostname;
29409
+ return $("fwh-navigate-mvp ✖ external URL blocked:", e.href), `EXTERNAL_LINK_BLOCKED: The URL "${a}" points to an external site (${t}) that opens in a new tab. I cannot open new tabs or navigate to external sites. Tell the visitor exactly this: "That link opens an external app — I'm not able to open it for you, but you can click the link directly in the navigation header."`;
29410
+ }
29413
29411
  } catch {}
29414
29412
  if (typeof window < "u") {
29415
29413
  try {
@@ -29627,8 +29625,8 @@ function wk(e) {
29627
29625
  let n = t.getAttribute("href"), r = (t.textContent || "").replace(/\s+/g, " ").trim();
29628
29626
  if (!r || !n || n === "#" || n.startsWith("javascript:")) return;
29629
29627
  try {
29630
- let e = qO(t);
29631
- if (e.display === "none" || e.visibility === "hidden") return;
29628
+ let e = t.parentElement;
29629
+ if (e && qO(e).display === "none" && !e.closest("nav, [role='navigation'], header, [class*='nav'], [class*='menu']")) return;
29632
29630
  } catch {}
29633
29631
  let i = r.toLowerCase() + "|" + n;
29634
29632
  e.has(i) || e.set(i, {
@@ -29671,10 +29669,15 @@ function wk(e) {
29671
29669
  },
29672
29670
  "fwh-list-forms-mvp": async () => {
29673
29671
  let e = QO(), t = $O();
29674
- return $("fwh-list-forms-mvp ✓", `${e.length} field(s)`, `${t.length} button(s)`), JSON.stringify({
29675
- fields: e,
29672
+ $("fwh-list-forms-mvp ✓", `${e.length} field(s)`, `${t.length} button(s)`);
29673
+ let n = e.map((e) => ({
29674
+ ...e,
29675
+ inputCategory: e.tag === "SELECT" ? "dropdown_select" : "text_input"
29676
+ }));
29677
+ return JSON.stringify({
29678
+ fields: n,
29676
29679
  buttons: t,
29677
- hint: "field_key: placeholder/label, name (e.g. url), id (e.g. url-input). If the page has two URL boxes, fwh-fill-form-mvp sets all matching URL inputs. fwh-click-button-mvp picks the Conduct Audit nearest the filled field when labels duplicate."
29680
+ 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."
29678
29681
  });
29679
29682
  },
29680
29683
  "fwh-fill-form-mvp": async (e) => {
@@ -29691,14 +29694,29 @@ function wk(e) {
29691
29694
  let t = e?.field_key, r = e?.value;
29692
29695
  if (t == null || r == null) continue;
29693
29696
  TO(`Filling ${String(t)}...`, { spinner: !0 });
29694
- let a = ZO(), o = uk(a, String(t), r);
29695
- if (o.length) {
29696
- for (let [e, t] of o.entries()) NO(t), await zO(t), xk(t, r, { skipScroll: e > 0 }), PO(t), await WO(120);
29697
- i = o, n.push(String(t));
29697
+ let a = ZO(), o = (() => {
29698
+ let e = ek(r);
29699
+ ek(String(t));
29700
+ let n = null, i = 0;
29701
+ for (let r of a) {
29702
+ if (r.tagName !== "SELECT" || !Array.from(r.options).find((t) => ek(t.text) === e || ek(t.value) === e)) continue;
29703
+ let a = nk(r, String(t));
29704
+ a >= i && (i = a, n = r);
29705
+ }
29706
+ return n && i >= 0 ? n : null;
29707
+ })();
29708
+ if (o) {
29709
+ $("fwh-fill-form-mvp · SELECT pre-pass matched dropdown:", o.name || o.id || o.getAttribute("aria-label")), NO(o), await zO(o), xk(o, r), PO(o), await WO(120), i = [o], n.push(String(t));
29710
+ continue;
29711
+ }
29712
+ let s = uk(a, String(t), r);
29713
+ if (s.length) {
29714
+ for (let [e, t] of s.entries()) NO(t), await zO(t), xk(t, r, { skipScroll: e > 0 }), PO(t), await WO(120);
29715
+ i = s, n.push(String(t));
29698
29716
  continue;
29699
29717
  }
29700
- let s = pk(a, String(t));
29701
- s ||= ik(a, String(t)), s ||= ak(a, String(t), r), s && (NO(s), await zO(s), xk(s, r), PO(s), await WO(120), i = [s], n.push(String(t)));
29718
+ let c = pk(a, String(t));
29719
+ c ||= ik(a, String(t)), c ||= ak(a, String(t), r), c && (NO(c), await zO(c), xk(c, r), PO(c), await WO(120), i = [c], n.push(String(t)));
29702
29720
  }
29703
29721
  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.";
29704
29722
  let a = `OK_FILLED: ${n.join(", ")}`;
@@ -30294,7 +30312,7 @@ function Ik({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
30294
30312
  y.overrides = { agent: { firstMessage: g ? e ? `Hi, welcome to ${e}!` : "Hi, welcome!" : `Welcome to the ${T} page!` } }, g || console.log(`[FlowEngage] 🏠 Page-context override: "${T}" for ${m}`);
30295
30313
  }
30296
30314
  else u && (y.overrides = { agent: { firstMessage: "" } });
30297
- let oe = !1, he = p ? "NAVIGATION COMPLETE — Your brief intro has been spoken. Now speak 2-3 sentences about this page from your knowledge. Then ask the visitor exactly this: \"Would you like to know about a specific section, or should I give you a complete overview?\" Then STOP — wait for their reply. Do NOT auto-highlight or auto-walkthrough." : null, ge = !1, _e = !p && !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, ve = await bD.startSession({
30315
+ let oe = !1, he = p ? `NAVIGATION COMPLETE — Your brief intro has been spoken. PRIOR CONVERSATION CONTEXT (continue from here — do NOT re-introduce yourself):\n${n?.transcript ? `Prior transcript:\n${n.transcript}\n` : "(no prior transcript)"}\nNow speak 2-3 sentences about this page from your knowledge, referring to the visitor's prior context if relevant. Then ask the visitor exactly this: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight or auto-walkthrough.` : null, ge = !1, _e = !p && !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, ve = await bD.startSession({
30298
30316
  ...y,
30299
30317
  onConnect: ({ conversationId: e }) => {
30300
30318
  ie.current = e, ae.current = Date.now(), console.log("[FlowEngage] 🎙️ AI chat session connected:", e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowengage/react-chatbot",
3
- "version": "7.0.12",
3
+ "version": "7.0.15",
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",