@eshal-bot/chat-widget 0.1.101 → 0.1.102
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.
- package/dist/{chat-widget-MarkdownRenderer-DwAarA-l.esm.js → chat-widget-MarkdownRenderer-DkfSQ430.esm.js} +1 -1
- package/dist/{chat-widget-index-B5VwIIEZ.esm.js → chat-widget-index-BcPgyNKZ.esm.js} +3 -3
- package/dist/chat-widget.esm.js +1 -1
- package/dist/chat-widget.js +190 -35
- package/dist/chat-widget.min.js +4 -4
- package/dist/chat-widget.umd.js +6 -6
- package/package.json +1 -1
package/dist/chat-widget.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{S as default}from"./chat-widget-index-
|
|
1
|
+
export{S as default}from"./chat-widget-index-BcPgyNKZ.esm.js";import"react";import"react-dom/client";import"react-dom";import"react/jsx-runtime";
|
package/dist/chat-widget.js
CHANGED
|
@@ -8183,6 +8183,10 @@
|
|
|
8183
8183
|
// (the full follow-up question) on click. Kept here or it's whitelisted
|
|
8184
8184
|
// out before render; click handlers fall back to `text` when absent.
|
|
8185
8185
|
submitText: typeof p.submitText === 'string' ? p.submitText : undefined,
|
|
8186
|
+
// EV-2979: the server mints a per-chip promptId so click rows can
|
|
8187
|
+
// be joined to their impression row. This whitelist would strip it
|
|
8188
|
+
// otherwise. Optional - older payloads simply have none.
|
|
8189
|
+
promptId: typeof p.promptId === 'string' ? p.promptId : undefined,
|
|
8186
8190
|
confidence: typeof p.confidence === 'number' ? p.confidence : undefined
|
|
8187
8191
|
})).filter(p => p.text);
|
|
8188
8192
|
return normalized.length ? normalized : undefined;
|
|
@@ -18799,6 +18803,162 @@
|
|
|
18799
18803
|
});
|
|
18800
18804
|
};
|
|
18801
18805
|
|
|
18806
|
+
/**
|
|
18807
|
+
* EV-2979 - auto-prompt chip CLICK telemetry (client half).
|
|
18808
|
+
*
|
|
18809
|
+
* Impressions are logged server-side at the chip-generation call sites;
|
|
18810
|
+
* clicks can only be observed on the client, so this module is the last
|
|
18811
|
+
* link in the funnel. It posts to the Express support proxy at
|
|
18812
|
+
* `POST /api/v1/support/chip-click`, which re-derives the organization
|
|
18813
|
+
* from the verified widget auth (EV-2388 - the client MUST NOT send an
|
|
18814
|
+
* organizationId) and forwards to knowledge-api.
|
|
18815
|
+
*
|
|
18816
|
+
* Hard rules, in priority order over "did the event land":
|
|
18817
|
+
* 1. Never block, delay or break the chip's real action. Callers must
|
|
18818
|
+
* not await this; every failure path resolves to `false` and never
|
|
18819
|
+
* throws.
|
|
18820
|
+
* 2. Never send PII beyond what the chip itself already contains
|
|
18821
|
+
* (its label, its submit text, its position, the conversation id).
|
|
18822
|
+
* 3. Be a silent no-op when there is nothing safe to send: no API base
|
|
18823
|
+
* URL, no conversation id, or telemetry disabled by config.
|
|
18824
|
+
*
|
|
18825
|
+
* Transport: `navigator.sendBeacon` is preferred because the browser
|
|
18826
|
+
* keeps it in flight across the re-render (and even a navigation) that
|
|
18827
|
+
* a chip click triggers. sendBeacon cannot set request headers, so the
|
|
18828
|
+
* in-app Bearer path (`getAuthToken` present, i.e. session auth) falls
|
|
18829
|
+
* back to `fetch(..., { keepalive: true })`, which has the same
|
|
18830
|
+
* survive-the-unload property but can carry Authorization. Mode B
|
|
18831
|
+
* embeds have no token - the HMAC signature is added by the
|
|
18832
|
+
* @eshal-bot/server proxy - so those take the sendBeacon path.
|
|
18833
|
+
*/
|
|
18834
|
+
|
|
18835
|
+
const CHIP_CLICK_PATH = '/api/v1/support/chip-click';
|
|
18836
|
+
|
|
18837
|
+
/**
|
|
18838
|
+
* Builds the wire payload for a chip click.
|
|
18839
|
+
*
|
|
18840
|
+
* `chipText` is deliberately the chip's SHORT LABEL (`text`), not the
|
|
18841
|
+
* displayed question (`submitText`): impression rows store `chip_text`
|
|
18842
|
+
* from `text`, so using the label is what makes clicks joinable to
|
|
18843
|
+
* impressions. EV-2977 changed only what the chip DISPLAYS.
|
|
18844
|
+
*
|
|
18845
|
+
* @param {{chip?: object|string, submitText?: string, position?: number,
|
|
18846
|
+
* conversationId?: string, source?: string}} args
|
|
18847
|
+
* @returns {object|null} payload, or null when there is no usable chipText
|
|
18848
|
+
*/
|
|
18849
|
+
function buildChipClickPayload() {
|
|
18850
|
+
let {
|
|
18851
|
+
chip,
|
|
18852
|
+
submitText,
|
|
18853
|
+
position,
|
|
18854
|
+
conversationId,
|
|
18855
|
+
source = 'widget'
|
|
18856
|
+
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
18857
|
+
const isObject = chip && typeof chip === 'object';
|
|
18858
|
+
const label = isObject && typeof chip.text === 'string' ? chip.text : '';
|
|
18859
|
+
const submit = typeof submitText === 'string' && submitText ? submitText : isObject && typeof chip.submitText === 'string' ? chip.submitText : typeof chip === 'string' ? chip : '';
|
|
18860
|
+
const chipText = label || submit;
|
|
18861
|
+
if (!chipText) return null;
|
|
18862
|
+
const payload = {
|
|
18863
|
+
conversationId,
|
|
18864
|
+
chipText,
|
|
18865
|
+
submitText: submit || undefined,
|
|
18866
|
+
position: Number.isInteger(position) ? position : undefined,
|
|
18867
|
+
source
|
|
18868
|
+
};
|
|
18869
|
+
|
|
18870
|
+
// The chip payload is growing a `promptId` concurrently. Read it
|
|
18871
|
+
// defensively and simply omit the key until it exists - this must
|
|
18872
|
+
// never become a hard dependency.
|
|
18873
|
+
const promptId = isObject ? chip === null || chip === void 0 ? void 0 : chip.promptId : undefined;
|
|
18874
|
+
if (typeof promptId === 'string' && promptId) payload.promptId = promptId;
|
|
18875
|
+
return payload;
|
|
18876
|
+
}
|
|
18877
|
+
|
|
18878
|
+
/**
|
|
18879
|
+
* Fire-and-forget chip-click beacon.
|
|
18880
|
+
*
|
|
18881
|
+
* @param {object} args
|
|
18882
|
+
* @param {string} [args.apiBaseUrl] Support API base (same one /csat uses).
|
|
18883
|
+
* @param {string} [args.conversationId] Required; no conversation = no event.
|
|
18884
|
+
* @param {object|string} [args.chip] The chip object from the suggestions row.
|
|
18885
|
+
* @param {string} [args.submitText] What the click submits.
|
|
18886
|
+
* @param {number} [args.position] 0-based index within the strip.
|
|
18887
|
+
* @param {string} [args.source] Surface id, defaults to "widget".
|
|
18888
|
+
* @param {Function} [args.getAuthToken] Optional async () => token (in-app path).
|
|
18889
|
+
* @param {boolean} [args.enabled] Config kill-switch, defaults to true.
|
|
18890
|
+
* @returns {Promise<boolean>} true only if a request was actually dispatched.
|
|
18891
|
+
*/
|
|
18892
|
+
async function sendChipClickBeacon() {
|
|
18893
|
+
let {
|
|
18894
|
+
apiBaseUrl,
|
|
18895
|
+
conversationId,
|
|
18896
|
+
chip,
|
|
18897
|
+
submitText,
|
|
18898
|
+
position,
|
|
18899
|
+
source = 'widget',
|
|
18900
|
+
getAuthToken,
|
|
18901
|
+
enabled = true
|
|
18902
|
+
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
18903
|
+
try {
|
|
18904
|
+
if (enabled === false) return false;
|
|
18905
|
+
if (!apiBaseUrl || typeof apiBaseUrl !== 'string') return false;
|
|
18906
|
+
if (!conversationId || typeof conversationId !== 'string') return false;
|
|
18907
|
+
const payload = buildChipClickPayload({
|
|
18908
|
+
chip,
|
|
18909
|
+
submitText,
|
|
18910
|
+
position,
|
|
18911
|
+
conversationId,
|
|
18912
|
+
source
|
|
18913
|
+
});
|
|
18914
|
+
if (!payload) return false;
|
|
18915
|
+
const url = "".concat(apiBaseUrl.replace(/\/$/, '')).concat(CHIP_CLICK_PATH);
|
|
18916
|
+
const body = JSON.stringify(payload);
|
|
18917
|
+
let token;
|
|
18918
|
+
if (typeof getAuthToken === 'function') {
|
|
18919
|
+
try {
|
|
18920
|
+
token = await getAuthToken();
|
|
18921
|
+
} catch (_unused) {
|
|
18922
|
+
token = undefined;
|
|
18923
|
+
}
|
|
18924
|
+
}
|
|
18925
|
+
|
|
18926
|
+
// No Authorization header needed -> sendBeacon, the most
|
|
18927
|
+
// re-render/unload-proof transport available.
|
|
18928
|
+
if (!token && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function' && typeof Blob !== 'undefined') {
|
|
18929
|
+
try {
|
|
18930
|
+
const queued = navigator.sendBeacon(url, new Blob([body], {
|
|
18931
|
+
type: 'application/json'
|
|
18932
|
+
}));
|
|
18933
|
+
if (queued) return true;
|
|
18934
|
+
// sendBeacon returns false when the user agent refuses to queue
|
|
18935
|
+
// (payload over the per-origin budget); fall through to fetch.
|
|
18936
|
+
} catch (_unused2) {
|
|
18937
|
+
// Fall through to fetch.
|
|
18938
|
+
}
|
|
18939
|
+
}
|
|
18940
|
+
if (typeof fetch !== 'function') return false;
|
|
18941
|
+
const headers = {
|
|
18942
|
+
'Content-Type': 'application/json'
|
|
18943
|
+
};
|
|
18944
|
+
if (token) headers.Authorization = "Bearer ".concat(token);
|
|
18945
|
+
|
|
18946
|
+
// Not awaited by callers; keepalive keeps it alive past the
|
|
18947
|
+
// re-render the click causes.
|
|
18948
|
+
await fetch(url, {
|
|
18949
|
+
method: 'POST',
|
|
18950
|
+
headers,
|
|
18951
|
+
credentials: 'include',
|
|
18952
|
+
keepalive: true,
|
|
18953
|
+
body
|
|
18954
|
+
});
|
|
18955
|
+
return true;
|
|
18956
|
+
} catch (_unused3) {
|
|
18957
|
+
// Telemetry only - never surface to the user, never rethrow.
|
|
18958
|
+
return false;
|
|
18959
|
+
}
|
|
18960
|
+
}
|
|
18961
|
+
|
|
18802
18962
|
const DEFAULT_AGENT_BUBBLE_COLOR = "#ffffff";
|
|
18803
18963
|
const DEFAULT_USER_MESSAGE_COLOR = "#f5f5f5";
|
|
18804
18964
|
const DEFAULT_TEXT_COLOR = "#000000";
|
|
@@ -18915,6 +19075,9 @@
|
|
|
18915
19075
|
// (submitText) instead of the title-case label. Display-only;
|
|
18916
19076
|
// kill-switch via behavior.autoPromptQuestionDisplay (default on).
|
|
18917
19077
|
autoPromptQuestionDisplay = true,
|
|
19078
|
+
// EV-2979: fire-and-forget click telemetry for auto-prompt chips.
|
|
19079
|
+
// Kill-switch via behavior.autoPromptClickTelemetry (default on).
|
|
19080
|
+
autoPromptClickTelemetry = true,
|
|
18918
19081
|
allowFeedback = true,
|
|
18919
19082
|
provideCitations = true,
|
|
18920
19083
|
onFeedback,
|
|
@@ -18951,37 +19114,23 @@
|
|
|
18951
19114
|
(_panelRef$current = panelRef.current) === null || _panelRef$current === void 0 || _panelRef$current.focus();
|
|
18952
19115
|
}, []);
|
|
18953
19116
|
|
|
18954
|
-
// EV-2842 - chip click telemetry. Fire-and-forget POST to
|
|
18955
|
-
//
|
|
19117
|
+
// EV-2842 / EV-2979 - chip click telemetry. Fire-and-forget POST to
|
|
19118
|
+
// the verified support proxy (same auth pattern as the CSAT calls
|
|
18956
19119
|
// below). A telemetry failure must never block or delay submitting
|
|
18957
|
-
// the chip's text, so this is never awaited and
|
|
18958
|
-
|
|
18959
|
-
|
|
18960
|
-
|
|
18961
|
-
|
|
18962
|
-
|
|
18963
|
-
|
|
18964
|
-
|
|
18965
|
-
|
|
18966
|
-
|
|
18967
|
-
|
|
18968
|
-
|
|
18969
|
-
|
|
18970
|
-
|
|
18971
|
-
credentials: "include",
|
|
18972
|
-
keepalive: true,
|
|
18973
|
-
body: JSON.stringify({
|
|
18974
|
-
conversationId,
|
|
18975
|
-
chipText: prompt && prompt.text || String(submitValue !== null && submitValue !== void 0 ? submitValue : ""),
|
|
18976
|
-
submitText: String(submitValue !== null && submitValue !== void 0 ? submitValue : ""),
|
|
18977
|
-
position: Number.isInteger(index) ? index : undefined,
|
|
18978
|
-
source: "widget"
|
|
18979
|
-
})
|
|
18980
|
-
});
|
|
18981
|
-
} catch (_unused) {
|
|
18982
|
-
// Telemetry only - never surface to the user.
|
|
18983
|
-
}
|
|
18984
|
-
}, [apiBaseUrl, getAuthToken, conversationId]);
|
|
19120
|
+
// the chip's text, so this is never awaited and sendChipClickBeacon
|
|
19121
|
+
// swallows everything internally.
|
|
19122
|
+
const reportChipClick = reactExports.useCallback((submitValue, prompt, index) => {
|
|
19123
|
+
void sendChipClickBeacon({
|
|
19124
|
+
apiBaseUrl,
|
|
19125
|
+
conversationId,
|
|
19126
|
+
chip: prompt,
|
|
19127
|
+
submitText: submitValue == null ? undefined : String(submitValue),
|
|
19128
|
+
position: index,
|
|
19129
|
+
source: "widget",
|
|
19130
|
+
getAuthToken,
|
|
19131
|
+
enabled: autoPromptClickTelemetry
|
|
19132
|
+
});
|
|
19133
|
+
}, [apiBaseUrl, getAuthToken, conversationId, autoPromptClickTelemetry]);
|
|
18985
19134
|
const stableOnPromptSuggestionClick = reactExports.useCallback((text, prompt, index) => {
|
|
18986
19135
|
// EV-2842: record the chip click (not awaited). Only fires when a
|
|
18987
19136
|
// prompt OBJECT rode along - i.e. a real auto-prompt chip row -
|
|
@@ -19003,7 +19152,7 @@
|
|
|
19003
19152
|
if (!raw) return null;
|
|
19004
19153
|
const parsed = JSON.parse(raw);
|
|
19005
19154
|
if (typeof (parsed === null || parsed === void 0 ? void 0 : parsed.width) === "number" && typeof (parsed === null || parsed === void 0 ? void 0 : parsed.height) === "number" && parsed.width >= _WIDGET_MIN_W && parsed.height >= _WIDGET_MIN_H) return parsed;
|
|
19006
|
-
} catch (
|
|
19155
|
+
} catch (_unused) {/* fall through */}
|
|
19007
19156
|
return null;
|
|
19008
19157
|
});
|
|
19009
19158
|
const resizeAxisRef = reactExports.useRef(null);
|
|
@@ -19051,7 +19200,7 @@
|
|
|
19051
19200
|
if (!widgetSize) return;
|
|
19052
19201
|
try {
|
|
19053
19202
|
window.localStorage.setItem(_WIDGET_SIZE_KEY, JSON.stringify(widgetSize));
|
|
19054
|
-
} catch (
|
|
19203
|
+
} catch (_unused2) {/* ignore */}
|
|
19055
19204
|
}, [widgetSize]);
|
|
19056
19205
|
const handleResizeStart = (axis, e) => {
|
|
19057
19206
|
e.preventDefault();
|
|
@@ -19079,7 +19228,7 @@
|
|
|
19079
19228
|
try {
|
|
19080
19229
|
var _getSession$csatSubmi, _getSession;
|
|
19081
19230
|
return (_getSession$csatSubmi = (_getSession = getSession(organizationId)) === null || _getSession === void 0 ? void 0 : _getSession.csatSubmitted) !== null && _getSession$csatSubmi !== void 0 ? _getSession$csatSubmi : false;
|
|
19082
|
-
} catch (
|
|
19231
|
+
} catch (_unused3) {
|
|
19083
19232
|
return false;
|
|
19084
19233
|
}
|
|
19085
19234
|
});
|
|
@@ -19098,7 +19247,7 @@
|
|
|
19098
19247
|
const submitted = (_getSession$csatSubmi2 = (_getSession2 = getSession(organizationId)) === null || _getSession2 === void 0 ? void 0 : _getSession2.csatSubmitted) !== null && _getSession$csatSubmi2 !== void 0 ? _getSession$csatSubmi2 : false;
|
|
19099
19248
|
setCsatSubmitted(submitted);
|
|
19100
19249
|
if (submitted) setShowCsat(false);
|
|
19101
|
-
} catch (
|
|
19250
|
+
} catch (_unused4) {}
|
|
19102
19251
|
}, [conversationId]);
|
|
19103
19252
|
|
|
19104
19253
|
// Auto-scroll hook
|
|
@@ -20080,7 +20229,7 @@
|
|
|
20080
20229
|
|
|
20081
20230
|
// Map API response to widget props (use props as overrides if provided)
|
|
20082
20231
|
const widgetConfig = reactExports.useMemo(() => {
|
|
20083
|
-
var _agentConfig$config, _cfg$identity, _cfg$branding, _cfg$typography, _cfg$messages, _cfg$voice, _cfg$onboarding, _cfg$disclaimer, _cfg$csat, _cfg$inactivity, _cfg$behavior, _cfg$security, _cfg$layout, _ref2, _messages$bundles$loc, _messages$bundles, _messages$bundles$en, _messages$bundles2, _ref3, _ref4, _security$domains, _ref5, _ref6, _ref7, _branding$chatbotAvat, _branding$chatbotAvat2, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _ref13, _typography$headerTex, _identity$subtitle, _identity$showStatus, _identity$statusMode, _identity$officeHours, _ref14, _ref15, _ref16, _ref17, _ref18, _ref19, _inactivity$timeoutVa, _inactivity$timeoutUn, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _ref26, _ref27, _csat$enabled, _csat$format, _csat$prompt, _csat$triggerType, _csat$idleTimeoutMins, _csat$followUpEnabled, _csat$followUpPrompt, _behavior$autoPromptE, _behavior$autoPromptQ, _behavior$allowFeedba, _behavior$provideCita, _agentConfig$organiza, _cfg$chatFeatures;
|
|
20232
|
+
var _agentConfig$config, _cfg$identity, _cfg$branding, _cfg$typography, _cfg$messages, _cfg$voice, _cfg$onboarding, _cfg$disclaimer, _cfg$csat, _cfg$inactivity, _cfg$behavior, _cfg$security, _cfg$layout, _ref2, _messages$bundles$loc, _messages$bundles, _messages$bundles$en, _messages$bundles2, _ref3, _ref4, _security$domains, _ref5, _ref6, _ref7, _branding$chatbotAvat, _branding$chatbotAvat2, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _ref13, _typography$headerTex, _identity$subtitle, _identity$showStatus, _identity$statusMode, _identity$officeHours, _ref14, _ref15, _ref16, _ref17, _ref18, _ref19, _inactivity$timeoutVa, _inactivity$timeoutUn, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _ref26, _ref27, _csat$enabled, _csat$format, _csat$prompt, _csat$triggerType, _csat$idleTimeoutMins, _csat$followUpEnabled, _csat$followUpPrompt, _behavior$autoPromptE, _behavior$autoPromptQ, _behavior$autoPromptC, _behavior$allowFeedba, _behavior$provideCita, _agentConfig$organiza, _cfg$chatFeatures;
|
|
20084
20233
|
if (!agentConfig) {
|
|
20085
20234
|
return null;
|
|
20086
20235
|
}
|
|
@@ -20180,6 +20329,11 @@
|
|
|
20180
20329
|
// (submit payload untouched). Kill-switch per deployment: set
|
|
20181
20330
|
// behavior.autoPromptQuestionDisplay=false to revert to labels.
|
|
20182
20331
|
autoPromptQuestionDisplay: (_behavior$autoPromptQ = behavior.autoPromptQuestionDisplay) !== null && _behavior$autoPromptQ !== void 0 ? _behavior$autoPromptQ : true,
|
|
20332
|
+
// EV-2979: fire-and-forget chip-click telemetry (the click half of
|
|
20333
|
+
// the impression funnel). Default on; set
|
|
20334
|
+
// behavior.autoPromptClickTelemetry=false to silence it for a
|
|
20335
|
+
// deployment that does not want click events recorded.
|
|
20336
|
+
autoPromptClickTelemetry: (_behavior$autoPromptC = behavior.autoPromptClickTelemetry) !== null && _behavior$autoPromptC !== void 0 ? _behavior$autoPromptC : true,
|
|
20183
20337
|
allowFeedback: (_behavior$allowFeedba = behavior.allowFeedback) !== null && _behavior$allowFeedba !== void 0 ? _behavior$allowFeedba : true,
|
|
20184
20338
|
// behavior.provideCitations - when false, hide the Sources panel on
|
|
20185
20339
|
// every message and tell the backend to skip citation generation.
|
|
@@ -20478,6 +20632,7 @@
|
|
|
20478
20632
|
onResetConversation: resetConversation,
|
|
20479
20633
|
autoPromptEnabled: widgetConfig.autoPromptEnabled,
|
|
20480
20634
|
autoPromptQuestionDisplay: widgetConfig.autoPromptQuestionDisplay,
|
|
20635
|
+
autoPromptClickTelemetry: widgetConfig.autoPromptClickTelemetry,
|
|
20481
20636
|
allowFeedback: widgetConfig.allowFeedback,
|
|
20482
20637
|
provideCitations: widgetConfig.provideCitations,
|
|
20483
20638
|
onFeedback: handleMessageFeedback,
|