@eshal-bot/chat-widget 0.2.35 → 0.2.37

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.
@@ -8060,6 +8060,48 @@
8060
8060
  return response.json();
8061
8061
  };
8062
8062
 
8063
+ /**
8064
+ * Widget verification codes (POST /api/v1/support/identity/start|verify).
8065
+ * The code is posted here, never as a chat message, so it never reaches the
8066
+ * model or the transcript. Resolves to { ok, status, body } so the card can
8067
+ * show the server's own wording (tries left, locked, expired).
8068
+ */
8069
+ const postIdentity = async (path, payload, apiBaseUrl, getAuthToken) => {
8070
+ const headers = {
8071
+ 'Content-Type': 'application/json'
8072
+ };
8073
+ if (typeof getAuthToken === 'function') {
8074
+ const token = await getAuthToken();
8075
+ if (token) headers['Authorization'] = `Bearer ${token}`;
8076
+ }
8077
+ const response = await fetch(`${apiBaseUrl.replace(/\/$/, '')}/api/v1/support/identity/${path}`, {
8078
+ method: 'POST',
8079
+ headers,
8080
+ credentials: 'include',
8081
+ body: JSON.stringify(payload)
8082
+ });
8083
+ let body = {};
8084
+ try {
8085
+ body = await response.json();
8086
+ } catch {
8087
+ body = {};
8088
+ }
8089
+ return {
8090
+ ok: response.ok,
8091
+ status: response.status,
8092
+ body
8093
+ };
8094
+ };
8095
+
8096
+ /** @param {{ conversationId: string, method: 'email'|'sms', email?: string, phone?: string }} payload */
8097
+ const startVisitorVerification = (payload, apiBaseUrl, getAuthToken) => postIdentity('start', payload, apiBaseUrl, getAuthToken);
8098
+
8099
+ /** @param {{ conversationId: string, code: string }} payload */
8100
+ const verifyVisitorCode = (payload, apiBaseUrl, getAuthToken) => postIdentity('verify', payload, apiBaseUrl, getAuthToken);
8101
+
8102
+ /** Delivery of the pending code ("sent", "delivered", "failed" or null). */
8103
+ const visitorCodeStatus = (payload, apiBaseUrl, getAuthToken) => postIdentity('status', payload, apiBaseUrl, getAuthToken);
8104
+
8063
8105
  // ============================================================================
8064
8106
  // UI HELPERS
8065
8107
  // ============================================================================
@@ -9245,7 +9287,28 @@
9245
9287
  // that dies on the wire (e.g. the network changed mid-request) used to
9246
9288
  // render exactly like a delivered message.
9247
9289
  messageNotDelivered: "Not delivered",
9248
- retrySend: "Retry"
9290
+ retrySend: "Retry",
9291
+ // Verification code card. EN-only for now - translate() falls back to EN
9292
+ // for locales without the key.
9293
+ verifyTitle: "Confirm it's you",
9294
+ verifyEmailLabel: "Your email",
9295
+ verifyPhoneLabel: "Your mobile number",
9296
+ verifySendCode: "Send code",
9297
+ verifySending: "Sending...",
9298
+ verifyEnterCode: "Enter the code we sent to {target}",
9299
+ verifyCodeLabel: "6-digit code",
9300
+ verifyConfirm: "Confirm",
9301
+ verifyResendIn: "Resend in {seconds} s",
9302
+ verifyResend: "Send a new code",
9303
+ verifyDifferent: "Use a different address",
9304
+ verifyDone: "Verified as {target}",
9305
+ verifyResumeMessage: "I've confirmed it's me.",
9306
+ verifyTriesLeft: "That code doesn't match. {count} tries left.",
9307
+ verifyGenericError: "Something went wrong. Try again.",
9308
+ verifyInputBlocked: "Enter your code above to continue",
9309
+ verifyCancel: "Cancel",
9310
+ verifyCancelled: "Verification cancelled.",
9311
+ verifyNotDelivered: "We couldn't deliver the code to that number. Check it and send a new code."
9249
9312
  };
9250
9313
  const DICTIONARIES = {
9251
9314
  en: EN,
@@ -12213,14 +12276,16 @@
12213
12276
  * only what reached the conversation another way: what a person sent from the
12214
12277
  * Inbox (contentType human_reply, handoff_ack), the away and holding lines
12215
12278
  * sent while the visitor waits for a person (handoff_wait, EV-4803; backend
12216
- * services/widgetHandoffLines.ts) and a Skill's reply to a staff
12279
+ * services/widgetHandoffLines.ts), the code card an agent sends with Request
12280
+ * verification (verification_request; backend services/verificationRequest.ts)
12281
+ * and a Skill's reply to a staff
12217
12282
  * turn (staffTurn: Instruct Skill, or a hand-back that resumes the Skill;
12218
12283
  * backend services/staffTurn.ts). Dev, 15 Oct 2026: a Skill reply sent while
12219
12284
  * the Testing lab was closed never showed there, because only a person's
12220
12285
  * replies were merged. Mirrors packages/frontend/src/lib/messages/repliedOutsideStream.ts.
12221
12286
  */
12222
12287
  function isRepliedOutsideStream(m) {
12223
- return m?.contentType === 'human_reply' || m?.contentType === 'handoff_ack' || m?.contentType === 'handoff_wait' || m?.staffTurn === true;
12288
+ return m?.contentType === 'human_reply' || m?.contentType === 'handoff_ack' || m?.contentType === 'handoff_wait' || m?.contentType === 'verification_request' || m?.staffTurn === true;
12224
12289
  }
12225
12290
 
12226
12291
  /**
@@ -14026,6 +14091,11 @@
14026
14091
  ...(opts?.toolConfirmation ? {
14027
14092
  tool_confirmation: opts.toolConfirmation
14028
14093
  } : {}),
14094
+ // Verification code card: the held personal tool may run now. The
14095
+ // code itself was posted to /support/identity, not here.
14096
+ ...(opts?.verificationComplete ? {
14097
+ verification_complete: opts.verificationComplete
14098
+ } : {}),
14029
14099
  messageHistory: messages.filter(msg => {
14030
14100
  // Filter out processing messages, empty messages, and onboarding messages
14031
14101
  return !msg.isProcessing && msg.content && msg.content.trim() && !['userName', 'email', 'phone'].includes(msg.type);
@@ -19851,6 +19921,9 @@
19851
19921
  isMinimized,
19852
19922
  isLoading,
19853
19923
  isConversationLoading = false,
19924
+ // A verification code card is waiting for its code: the visitor finishes
19925
+ // (or cancels) it before typing, so a code is never typed into the chat.
19926
+ verificationPending = false,
19854
19927
  placeholder,
19855
19928
  textColor,
19856
19929
  fontFamily,
@@ -20054,7 +20127,7 @@
20054
20127
  // (so a user can upload a file and hit Send without typing). When
20055
20128
  // uploads are in flight we block Send to prevent partial payloads.
20056
20129
  const hasReadyAttachment = attachments.some(a => a.status === "ready");
20057
- const isDisabled = !inputValue.trim() && !hasReadyAttachment || isLoading || isConversationLoading || isUploadBusy;
20130
+ const isDisabled = !inputValue.trim() && !hasReadyAttachment || isLoading || isConversationLoading || isUploadBusy || verificationPending;
20058
20131
  const handleKeyPress = event => {
20059
20132
  if (event.key === "Enter" && !event.shiftKey) {
20060
20133
  event.preventDefault();
@@ -20065,6 +20138,7 @@
20065
20138
  // session - so the file is ingested into the shared session store and
20066
20139
  // answered, and later spoken turns in the same session see it too. A
20067
20140
  // plain voice turn (no attachment) still goes over the WS.
20141
+ if (verificationPending) return;
20068
20142
  if (isVoiceSessionActive && onBidiSubmit && !hasReadyAttachment) {
20069
20143
  onBidiSubmit();
20070
20144
  return;
@@ -20085,7 +20159,9 @@
20085
20159
  // Check if onboarding flow exists and is not completed
20086
20160
  const hasOnboardingQuestions = onboardingQuestions && onboardingQuestions.length > 0;
20087
20161
  const isOnboardingIncomplete = hasOnboardingQuestions && !onboardingCompleted;
20088
- const isVoiceButtonDisabled = csatVisible || isConversationLoading || onboardingEnabled && isOnboardingIncomplete || voiceStatus === "connecting";
20162
+ // A pending code card blocks starting voice; a live session can still be
20163
+ // stopped.
20164
+ const isVoiceButtonDisabled = csatVisible || isConversationLoading || onboardingEnabled && isOnboardingIncomplete || voiceStatus === "connecting" || verificationPending && !isVoiceSessionActive;
20089
20165
 
20090
20166
  // Determine tooltip message
20091
20167
  const getTooltipMessage = () => {
@@ -20285,7 +20361,7 @@
20285
20361
  children: [/*#__PURE__*/jsxRuntimeExports.jsx("button", {
20286
20362
  type: "button",
20287
20363
  onClick: () => fileInputRef.current && fileInputRef.current.click(),
20288
- disabled: csatVisible || isConversationLoading || isLoading || attachmentsAtLimit,
20364
+ disabled: csatVisible || isConversationLoading || isLoading || attachmentsAtLimit || verificationPending,
20289
20365
  "aria-label": attachmentsAtLimit ? paperclipLimitTooltip : "Attach file",
20290
20366
  title: attachmentsAtLimit ? paperclipLimitTooltip : "Attach file",
20291
20367
  className: `h-8 w-8 rounded-lg flex items-center justify-center transition-colors duration-200 ${isDark ? "text-gray-300 hover:bg-gray-700" : "text-gray-500 hover:bg-gray-200"} disabled:opacity-40 disabled:cursor-not-allowed`,
@@ -20311,9 +20387,9 @@
20311
20387
  onFocus: () => setIsFocused(true),
20312
20388
  onBlur: () => setIsFocused(false),
20313
20389
  onKeyDown: handleKeyPress,
20314
- placeholder: isConversationLoading ? t("agentIsLoading") : placeholder || t("typeYourMessage"),
20390
+ placeholder: isConversationLoading ? t("agentIsLoading") : verificationPending ? t("verifyInputBlocked") : placeholder || t("typeYourMessage"),
20315
20391
  rows: 1,
20316
- disabled: csatVisible || isConversationLoading || isLoading || isVoiceSessionActive && voiceStatus !== "connected",
20392
+ disabled: csatVisible || isConversationLoading || isLoading || verificationPending || isVoiceSessionActive && voiceStatus !== "connected",
20317
20393
  dir: typedIsRtl ? "rtl" : "ltr",
20318
20394
  className: `w-full px-3 bg-transparent rounded-xl leading-normal ${isDark ? "text-gray-100" : "text-gray-900"} placeholder-gray-400 resize-none outline-none scrollbar-hide break-words`,
20319
20395
  style: {
@@ -20449,7 +20525,7 @@
20449
20525
  })
20450
20526
  }) : /*#__PURE__*/jsxRuntimeExports.jsx("button", {
20451
20527
  onClick: isVoiceSessionActive && onBidiSubmit && !hasReadyAttachment ? onBidiSubmit : sendWithAttachments,
20452
- disabled: csatVisible || isDisabled || isVoiceSessionActive && voiceStatus !== "connected",
20528
+ disabled: csatVisible || isDisabled || verificationPending || isVoiceSessionActive && voiceStatus !== "connected",
20453
20529
  className: `h-10 w-10 flex-shrink-0 rounded-xl transition-all duration-200 flex items-center justify-center shadow-md disabled:opacity-40 disabled:cursor-not-allowed disabled:shadow-none ${inputValue.trim() ? "scale-100" : "scale-95"}`,
20454
20530
  style: {
20455
20531
  backgroundColor: inputValue.trim() ? primaryColor : isDark ? "#374151" : "#e5e7eb",
@@ -21746,6 +21822,8 @@
21746
21822
  }
21747
21823
  }
21748
21824
 
21825
+ const VerificationContext = /*#__PURE__*/reactExports.createContext(null);
21826
+
21749
21827
  const DEFAULT_AGENT_BUBBLE_COLOR = "#ffffff";
21750
21828
  const DEFAULT_USER_MESSAGE_COLOR = "#f5f5f5";
21751
21829
  const DEFAULT_TEXT_COLOR = "#000000";
@@ -21897,6 +21975,35 @@
21897
21975
  const panelRef = reactExports.useRef(null);
21898
21976
  const t = reactExports.useMemo(() => createTranslator(defaultLanguage), [defaultLanguage]);
21899
21977
 
21978
+ // What the verify card (A2uiBlock "verification" fence) needs. The code is
21979
+ // posted to /support/identity, never through the chat send. Declared with
21980
+ // the other top-level hooks, ahead of the `if (!isOpen) return null;` below.
21981
+ // Cards still waiting for a code; while any is, the chat input is blocked.
21982
+ const [verificationPendingKeys, setVerificationPendingKeys] = reactExports.useState(() => new Set());
21983
+ const setVerificationPending = reactExports.useCallback((key, on) => {
21984
+ setVerificationPendingKeys(prev => {
21985
+ if (on === prev.has(key)) return prev;
21986
+ const next = new Set(prev);
21987
+ if (on) next.add(key);else next.delete(key);
21988
+ return next;
21989
+ });
21990
+ }, []);
21991
+ const verificationContextValue = reactExports.useMemo(() => apiBaseUrl && conversationId ? {
21992
+ t,
21993
+ setPending: setVerificationPending,
21994
+ start: payload => startVisitorVerification({
21995
+ ...payload,
21996
+ conversationId
21997
+ }, apiBaseUrl, getAuthToken),
21998
+ verify: payload => verifyVisitorCode({
21999
+ ...payload,
22000
+ conversationId
22001
+ }, apiBaseUrl, getAuthToken),
22002
+ status: () => visitorCodeStatus({
22003
+ conversationId
22004
+ }, apiBaseUrl, getAuthToken)
22005
+ } : null, [t, apiBaseUrl, conversationId, getAuthToken, setVerificationPending]);
22006
+
21900
22007
  // EV-2480: move focus into the dialog on open. This component only
21901
22008
  // mounts while isOpen is true (see the `if (!isOpen) return null;` below),
21902
22009
  // so a mount-only effect fires exactly once per open.
@@ -21934,8 +22041,13 @@
21934
22041
  // The structured answer rides on the send; the text is still the
21935
22042
  // message. A host override (onPromptSuggestionClick) keeps the text.
21936
22043
  const toolConfirmation = index && typeof index === "object" && index.toolConfirmation ? index.toolConfirmation : null;
22044
+ // The verify card's resume: the code was already checked by the
22045
+ // backend; this only tells the held tool to run.
22046
+ const verificationComplete = index && typeof index === "object" && index.verificationComplete ? index.verificationComplete : null;
21937
22047
  if (onPromptSuggestionClick) onPromptSuggestionClick(text);else if (toolConfirmation) onDirectSend?.(text, undefined, {
21938
22048
  toolConfirmation
22049
+ });else if (verificationComplete) onDirectSend?.(text, undefined, {
22050
+ verificationComplete
21939
22051
  });else onDirectSend?.(text);
21940
22052
  }, [onPromptSuggestionClick, onDirectSend, reportChipClick]);
21941
22053
 
@@ -22541,236 +22653,240 @@
22541
22653
  maxWidth: "92vw",
22542
22654
  maxHeight: "85vh"
22543
22655
  } : undefined;
22544
- return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22545
- dir: isRtlLanguage ? "rtl" : "ltr",
22546
- className: `relative flex-shrink-0 z-50 ${isMinimized ? "w-80 h-auto" : ""}`,
22547
- style: sizeStyle,
22548
- children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22549
- children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
22550
- onMouseDown: e => handleResizeStart("horizontal", e),
22551
- className: `absolute top-0 h-full w-1.5 cursor-ew-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorRight ? "left-0" : "right-0"}`,
22552
- "aria-hidden": true
22553
- }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22554
- onMouseDown: e => handleResizeStart("vertical", e),
22555
- className: `absolute left-0 w-full h-1.5 cursor-ns-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorBottom ? "top-0" : "bottom-0"}`,
22556
- "aria-hidden": true
22557
- })]
22558
- }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22559
- id: "chat-window-panel",
22560
- ref: panelRef,
22561
- role: "dialog",
22562
- "aria-modal": "true",
22563
- "aria-label": t("openChat"),
22564
- tabIndex: -1,
22565
- className: `relative focus:outline-none ${!widgetSize && !isMinimized ? "w-[380px]" : ""} ${!widgetSize && !isMinimized ? "h-[650px]" : ""} ${isMinimized ? "w-80 h-auto" : ""} ${widgetSize && !isMinimized ? "w-full h-full" : ""} max-w-[92vw] border rounded-2xl shadow-2xl bg-white border-gray-200 flex flex-col ${!isMinimized ? "max-h-[85vh]" : ""} overflow-hidden ${isDark ? "bg-gray-900 border-gray-700" : ""}`,
22566
- children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22567
- onMouseDown: e => handleResizeStart("corner", e),
22568
- "aria-hidden": "true",
22569
- className: `absolute w-4 h-4 ${anchorRight === anchorBottom ? "cursor-nwse-resize" : "cursor-nesw-resize"} text-gray-400 hover:text-blue-500 transition-colors z-[71] flex p-0.5 ${anchorBottom ? "top-0 items-start" : "bottom-0 items-end"} ${anchorRight ? "left-0 justify-start" : "right-0 justify-end"}`,
22570
- children: /*#__PURE__*/jsxRuntimeExports.jsx("svg", {
22571
- viewBox: "0 0 12 12",
22572
- className: `w-3 h-3 ${anchorBottom && anchorRight ? "rotate-180" : anchorBottom ? "-rotate-90" : anchorRight ? "rotate-90" : ""}`,
22573
- "aria-hidden": true,
22574
- children: /*#__PURE__*/jsxRuntimeExports.jsx("path", {
22575
- d: "M11 1 L1 11 M11 5 L5 11 M11 9 L9 11",
22576
- stroke: "currentColor",
22577
- strokeWidth: "1.5",
22578
- fill: "none",
22579
- strokeLinecap: "round"
22580
- })
22581
- })
22582
- }), /*#__PURE__*/jsxRuntimeExports.jsx(ChatHeader, {
22583
- conciergeName: conciergeName,
22584
- companyName: companyName,
22585
- companyLogo: companyLogo,
22586
- primaryColor: primaryColor,
22587
- isDark: isDark,
22588
- isMinimized: isMinimized,
22589
- textColor: resolvedTextColor,
22590
- fontFamily: fontFamily,
22591
- fontSize: fontSize,
22592
- onToggleTheme: onToggleTheme,
22593
- onMinimize: onMinimize,
22594
- onClose: handleCloseClick,
22595
- headerTextBold: headerTextBold,
22596
- headerTextItalic: headerTextItalic,
22597
- headerTextColor: headerTextColor,
22598
- headerFontFamily: headerFontFamily,
22599
- headerFontSize: headerFontSize,
22600
- subtitle: subtitle,
22601
- showStatus: showStatus,
22602
- statusMode: statusMode,
22603
- officeHours: officeHours,
22604
- onRefreshChat: onRefreshChat,
22605
- onCopyChat: onCopyChat,
22606
- defaultLanguage: defaultLanguage
22607
- }), !isMinimized && filterEnabled && !showInlineFilter && !(showResolveForm && !isConversationResolved) && !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(CategoryTabsBar, {
22608
- categories: filterCategories,
22609
- selectedCategoryId: widgetFilter?.category || null,
22610
- onSelect: handleSelectCategory,
22611
- isDark: isDark,
22612
- primaryColor: primaryColor,
22613
- fontFamily: fontFamily,
22614
- isRtl: isRtlLanguage,
22615
- defaultLanguage: defaultLanguage
22616
- }), !isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22656
+ return /*#__PURE__*/jsxRuntimeExports.jsx(VerificationContext.Provider, {
22657
+ value: verificationContextValue,
22658
+ children: /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22659
+ dir: isRtlLanguage ? "rtl" : "ltr",
22660
+ className: `relative flex-shrink-0 z-50 ${isMinimized ? "w-80 h-auto" : ""}`,
22661
+ style: sizeStyle,
22662
+ children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22617
22663
  children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
22618
- ref: messagesContainerRef,
22619
- role: "log",
22620
- "aria-live": "polite",
22621
- className: `chat-messages flex-1 overflow-y-auto px-3 py-4 space-y-4 ${isDark ? "bg-gray-900" : "bg-gradient-to-b from-gray-50/50 to-white"} break-words`,
22622
- children: showResolveForm && !isConversationResolved ? renderFeedbackForm() : onboardingActive && !onboardingCompleted && onOnboardingFormSubmit ? /*#__PURE__*/jsxRuntimeExports.jsx(OnboardingForm, {
22623
- questions: onboardingQuestions,
22624
- onPromptSuggestionClick: stableOnPromptSuggestionClick,
22625
- collapsiblePrompt: collectionPrompt,
22626
- onSubmit: onOnboardingFormSubmit,
22627
- primaryColor: primaryColor,
22628
- isRtl: isRtlLanguage,
22629
- isDark: isDark,
22630
- defaultLanguage: defaultLanguage,
22631
- fontFamily: fontFamily
22632
- }) : /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22633
- children: [sessionExpiringSoon && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22634
- role: "status",
22635
- className: `mx-3 mt-1 mb-2 rounded-lg px-3 py-2 text-xs font-medium ${isDark ? 'bg-amber-900/40 text-amber-200 border border-amber-700/50' : 'bg-amber-50 text-amber-800 border border-amber-200'}`,
22636
- children: t("sessionExpiringSoon")
22637
- }), /*#__PURE__*/jsxRuntimeExports.jsx(MessageList, {
22638
- messages: messages,
22639
- liveJoined: liveJoined,
22640
- isDark: isDark,
22664
+ onMouseDown: e => handleResizeStart("horizontal", e),
22665
+ className: `absolute top-0 h-full w-1.5 cursor-ew-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorRight ? "left-0" : "right-0"}`,
22666
+ "aria-hidden": true
22667
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22668
+ onMouseDown: e => handleResizeStart("vertical", e),
22669
+ className: `absolute left-0 w-full h-1.5 cursor-ns-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorBottom ? "top-0" : "bottom-0"}`,
22670
+ "aria-hidden": true
22671
+ })]
22672
+ }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22673
+ id: "chat-window-panel",
22674
+ ref: panelRef,
22675
+ role: "dialog",
22676
+ "aria-modal": "true",
22677
+ "aria-label": t("openChat"),
22678
+ tabIndex: -1,
22679
+ className: `relative focus:outline-none ${!widgetSize && !isMinimized ? "w-[380px]" : ""} ${!widgetSize && !isMinimized ? "h-[650px]" : ""} ${isMinimized ? "w-80 h-auto" : ""} ${widgetSize && !isMinimized ? "w-full h-full" : ""} max-w-[92vw] border rounded-2xl shadow-2xl bg-white border-gray-200 flex flex-col ${!isMinimized ? "max-h-[85vh]" : ""} overflow-hidden ${isDark ? "bg-gray-900 border-gray-700" : ""}`,
22680
+ children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22681
+ onMouseDown: e => handleResizeStart("corner", e),
22682
+ "aria-hidden": "true",
22683
+ className: `absolute w-4 h-4 ${anchorRight === anchorBottom ? "cursor-nwse-resize" : "cursor-nesw-resize"} text-gray-400 hover:text-blue-500 transition-colors z-[71] flex p-0.5 ${anchorBottom ? "top-0 items-start" : "bottom-0 items-end"} ${anchorRight ? "left-0 justify-start" : "right-0 justify-end"}`,
22684
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("svg", {
22685
+ viewBox: "0 0 12 12",
22686
+ className: `w-3 h-3 ${anchorBottom && anchorRight ? "rotate-180" : anchorBottom ? "-rotate-90" : anchorRight ? "rotate-90" : ""}`,
22687
+ "aria-hidden": true,
22688
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("path", {
22689
+ d: "M11 1 L1 11 M11 5 L5 11 M11 9 L9 11",
22690
+ stroke: "currentColor",
22691
+ strokeWidth: "1.5",
22692
+ fill: "none",
22693
+ strokeLinecap: "round"
22694
+ })
22695
+ })
22696
+ }), /*#__PURE__*/jsxRuntimeExports.jsx(ChatHeader, {
22697
+ conciergeName: conciergeName,
22698
+ companyName: companyName,
22699
+ companyLogo: companyLogo,
22700
+ primaryColor: primaryColor,
22701
+ isDark: isDark,
22702
+ isMinimized: isMinimized,
22703
+ textColor: resolvedTextColor,
22704
+ fontFamily: fontFamily,
22705
+ fontSize: fontSize,
22706
+ onToggleTheme: onToggleTheme,
22707
+ onMinimize: onMinimize,
22708
+ onClose: handleCloseClick,
22709
+ headerTextBold: headerTextBold,
22710
+ headerTextItalic: headerTextItalic,
22711
+ headerTextColor: headerTextColor,
22712
+ headerFontFamily: headerFontFamily,
22713
+ headerFontSize: headerFontSize,
22714
+ subtitle: subtitle,
22715
+ showStatus: showStatus,
22716
+ statusMode: statusMode,
22717
+ officeHours: officeHours,
22718
+ onRefreshChat: onRefreshChat,
22719
+ onCopyChat: onCopyChat,
22720
+ defaultLanguage: defaultLanguage
22721
+ }), !isMinimized && filterEnabled && !showInlineFilter && !(showResolveForm && !isConversationResolved) && !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(CategoryTabsBar, {
22722
+ categories: filterCategories,
22723
+ selectedCategoryId: widgetFilter?.category || null,
22724
+ onSelect: handleSelectCategory,
22725
+ isDark: isDark,
22726
+ primaryColor: primaryColor,
22727
+ fontFamily: fontFamily,
22728
+ isRtl: isRtlLanguage,
22729
+ defaultLanguage: defaultLanguage
22730
+ }), !isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22731
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
22732
+ ref: messagesContainerRef,
22733
+ role: "log",
22734
+ "aria-live": "polite",
22735
+ className: `chat-messages flex-1 overflow-y-auto px-3 py-4 space-y-4 ${isDark ? "bg-gray-900" : "bg-gradient-to-b from-gray-50/50 to-white"} break-words`,
22736
+ children: showResolveForm && !isConversationResolved ? renderFeedbackForm() : onboardingActive && !onboardingCompleted && onOnboardingFormSubmit ? /*#__PURE__*/jsxRuntimeExports.jsx(OnboardingForm, {
22737
+ questions: onboardingQuestions,
22738
+ onPromptSuggestionClick: stableOnPromptSuggestionClick,
22739
+ collapsiblePrompt: collectionPrompt,
22740
+ onSubmit: onOnboardingFormSubmit,
22641
22741
  primaryColor: primaryColor,
22642
- isLoading: isLoading,
22643
- agentMessageBubbleColor: agentMessageBubbleColor,
22644
- userMessageBoxColor: userMessageBoxColor,
22645
- textColor: textColor,
22646
- assistantTextColor: assistantTextColor,
22647
- userTextColor: userTextColor,
22648
- fontFamily: fontFamily,
22649
- agentMessageBubbleFontFamily: agentMessageBubbleFontFamily,
22650
- agentMessageBubbleFontSize: agentMessageBubbleFontSize,
22651
- userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22652
- userMessageBubbleFontSize: userMessageBubbleFontSize,
22653
- fontSize: fontSize,
22654
- formatTime: formatTime,
22655
22742
  isRtl: isRtlLanguage,
22743
+ isDark: isDark,
22656
22744
  defaultLanguage: defaultLanguage,
22657
- quickQuestions: quickQuestions,
22658
- shouldShowQuickQuestions: shouldShowQuickQuestions,
22659
- onQuickQuestion: onQuickQuestion ?? onDirectSend,
22660
- quickQuestionsLayout: quickQuestionsLayout,
22661
- onDecision: onDecision,
22662
- disclaimerEnabled: disclaimerEnabled,
22663
- disclaimerText: disclaimerText,
22664
- disclaimerPosition: disclaimerPosition,
22665
- disclaimerLinkUrl: disclaimerLinkUrl,
22666
- disclaimerLinkLabel: disclaimerLinkLabel,
22667
- resolvedAgentBubbleColor: resolvedAgentBubbleColor,
22668
- resolvedUserMessageColor: resolvedUserMessageColor,
22669
- resolvedTextColor: resolvedTextColor,
22670
- isVoiceSessionActive: isVoiceSessionActive,
22671
- voiceStatus: voiceStatus,
22672
- messagesContainerRef: messagesContainerRef,
22673
- companyLogo: companyLogo,
22674
- chatbotAvatarEnabled: chatbotAvatarEnabled,
22675
- chatbotAvatar: chatbotAvatar,
22676
- conciergeName: conciergeName,
22677
- companyName: companyName,
22678
- apiBaseUrl: apiBaseUrl,
22679
- getAuthToken: getAuthToken,
22680
- onPromptSuggestionClick: stableOnPromptSuggestionClick,
22681
- conversationResetKey: conversationId,
22682
- allowFeedback: allowFeedback,
22683
- provideCitations: provideCitations,
22684
- onFeedback: onFeedback,
22685
- onRetryMessage: onRetryMessage,
22686
- headerTextColor: headerTextColor,
22687
- beforePromptsSlot: showInlineFilter ? /*#__PURE__*/jsxRuntimeExports.jsx(CategoryFilterInline, {
22688
- categories: filterCategories,
22689
- selectedCategoryId: widgetFilter?.category || null,
22690
- onSelect: handleSelectCategory,
22745
+ fontFamily: fontFamily
22746
+ }) : /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22747
+ children: [sessionExpiringSoon && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22748
+ role: "status",
22749
+ className: `mx-3 mt-1 mb-2 rounded-lg px-3 py-2 text-xs font-medium ${isDark ? 'bg-amber-900/40 text-amber-200 border border-amber-700/50' : 'bg-amber-50 text-amber-800 border border-amber-200'}`,
22750
+ children: t("sessionExpiringSoon")
22751
+ }), /*#__PURE__*/jsxRuntimeExports.jsx(MessageList, {
22752
+ messages: messages,
22753
+ liveJoined: liveJoined,
22691
22754
  isDark: isDark,
22692
22755
  primaryColor: primaryColor,
22756
+ isLoading: isLoading,
22757
+ agentMessageBubbleColor: agentMessageBubbleColor,
22758
+ userMessageBoxColor: userMessageBoxColor,
22759
+ textColor: textColor,
22760
+ assistantTextColor: assistantTextColor,
22761
+ userTextColor: userTextColor,
22693
22762
  fontFamily: fontFamily,
22763
+ agentMessageBubbleFontFamily: agentMessageBubbleFontFamily,
22764
+ agentMessageBubbleFontSize: agentMessageBubbleFontSize,
22765
+ userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22766
+ userMessageBubbleFontSize: userMessageBubbleFontSize,
22694
22767
  fontSize: fontSize,
22768
+ formatTime: formatTime,
22695
22769
  isRtl: isRtlLanguage,
22696
- label: t("chooseTopicLabel"),
22697
- regionLabel: t("categoryFilter")
22698
- }) : null,
22699
- quickQuestionsHeadingLabel: filterEnabled ? t("quickQuestionsHeadingLabel") : undefined
22700
- }), (showCsat && csatEnabled || csatRequest) && !csatSubmitted && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22701
- className: "",
22702
- "data-testid": "widget-csat-card",
22703
- children: /*#__PURE__*/jsxRuntimeExports.jsx(CSATWidget, {
22704
- format: normalizeCsatFormat(csatRequest?.format || csatFormat),
22705
- prompt: csatRequest?.prompt || csatPrompt || t("howWasYourExperience"),
22706
- onRating: handleCsatRating,
22707
- disabled: false,
22708
- isDark: isDark,
22709
- primaryColor: primaryColor,
22710
- defaultLanguage: defaultLanguage
22711
- })
22712
- })]
22713
- })
22714
- }), !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(ChatInput, {
22715
- onSynthesizeAssistantMessage: onSynthesizeAssistantMessage,
22716
- onStopGeneration: onStopGeneration,
22717
- inputValue: inputValue,
22718
- setInputValue: setInputValue,
22719
- onSend: onSend,
22720
- isDark: isDark,
22721
- primaryColor: primaryColor,
22722
- isOpen: isOpen,
22723
- isMinimized: isMinimized,
22724
- isLoading: isLoading,
22725
- isConversationLoading: isConversationLoading,
22726
- placeholder: placeholder,
22727
- textColor: resolvedTextColor,
22728
- fontFamily: fontFamily,
22729
- userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22730
- userMessageBubbleFontSize: userMessageBubbleFontSize,
22731
- fontSize: fontSize,
22732
- isRtl: isRtlLanguage,
22733
- csatVisible: showCsat && csatEnabled && !csatSubmitted || isCsatEnabled && (showResolveForm || isConversationResolved),
22734
- enableVoiceInteraction: enableVoiceInteraction,
22735
- isVoiceSessionActive: isVoiceSessionActive,
22736
- voiceStatus: voiceStatus,
22737
- voiceError: voiceError,
22738
- onVoiceToggle: onVoiceToggle,
22739
- onBidiSubmit: onBidiSubmit,
22740
- disclaimerEnabled: disclaimerEnabled,
22741
- disclaimerText: disclaimerText,
22742
- disclaimerPosition: disclaimerPosition,
22743
- disclaimerLinkUrl: disclaimerLinkUrl,
22744
- disclaimerLinkLabel: disclaimerLinkLabel,
22745
- showPoweredBy: showPoweredBy,
22746
- defaultLanguage: defaultLanguage,
22747
- onboardingQuestions: onboardingQuestions,
22748
- onboardingActive: onboardingActive,
22749
- onboardingCompleted: onboardingCompleted,
22750
- onboardingEnabled: onboardingEnabled,
22751
- userMessageBoxColor: userMessageBoxColor,
22752
- resolvedUserMessageColor: resolvedUserMessageColor,
22753
- userTextColor: userTextColor,
22754
- promptSuggestions: showResolveForm || isConversationResolved || autoPromptEnabled === false || isLoading ? [] : stablePromptSuggestions,
22755
- onPromptSuggestionClick: stableOnPromptSuggestionClick,
22756
- autoPromptQuestionDisplay: autoPromptQuestionDisplay,
22757
- tagSelectorNode: null,
22758
- showResolveButton: isCsatEnabled && hasUserMessages && !isConversationResolved && !showResolveForm && !showCsat && !shouldHideResolveForOnboarding,
22759
- onResolve: () => {
22760
- if (!isCsatEnabled) return;
22761
- setShowResolveForm(true);
22762
- }
22763
- // Attachments (RAG-attach-1) - paperclip stays hidden
22764
- // unless the operator explicitly opted in via
22765
- // MasterAgent.config.chatFeatures.
22766
- ,
22767
- chatFeatures: chatFeatures,
22768
- apiEndpoint: apiBaseUrl,
22769
- organizationId: organizationId,
22770
- conversationId: conversationId
22770
+ defaultLanguage: defaultLanguage,
22771
+ quickQuestions: quickQuestions,
22772
+ shouldShowQuickQuestions: shouldShowQuickQuestions,
22773
+ onQuickQuestion: onQuickQuestion ?? onDirectSend,
22774
+ quickQuestionsLayout: quickQuestionsLayout,
22775
+ onDecision: onDecision,
22776
+ disclaimerEnabled: disclaimerEnabled,
22777
+ disclaimerText: disclaimerText,
22778
+ disclaimerPosition: disclaimerPosition,
22779
+ disclaimerLinkUrl: disclaimerLinkUrl,
22780
+ disclaimerLinkLabel: disclaimerLinkLabel,
22781
+ resolvedAgentBubbleColor: resolvedAgentBubbleColor,
22782
+ resolvedUserMessageColor: resolvedUserMessageColor,
22783
+ resolvedTextColor: resolvedTextColor,
22784
+ isVoiceSessionActive: isVoiceSessionActive,
22785
+ voiceStatus: voiceStatus,
22786
+ messagesContainerRef: messagesContainerRef,
22787
+ companyLogo: companyLogo,
22788
+ chatbotAvatarEnabled: chatbotAvatarEnabled,
22789
+ chatbotAvatar: chatbotAvatar,
22790
+ conciergeName: conciergeName,
22791
+ companyName: companyName,
22792
+ apiBaseUrl: apiBaseUrl,
22793
+ getAuthToken: getAuthToken,
22794
+ onPromptSuggestionClick: stableOnPromptSuggestionClick,
22795
+ conversationResetKey: conversationId,
22796
+ allowFeedback: allowFeedback,
22797
+ provideCitations: provideCitations,
22798
+ onFeedback: onFeedback,
22799
+ onRetryMessage: onRetryMessage,
22800
+ headerTextColor: headerTextColor,
22801
+ beforePromptsSlot: showInlineFilter ? /*#__PURE__*/jsxRuntimeExports.jsx(CategoryFilterInline, {
22802
+ categories: filterCategories,
22803
+ selectedCategoryId: widgetFilter?.category || null,
22804
+ onSelect: handleSelectCategory,
22805
+ isDark: isDark,
22806
+ primaryColor: primaryColor,
22807
+ fontFamily: fontFamily,
22808
+ fontSize: fontSize,
22809
+ isRtl: isRtlLanguage,
22810
+ label: t("chooseTopicLabel"),
22811
+ regionLabel: t("categoryFilter")
22812
+ }) : null,
22813
+ quickQuestionsHeadingLabel: filterEnabled ? t("quickQuestionsHeadingLabel") : undefined
22814
+ }), (showCsat && csatEnabled || csatRequest) && !csatSubmitted && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22815
+ className: "",
22816
+ "data-testid": "widget-csat-card",
22817
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(CSATWidget, {
22818
+ format: normalizeCsatFormat(csatRequest?.format || csatFormat),
22819
+ prompt: csatRequest?.prompt || csatPrompt || t("howWasYourExperience"),
22820
+ onRating: handleCsatRating,
22821
+ disabled: false,
22822
+ isDark: isDark,
22823
+ primaryColor: primaryColor,
22824
+ defaultLanguage: defaultLanguage
22825
+ })
22826
+ })]
22827
+ })
22828
+ }), !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(ChatInput, {
22829
+ onSynthesizeAssistantMessage: onSynthesizeAssistantMessage,
22830
+ onStopGeneration: onStopGeneration,
22831
+ inputValue: inputValue,
22832
+ setInputValue: setInputValue,
22833
+ onSend: onSend,
22834
+ isDark: isDark,
22835
+ primaryColor: primaryColor,
22836
+ isOpen: isOpen,
22837
+ isMinimized: isMinimized,
22838
+ isLoading: isLoading,
22839
+ isConversationLoading: isConversationLoading,
22840
+ verificationPending: verificationPendingKeys.size > 0,
22841
+ placeholder: placeholder,
22842
+ textColor: resolvedTextColor,
22843
+ fontFamily: fontFamily,
22844
+ userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22845
+ userMessageBubbleFontSize: userMessageBubbleFontSize,
22846
+ fontSize: fontSize,
22847
+ isRtl: isRtlLanguage,
22848
+ csatVisible: showCsat && csatEnabled && !csatSubmitted || isCsatEnabled && (showResolveForm || isConversationResolved),
22849
+ enableVoiceInteraction: enableVoiceInteraction,
22850
+ isVoiceSessionActive: isVoiceSessionActive,
22851
+ voiceStatus: voiceStatus,
22852
+ voiceError: voiceError,
22853
+ onVoiceToggle: onVoiceToggle,
22854
+ onBidiSubmit: onBidiSubmit,
22855
+ disclaimerEnabled: disclaimerEnabled,
22856
+ disclaimerText: disclaimerText,
22857
+ disclaimerPosition: disclaimerPosition,
22858
+ disclaimerLinkUrl: disclaimerLinkUrl,
22859
+ disclaimerLinkLabel: disclaimerLinkLabel,
22860
+ showPoweredBy: showPoweredBy,
22861
+ defaultLanguage: defaultLanguage,
22862
+ onboardingQuestions: onboardingQuestions,
22863
+ onboardingActive: onboardingActive,
22864
+ onboardingCompleted: onboardingCompleted,
22865
+ onboardingEnabled: onboardingEnabled,
22866
+ userMessageBoxColor: userMessageBoxColor,
22867
+ resolvedUserMessageColor: resolvedUserMessageColor,
22868
+ userTextColor: userTextColor,
22869
+ promptSuggestions: showResolveForm || isConversationResolved || autoPromptEnabled === false || isLoading ? [] : stablePromptSuggestions,
22870
+ onPromptSuggestionClick: stableOnPromptSuggestionClick,
22871
+ autoPromptQuestionDisplay: autoPromptQuestionDisplay,
22872
+ tagSelectorNode: null,
22873
+ showResolveButton: isCsatEnabled && hasUserMessages && !isConversationResolved && !showResolveForm && !showCsat && !shouldHideResolveForOnboarding,
22874
+ onResolve: () => {
22875
+ if (!isCsatEnabled) return;
22876
+ setShowResolveForm(true);
22877
+ }
22878
+ // Attachments (RAG-attach-1) - paperclip stays hidden
22879
+ // unless the operator explicitly opted in via
22880
+ // MasterAgent.config.chatFeatures.
22881
+ ,
22882
+ chatFeatures: chatFeatures,
22883
+ apiEndpoint: apiBaseUrl,
22884
+ organizationId: organizationId,
22885
+ conversationId: conversationId
22886
+ })]
22771
22887
  })]
22772
22888
  })]
22773
- })]
22889
+ })
22774
22890
  });
22775
22891
  };
22776
22892
 
@@ -23089,7 +23205,7 @@
23089
23205
  * value by its own test (that constant sat at 0.1.113 while this package was
23090
23206
  * at 0.2.2 precisely because nothing enforced it - EV-2431).
23091
23207
  */
23092
- const WIDGET_VERSION = '0.2.35';
23208
+ const WIDGET_VERSION = '0.2.37';
23093
23209
 
23094
23210
  /**
23095
23211
  * API utility functions