@eshal-bot/chat-widget 0.1.97 → 0.1.99
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-BjWO1Sot.esm.js → chat-widget-MarkdownRenderer-DPwT1hDQ.esm.js} +1 -1
- package/dist/{chat-widget-index-CHqB62M7.esm.js → chat-widget-index-BHNeh4MK.esm.js} +1 -1
- package/dist/chat-widget.esm.js +1 -1
- package/dist/chat-widget.js +152 -15
- package/dist/chat-widget.min.js +5 -5
- 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-BHNeh4MK.esm.js";import"react";import"react-dom/client";import"react-dom";import"react/jsx-runtime";
|
package/dist/chat-widget.js
CHANGED
|
@@ -16546,13 +16546,43 @@
|
|
|
16546
16546
|
message: backendMsg
|
|
16547
16547
|
};
|
|
16548
16548
|
}
|
|
16549
|
-
|
|
16549
|
+
|
|
16550
|
+
// Give back session budget the backend reserved at /presign admission time
|
|
16551
|
+
// (EV-2791) - fired when a chip is removed or its upload fails AFTER that
|
|
16552
|
+
// reservation succeeded, so a not-actually-sent file doesn't permanently
|
|
16553
|
+
// inflate the conversation's "used" total for the rest of the session TTL.
|
|
16554
|
+
// Fire-and-forget: a failed release just leaves the budget a bit tighter
|
|
16555
|
+
// than it truly is, never more permissive, so it's safe to ignore errors.
|
|
16556
|
+
function releaseSessionBytes(_ref2) {
|
|
16557
|
+
let {
|
|
16558
|
+
apiEndpoint,
|
|
16559
|
+
conversationId,
|
|
16560
|
+
size,
|
|
16561
|
+
authHeader
|
|
16562
|
+
} = _ref2;
|
|
16563
|
+
fetch(joinUrl(apiEndpoint, "/api/v1/chat-attachments/release"), {
|
|
16564
|
+
method: "POST",
|
|
16565
|
+
credentials: "include",
|
|
16566
|
+
headers: _objectSpread2({
|
|
16567
|
+
"Content-Type": "application/json"
|
|
16568
|
+
}, authHeader ? {
|
|
16569
|
+
Authorization: authHeader
|
|
16570
|
+
} : {}),
|
|
16571
|
+
body: JSON.stringify({
|
|
16572
|
+
conversationId,
|
|
16573
|
+
size
|
|
16574
|
+
})
|
|
16575
|
+
}).catch(() => {
|
|
16576
|
+
/* best-effort - see comment above */
|
|
16577
|
+
});
|
|
16578
|
+
}
|
|
16579
|
+
function putWithProgress(_ref3) {
|
|
16550
16580
|
let {
|
|
16551
16581
|
url,
|
|
16552
16582
|
file,
|
|
16553
16583
|
onProgress,
|
|
16554
16584
|
registerXhr
|
|
16555
|
-
} =
|
|
16585
|
+
} = _ref3;
|
|
16556
16586
|
return new Promise((resolve, reject) => {
|
|
16557
16587
|
const xhr = new XMLHttpRequest();
|
|
16558
16588
|
registerXhr(xhr);
|
|
@@ -16583,7 +16613,7 @@
|
|
|
16583
16613
|
// `url` is consumed today (READ SAS URL that knowledge-api's
|
|
16584
16614
|
// attachment_ingest fetches bytes from). Malformed / empty JSON
|
|
16585
16615
|
// resolves to `{}` - the upload succeeded, the read URL is best-effort.
|
|
16586
|
-
function postMultipartWithProgress(
|
|
16616
|
+
function postMultipartWithProgress(_ref4) {
|
|
16587
16617
|
let {
|
|
16588
16618
|
url,
|
|
16589
16619
|
file,
|
|
@@ -16591,7 +16621,7 @@
|
|
|
16591
16621
|
authHeader,
|
|
16592
16622
|
onProgress,
|
|
16593
16623
|
registerXhr
|
|
16594
|
-
} =
|
|
16624
|
+
} = _ref4;
|
|
16595
16625
|
return new Promise((resolve, reject) => {
|
|
16596
16626
|
const xhr = new XMLHttpRequest();
|
|
16597
16627
|
registerXhr(xhr);
|
|
@@ -16636,14 +16666,14 @@
|
|
|
16636
16666
|
xhr.send(form);
|
|
16637
16667
|
});
|
|
16638
16668
|
}
|
|
16639
|
-
function useFileUpload(
|
|
16669
|
+
function useFileUpload(_ref5) {
|
|
16640
16670
|
let {
|
|
16641
16671
|
conversationId,
|
|
16642
16672
|
config,
|
|
16643
16673
|
apiEndpoint,
|
|
16644
16674
|
authHeader,
|
|
16645
16675
|
onError
|
|
16646
|
-
} =
|
|
16676
|
+
} = _ref5;
|
|
16647
16677
|
const [attachments, setAttachments] = reactExports.useState([]);
|
|
16648
16678
|
const inflightRef = reactExports.useRef(new Map());
|
|
16649
16679
|
const idCounterRef = reactExports.useRef(0);
|
|
@@ -16746,6 +16776,9 @@
|
|
|
16746
16776
|
})
|
|
16747
16777
|
});
|
|
16748
16778
|
} catch (err) {
|
|
16779
|
+
// Never reached the server - no reservation was ever made, so just
|
|
16780
|
+
// undo this attachment's optimistic client-side estimate (EV-2791).
|
|
16781
|
+
sessionBytesRef.current.bytes = Math.max(0, sessionBytesRef.current.bytes - file.size);
|
|
16749
16782
|
errorPatch(attachmentId, "network", "Network error while requesting upload.");
|
|
16750
16783
|
return;
|
|
16751
16784
|
}
|
|
@@ -16759,13 +16792,34 @@
|
|
|
16759
16792
|
} catch (_unused4) {
|
|
16760
16793
|
/* body not JSON - keep defaults */
|
|
16761
16794
|
}
|
|
16795
|
+
// decideAttachmentPolicy rejects BEFORE reserving budget, so there's
|
|
16796
|
+
// nothing to release server-side - only undo the client estimate.
|
|
16797
|
+
sessionBytesRef.current.bytes = Math.max(0, sessionBytesRef.current.bytes - file.size);
|
|
16762
16798
|
errorPatch(attachmentId, backendCode, backendMsg);
|
|
16763
16799
|
return;
|
|
16764
16800
|
}
|
|
16801
|
+
|
|
16802
|
+
// presignRes.ok means decideAttachmentPolicy's LAST step ran -
|
|
16803
|
+
// addSessionBytes already reserved this file's bytes server-side.
|
|
16804
|
+
// Mark it so removeAttachment (and every error path below) knows to
|
|
16805
|
+
// call /release rather than just correcting the client estimate.
|
|
16806
|
+
patchAttachment(attachmentId, {
|
|
16807
|
+
reservedBytes: file.size
|
|
16808
|
+
});
|
|
16765
16809
|
let presign;
|
|
16766
16810
|
try {
|
|
16767
16811
|
presign = await presignRes.json();
|
|
16768
16812
|
} catch (_unused5) {
|
|
16813
|
+
releaseSessionBytes({
|
|
16814
|
+
apiEndpoint,
|
|
16815
|
+
conversationId,
|
|
16816
|
+
size: file.size,
|
|
16817
|
+
authHeader
|
|
16818
|
+
});
|
|
16819
|
+
sessionBytesRef.current.bytes = Math.max(0, sessionBytesRef.current.bytes - file.size);
|
|
16820
|
+
patchAttachment(attachmentId, {
|
|
16821
|
+
reservedBytes: 0
|
|
16822
|
+
});
|
|
16769
16823
|
errorPatch(attachmentId, "unknown", "Malformed presign response.");
|
|
16770
16824
|
return;
|
|
16771
16825
|
}
|
|
@@ -16824,6 +16878,16 @@
|
|
|
16824
16878
|
});
|
|
16825
16879
|
if (!confirmed.ok) {
|
|
16826
16880
|
inflightRef.current.delete(attachmentId);
|
|
16881
|
+
releaseSessionBytes({
|
|
16882
|
+
apiEndpoint,
|
|
16883
|
+
conversationId,
|
|
16884
|
+
size: file.size,
|
|
16885
|
+
authHeader
|
|
16886
|
+
});
|
|
16887
|
+
sessionBytesRef.current.bytes = Math.max(0, sessionBytesRef.current.bytes - file.size);
|
|
16888
|
+
patchAttachment(attachmentId, {
|
|
16889
|
+
reservedBytes: 0
|
|
16890
|
+
});
|
|
16827
16891
|
errorPatch(attachmentId, confirmed.code, confirmed.message);
|
|
16828
16892
|
return;
|
|
16829
16893
|
}
|
|
@@ -16832,7 +16896,19 @@
|
|
|
16832
16896
|
}
|
|
16833
16897
|
} catch (err) {
|
|
16834
16898
|
inflightRef.current.delete(attachmentId);
|
|
16899
|
+
// Aborted means removeAttachment already released this reservation -
|
|
16900
|
+
// releasing again here would double-count the give-back.
|
|
16835
16901
|
if (err && err.aborted) return;
|
|
16902
|
+
releaseSessionBytes({
|
|
16903
|
+
apiEndpoint,
|
|
16904
|
+
conversationId,
|
|
16905
|
+
size: file.size,
|
|
16906
|
+
authHeader
|
|
16907
|
+
});
|
|
16908
|
+
sessionBytesRef.current.bytes = Math.max(0, sessionBytesRef.current.bytes - file.size);
|
|
16909
|
+
patchAttachment(attachmentId, {
|
|
16910
|
+
reservedBytes: 0
|
|
16911
|
+
});
|
|
16836
16912
|
errorPatch(attachmentId, "network", "Upload failed. Please retry.");
|
|
16837
16913
|
return;
|
|
16838
16914
|
}
|
|
@@ -16875,7 +16951,11 @@
|
|
|
16875
16951
|
size: file.size,
|
|
16876
16952
|
mimeType: file.type,
|
|
16877
16953
|
status: "uploading",
|
|
16878
|
-
progress: 0
|
|
16954
|
+
progress: 0,
|
|
16955
|
+
// Set once /presign confirms the server actually reserved this
|
|
16956
|
+
// file's bytes (EV-2791) - removeAttachment uses it to decide
|
|
16957
|
+
// whether a removal needs to call /release.
|
|
16958
|
+
reservedBytes: 0
|
|
16879
16959
|
};
|
|
16880
16960
|
setAttachments(prev => [...prev, entry]);
|
|
16881
16961
|
// Reserve session budget at ADMISSION, not upload completion -
|
|
@@ -16892,8 +16972,22 @@
|
|
|
16892
16972
|
xhr.abort();
|
|
16893
16973
|
inflightRef.current.delete(id);
|
|
16894
16974
|
}
|
|
16975
|
+
// EV-2791: a chip removed before Send had its bytes reserved server-side
|
|
16976
|
+
// at /presign admission time - give them back, or the session's "used"
|
|
16977
|
+
// total stays inflated by every file the user attached-then-removed,
|
|
16978
|
+
// for the rest of the 24h session TTL.
|
|
16979
|
+
const removed = attachmentsRef.current.find(a => a.id === id);
|
|
16980
|
+
if (removed && removed.reservedBytes > 0) {
|
|
16981
|
+
releaseSessionBytes({
|
|
16982
|
+
apiEndpoint,
|
|
16983
|
+
conversationId,
|
|
16984
|
+
size: removed.reservedBytes,
|
|
16985
|
+
authHeader
|
|
16986
|
+
});
|
|
16987
|
+
sessionBytesRef.current.bytes = Math.max(0, sessionBytesRef.current.bytes - removed.reservedBytes);
|
|
16988
|
+
}
|
|
16895
16989
|
setAttachments(prev => prev.filter(a => a.id !== id));
|
|
16896
|
-
}, []);
|
|
16990
|
+
}, [apiEndpoint, authHeader, conversationId]);
|
|
16897
16991
|
const clearAll = reactExports.useCallback(() => {
|
|
16898
16992
|
for (const xhr of inflightRef.current.values()) xhr.abort();
|
|
16899
16993
|
inflightRef.current.clear();
|
|
@@ -17075,7 +17169,11 @@
|
|
|
17075
17169
|
},
|
|
17076
17170
|
children: suggestions.map((p, index) => /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
17077
17171
|
type: "button",
|
|
17078
|
-
onClick: () =>
|
|
17172
|
+
onClick: () =>
|
|
17173
|
+
// EV-2842: pass the prompt object + position so the click
|
|
17174
|
+
// handler can record telemetry; extra args are ignored by
|
|
17175
|
+
// handlers that only read the submit value.
|
|
17176
|
+
onSuggestionClick(p.submitText || p.text || p, p, index),
|
|
17079
17177
|
dir: "auto",
|
|
17080
17178
|
className: "inline-flex items-center rounded-full px-4 py-1.5 whitespace-nowrap flex-shrink-0 border-0 transition-transform duration-150 active:scale-95",
|
|
17081
17179
|
style: {
|
|
@@ -18758,9 +18856,48 @@
|
|
|
18758
18856
|
var _panelRef$current;
|
|
18759
18857
|
(_panelRef$current = panelRef.current) === null || _panelRef$current === void 0 || _panelRef$current.focus();
|
|
18760
18858
|
}, []);
|
|
18761
|
-
|
|
18859
|
+
|
|
18860
|
+
// EV-2842 - chip click telemetry. Fire-and-forget POST to the
|
|
18861
|
+
// HMAC-verified support proxy (same auth pattern as the CSAT calls
|
|
18862
|
+
// below). A telemetry failure must never block or delay submitting
|
|
18863
|
+
// the chip's text, so this is never awaited and swallows everything.
|
|
18864
|
+
const reportChipClick = reactExports.useCallback(async (submitValue, prompt, index) => {
|
|
18865
|
+
try {
|
|
18866
|
+
if (!apiBaseUrl) return;
|
|
18867
|
+
const headers = {
|
|
18868
|
+
"Content-Type": "application/json"
|
|
18869
|
+
};
|
|
18870
|
+
if (typeof getAuthToken === "function") {
|
|
18871
|
+
const token = await getAuthToken();
|
|
18872
|
+
if (token) headers["Authorization"] = "Bearer ".concat(token);
|
|
18873
|
+
}
|
|
18874
|
+
await fetch("".concat(apiBaseUrl.replace(/\/$/, ""), "/api/v1/support/chip-click"), {
|
|
18875
|
+
method: "POST",
|
|
18876
|
+
headers,
|
|
18877
|
+
credentials: "include",
|
|
18878
|
+
keepalive: true,
|
|
18879
|
+
body: JSON.stringify({
|
|
18880
|
+
conversationId,
|
|
18881
|
+
chipText: prompt && prompt.text || String(submitValue !== null && submitValue !== void 0 ? submitValue : ""),
|
|
18882
|
+
submitText: String(submitValue !== null && submitValue !== void 0 ? submitValue : ""),
|
|
18883
|
+
position: Number.isInteger(index) ? index : undefined,
|
|
18884
|
+
source: "widget"
|
|
18885
|
+
})
|
|
18886
|
+
});
|
|
18887
|
+
} catch (_unused) {
|
|
18888
|
+
// Telemetry only - never surface to the user.
|
|
18889
|
+
}
|
|
18890
|
+
}, [apiBaseUrl, getAuthToken, conversationId]);
|
|
18891
|
+
const stableOnPromptSuggestionClick = reactExports.useCallback((text, prompt, index) => {
|
|
18892
|
+
// EV-2842: record the chip click (not awaited). Only fires when a
|
|
18893
|
+
// prompt OBJECT rode along - i.e. a real auto-prompt chip row -
|
|
18894
|
+
// so A2UI buttons / onboarding handlers that call this with just
|
|
18895
|
+
// a string are not miscounted as chip clicks.
|
|
18896
|
+
if (prompt && typeof prompt === "object") {
|
|
18897
|
+
reportChipClick(text, prompt, index);
|
|
18898
|
+
}
|
|
18762
18899
|
if (onPromptSuggestionClick) onPromptSuggestionClick(text);else onDirectSend === null || onDirectSend === void 0 || onDirectSend(text);
|
|
18763
|
-
}, [onPromptSuggestionClick, onDirectSend]);
|
|
18900
|
+
}, [onPromptSuggestionClick, onDirectSend, reportChipClick]);
|
|
18764
18901
|
|
|
18765
18902
|
// ─── Resizable widget ────────────────────────────────────────────
|
|
18766
18903
|
const anchorRight = launcherPosition.includes("right");
|
|
@@ -18772,7 +18909,7 @@
|
|
|
18772
18909
|
if (!raw) return null;
|
|
18773
18910
|
const parsed = JSON.parse(raw);
|
|
18774
18911
|
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;
|
|
18775
|
-
} catch (
|
|
18912
|
+
} catch (_unused2) {/* fall through */}
|
|
18776
18913
|
return null;
|
|
18777
18914
|
});
|
|
18778
18915
|
const resizeAxisRef = reactExports.useRef(null);
|
|
@@ -18820,7 +18957,7 @@
|
|
|
18820
18957
|
if (!widgetSize) return;
|
|
18821
18958
|
try {
|
|
18822
18959
|
window.localStorage.setItem(_WIDGET_SIZE_KEY, JSON.stringify(widgetSize));
|
|
18823
|
-
} catch (
|
|
18960
|
+
} catch (_unused3) {/* ignore */}
|
|
18824
18961
|
}, [widgetSize]);
|
|
18825
18962
|
const handleResizeStart = (axis, e) => {
|
|
18826
18963
|
e.preventDefault();
|
|
@@ -18848,7 +18985,7 @@
|
|
|
18848
18985
|
try {
|
|
18849
18986
|
var _getSession$csatSubmi, _getSession;
|
|
18850
18987
|
return (_getSession$csatSubmi = (_getSession = getSession(organizationId)) === null || _getSession === void 0 ? void 0 : _getSession.csatSubmitted) !== null && _getSession$csatSubmi !== void 0 ? _getSession$csatSubmi : false;
|
|
18851
|
-
} catch (
|
|
18988
|
+
} catch (_unused4) {
|
|
18852
18989
|
return false;
|
|
18853
18990
|
}
|
|
18854
18991
|
});
|
|
@@ -18867,7 +19004,7 @@
|
|
|
18867
19004
|
const submitted = (_getSession$csatSubmi2 = (_getSession2 = getSession(organizationId)) === null || _getSession2 === void 0 ? void 0 : _getSession2.csatSubmitted) !== null && _getSession$csatSubmi2 !== void 0 ? _getSession$csatSubmi2 : false;
|
|
18868
19005
|
setCsatSubmitted(submitted);
|
|
18869
19006
|
if (submitted) setShowCsat(false);
|
|
18870
|
-
} catch (
|
|
19007
|
+
} catch (_unused5) {}
|
|
18871
19008
|
}, [conversationId]);
|
|
18872
19009
|
|
|
18873
19010
|
// Auto-scroll hook
|