@eshal-bot/chat-widget 0.1.66 → 0.1.67
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.esm.js +2 -2
- package/dist/chat-widget.js +140 -155
- package/dist/chat-widget.min.js +2 -2
- package/dist/chat-widget.umd.js +2 -2
- package/package.json +1 -1
package/dist/chat-widget.js
CHANGED
|
@@ -8010,21 +8010,20 @@
|
|
|
8010
8010
|
* Sends a streaming chat request using fetch
|
|
8011
8011
|
* @param {object} request - Chat request object
|
|
8012
8012
|
* @param {string} apiBaseUrl - Base URL for the API
|
|
8013
|
-
* @param {Function|undefined} getAuthToken - async fn returning a Bearer token (in-app JWT path), or undefined (Mode B proxy)
|
|
8014
8013
|
*/
|
|
8015
|
-
const sendStreamingRequest = async (request, apiBaseUrl,
|
|
8014
|
+
const sendStreamingRequest = async (request, apiBaseUrl, organizationId, secretKey) => {
|
|
8016
8015
|
const headers = {
|
|
8017
8016
|
'Content-Type': 'application/json',
|
|
8018
8017
|
Accept: 'text/event-stream'
|
|
8019
8018
|
};
|
|
8020
8019
|
|
|
8021
|
-
//
|
|
8022
|
-
// Mode B proxy: no
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8020
|
+
// Mode A — secret key (direct embed): key replaces orgId in the header
|
|
8021
|
+
// Mode B — proxy (@eshal-bot/server): no header from widget; proxy injects x-eshal-sig + x-eshal-org
|
|
8022
|
+
// Mode C — legacy: orgId sent directly
|
|
8023
|
+
if (secretKey) {
|
|
8024
|
+
headers['x-eshal-key'] = secretKey;
|
|
8025
|
+
} else if (organizationId) {
|
|
8026
|
+
headers['x-eshal-org'] = organizationId;
|
|
8028
8027
|
}
|
|
8029
8028
|
const response = await fetch("".concat(apiBaseUrl.replace(/\/$/, ''), "/api/v1/support"), {
|
|
8030
8029
|
method: 'POST',
|
|
@@ -9147,7 +9146,7 @@
|
|
|
9147
9146
|
apiBaseUrl,
|
|
9148
9147
|
apiKey,
|
|
9149
9148
|
organizationId,
|
|
9150
|
-
|
|
9149
|
+
secretKey,
|
|
9151
9150
|
autoOpen,
|
|
9152
9151
|
openDelay,
|
|
9153
9152
|
darkMode,
|
|
@@ -9784,7 +9783,7 @@
|
|
|
9784
9783
|
if (apiType === 'userName' || apiType === 'email' || apiType === 'phone') {
|
|
9785
9784
|
// For onboarding fields, just consume the stream without processing.
|
|
9786
9785
|
// Single attempt — no retry, no user-visible partial state to clean up.
|
|
9787
|
-
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl,
|
|
9786
|
+
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, organizationId, secretKey);
|
|
9788
9787
|
const reader = stream.getReader();
|
|
9789
9788
|
const decoder = new TextDecoder();
|
|
9790
9789
|
while (true) {
|
|
@@ -9803,7 +9802,7 @@
|
|
|
9803
9802
|
let lastErr;
|
|
9804
9803
|
for (let attempt = 0; attempt <= STREAM_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
9805
9804
|
try {
|
|
9806
|
-
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl,
|
|
9805
|
+
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, organizationId, secretKey);
|
|
9807
9806
|
await processStream(stream, setMessages);
|
|
9808
9807
|
updateActivity(organizationId);
|
|
9809
9808
|
return {
|
|
@@ -9831,7 +9830,7 @@
|
|
|
9831
9830
|
|
|
9832
9831
|
// Non-chat, non-onboarding apiType (shouldn't currently happen):
|
|
9833
9832
|
// fire and forget, single attempt.
|
|
9834
|
-
await sendStreamingRequest(chatRequest, apiBaseUrl,
|
|
9833
|
+
await sendStreamingRequest(chatRequest, apiBaseUrl, organizationId);
|
|
9835
9834
|
updateActivity(organizationId);
|
|
9836
9835
|
return {
|
|
9837
9836
|
success: true
|
|
@@ -9867,7 +9866,7 @@
|
|
|
9867
9866
|
// UX-M09: release the concurrency guard so the next send can proceed.
|
|
9868
9867
|
isSendingRef.current = false;
|
|
9869
9868
|
}
|
|
9870
|
-
}, [apiBaseUrl, apiKey, getNextMessageId,
|
|
9869
|
+
}, [apiBaseUrl, apiKey, getNextMessageId, organizationId, messages, bidiSessionId, routingChoice, widgetFilter, provideCitations]);
|
|
9871
9870
|
const handleOnboardingFormSubmit = reactExports.useCallback(async answers => {
|
|
9872
9871
|
const questions = getOnboardingQuestions(onboardingQuestions);
|
|
9873
9872
|
if (questions.length === 0) return;
|
|
@@ -94385,7 +94384,7 @@
|
|
|
94385
94384
|
let {
|
|
94386
94385
|
sources = [],
|
|
94387
94386
|
apiBaseUrl,
|
|
94388
|
-
|
|
94387
|
+
organizationId,
|
|
94389
94388
|
isDark,
|
|
94390
94389
|
textColor,
|
|
94391
94390
|
fontFamily,
|
|
@@ -94411,7 +94410,7 @@
|
|
|
94411
94410
|
// corpora that have none of the above.
|
|
94412
94411
|
const _downloadKey = s => s.url || s.source_id || s.source_name || "";
|
|
94413
94412
|
const handleFileDownload = async source => {
|
|
94414
|
-
if (!apiBaseUrl) return;
|
|
94413
|
+
if (!apiBaseUrl || !organizationId) return;
|
|
94415
94414
|
// SharePoint proxy URLs are GET endpoints that stream the file
|
|
94416
94415
|
// directly via Microsoft Graph using the stored OAuth credential.
|
|
94417
94416
|
// Bypass the legacy POST /file-download lookup (which expects an
|
|
@@ -94437,14 +94436,11 @@
|
|
|
94437
94436
|
// set, or future deployments that set it) pass through
|
|
94438
94437
|
// unchanged.
|
|
94439
94438
|
const spUrl = source.url.startsWith("http") ? source.url : "".concat(apiBaseUrl.replace(/\/$/, "")).concat(source.url);
|
|
94440
|
-
const spHeaders = {};
|
|
94441
|
-
if (typeof getAuthToken === 'function') {
|
|
94442
|
-
const token = await getAuthToken();
|
|
94443
|
-
if (token) spHeaders['Authorization'] = "Bearer ".concat(token);
|
|
94444
|
-
}
|
|
94445
94439
|
res = await fetch(spUrl, {
|
|
94446
94440
|
method: "GET",
|
|
94447
|
-
headers:
|
|
94441
|
+
headers: {
|
|
94442
|
+
"x-eshal-org": organizationId
|
|
94443
|
+
},
|
|
94448
94444
|
credentials: "include"
|
|
94449
94445
|
});
|
|
94450
94446
|
} else {
|
|
@@ -94460,18 +94456,15 @@
|
|
|
94460
94456
|
// - source.source_name (the user's original filename)
|
|
94461
94457
|
// Sending both lets the server skip the Milvus resolution
|
|
94462
94458
|
// AND advertise the readable name in Content-Disposition.
|
|
94463
|
-
const dlHeaders = {
|
|
94464
|
-
"Content-Type": "application/json"
|
|
94465
|
-
};
|
|
94466
|
-
if (typeof getAuthToken === 'function') {
|
|
94467
|
-
const token = await getAuthToken();
|
|
94468
|
-
if (token) dlHeaders['Authorization'] = "Bearer ".concat(token);
|
|
94469
|
-
}
|
|
94470
94459
|
res = await fetch(url, {
|
|
94471
94460
|
method: "POST",
|
|
94472
|
-
headers:
|
|
94461
|
+
headers: {
|
|
94462
|
+
"Content-Type": "application/json",
|
|
94463
|
+
"x-eshal-org": organizationId
|
|
94464
|
+
},
|
|
94473
94465
|
credentials: "include",
|
|
94474
94466
|
body: JSON.stringify({
|
|
94467
|
+
org_id: organizationId,
|
|
94475
94468
|
source_id: source.source_id,
|
|
94476
94469
|
file_name: source.url || "",
|
|
94477
94470
|
source_name: source.source_name || ""
|
|
@@ -94656,7 +94649,7 @@
|
|
|
94656
94649
|
conciergeName,
|
|
94657
94650
|
companyName,
|
|
94658
94651
|
apiBaseUrl,
|
|
94659
|
-
|
|
94652
|
+
organizationId,
|
|
94660
94653
|
onPromptSuggestionClick,
|
|
94661
94654
|
allowFeedback = true,
|
|
94662
94655
|
provideCitations = true,
|
|
@@ -94828,7 +94821,7 @@
|
|
|
94828
94821
|
}), /*#__PURE__*/jsxRuntimeExports.jsx(MessageSources, {
|
|
94829
94822
|
sources: message.sources,
|
|
94830
94823
|
apiBaseUrl: apiBaseUrl,
|
|
94831
|
-
|
|
94824
|
+
organizationId: organizationId,
|
|
94832
94825
|
isDark: isDark,
|
|
94833
94826
|
textColor: messageTextColor,
|
|
94834
94827
|
fontFamily: messageFontFamily,
|
|
@@ -94854,7 +94847,7 @@
|
|
|
94854
94847
|
}), /*#__PURE__*/jsxRuntimeExports.jsx(MessageSources, {
|
|
94855
94848
|
sources: message.sources,
|
|
94856
94849
|
apiBaseUrl: apiBaseUrl,
|
|
94857
|
-
|
|
94850
|
+
organizationId: organizationId,
|
|
94858
94851
|
isDark: isDark,
|
|
94859
94852
|
textColor: messageTextColor,
|
|
94860
94853
|
fontFamily: messageFontFamily,
|
|
@@ -95034,7 +95027,7 @@
|
|
|
95034
95027
|
conciergeName,
|
|
95035
95028
|
companyName,
|
|
95036
95029
|
apiBaseUrl,
|
|
95037
|
-
|
|
95030
|
+
organizationId,
|
|
95038
95031
|
onPromptSuggestionClick,
|
|
95039
95032
|
allowFeedback,
|
|
95040
95033
|
provideCitations,
|
|
@@ -95078,7 +95071,7 @@
|
|
|
95078
95071
|
conciergeName: conciergeName,
|
|
95079
95072
|
companyName: companyName,
|
|
95080
95073
|
apiBaseUrl: apiBaseUrl,
|
|
95081
|
-
|
|
95074
|
+
organizationId: organizationId,
|
|
95082
95075
|
onPromptSuggestionClick: onPromptSuggestionClick,
|
|
95083
95076
|
allowFeedback: allowFeedback,
|
|
95084
95077
|
provideCitations: provideCitations,
|
|
@@ -95923,7 +95916,7 @@
|
|
|
95923
95916
|
conciergeName,
|
|
95924
95917
|
companyName,
|
|
95925
95918
|
apiBaseUrl,
|
|
95926
|
-
|
|
95919
|
+
organizationId,
|
|
95927
95920
|
onPromptSuggestionClick,
|
|
95928
95921
|
conversationResetKey,
|
|
95929
95922
|
allowFeedback,
|
|
@@ -96105,7 +96098,7 @@
|
|
|
96105
96098
|
conciergeName: conciergeName,
|
|
96106
96099
|
companyName: companyName,
|
|
96107
96100
|
apiBaseUrl: apiBaseUrl,
|
|
96108
|
-
|
|
96101
|
+
organizationId: organizationId,
|
|
96109
96102
|
allowFeedback: allowFeedback,
|
|
96110
96103
|
provideCitations: provideCitations,
|
|
96111
96104
|
onFeedback: onFeedback,
|
|
@@ -96137,7 +96130,7 @@
|
|
|
96137
96130
|
conciergeName: conciergeName,
|
|
96138
96131
|
companyName: companyName,
|
|
96139
96132
|
apiBaseUrl: apiBaseUrl,
|
|
96140
|
-
|
|
96133
|
+
organizationId: organizationId,
|
|
96141
96134
|
headerTextColor: headerTextColor
|
|
96142
96135
|
}, "skeleton-waiting");
|
|
96143
96136
|
}
|
|
@@ -99652,7 +99645,8 @@
|
|
|
99652
99645
|
showPoweredBy = true,
|
|
99653
99646
|
apiBaseUrl,
|
|
99654
99647
|
apiKey,
|
|
99655
|
-
|
|
99648
|
+
organizationId,
|
|
99649
|
+
secretKey,
|
|
99656
99650
|
conversationId,
|
|
99657
99651
|
conciergeId,
|
|
99658
99652
|
onboardingQuestions = [],
|
|
@@ -99800,7 +99794,7 @@
|
|
|
99800
99794
|
setCsatSubmitted(submitted);
|
|
99801
99795
|
if (submitted) setShowCsat(false);
|
|
99802
99796
|
} catch (_unused4) {}
|
|
99803
|
-
}, [conversationId]);
|
|
99797
|
+
}, [conversationId, organizationId]);
|
|
99804
99798
|
|
|
99805
99799
|
// Auto-scroll hook
|
|
99806
99800
|
useAutoScroll(messagesContainerRef, [messages, isLoading], {
|
|
@@ -99938,15 +99932,14 @@
|
|
|
99938
99932
|
const handleCsatRating = async (rating, format) => {
|
|
99939
99933
|
setCsatSubmitted(true); // optimistic UI
|
|
99940
99934
|
setShowCsat(false);
|
|
99941
|
-
markCsatSubmitted(
|
|
99935
|
+
markCsatSubmitted(organizationId); // persist so page refresh doesn't re-show CSAT
|
|
99942
99936
|
|
|
99943
99937
|
try {
|
|
99944
99938
|
const headers = {
|
|
99945
99939
|
"Content-Type": "application/json"
|
|
99946
99940
|
};
|
|
99947
|
-
if (
|
|
99948
|
-
|
|
99949
|
-
if (token) headers['Authorization'] = "Bearer ".concat(token);
|
|
99941
|
+
if (organizationId) {
|
|
99942
|
+
headers["x-eshal-org"] = organizationId;
|
|
99950
99943
|
}
|
|
99951
99944
|
const response = await fetch("".concat(apiBaseUrl.replace(/\/$/, ""), "/api/v1/support/csat"), {
|
|
99952
99945
|
method: "POST",
|
|
@@ -99956,6 +99949,7 @@
|
|
|
99956
99949
|
conversationId,
|
|
99957
99950
|
rating,
|
|
99958
99951
|
ratingFormat: format,
|
|
99952
|
+
organizationId,
|
|
99959
99953
|
conciergeId
|
|
99960
99954
|
})
|
|
99961
99955
|
});
|
|
@@ -99979,9 +99973,8 @@
|
|
|
99979
99973
|
const headers = {
|
|
99980
99974
|
"Content-Type": "application/json"
|
|
99981
99975
|
};
|
|
99982
|
-
if (
|
|
99983
|
-
|
|
99984
|
-
if (token) headers['Authorization'] = "Bearer ".concat(token);
|
|
99976
|
+
if (organizationId) {
|
|
99977
|
+
headers["x-eshal-org"] = organizationId;
|
|
99985
99978
|
}
|
|
99986
99979
|
const ratingFormat = normalizeCsatFormat(csatFormat);
|
|
99987
99980
|
const response = await fetch("".concat(apiBaseUrl.replace(/\/$/, ""), "/api/v1/support/csat"), {
|
|
@@ -99992,6 +99985,7 @@
|
|
|
99992
99985
|
conversationId,
|
|
99993
99986
|
rating: String(resolveRating),
|
|
99994
99987
|
ratingFormat,
|
|
99988
|
+
organizationId,
|
|
99995
99989
|
conciergeId,
|
|
99996
99990
|
feedback: resolveFeedbackText || undefined
|
|
99997
99991
|
})
|
|
@@ -100025,7 +100019,7 @@
|
|
|
100025
100019
|
} finally {
|
|
100026
100020
|
setIsSubmittingResolve(false);
|
|
100027
100021
|
}
|
|
100028
|
-
}, [isCsatEnabled, isSubmittingResolve, isConversationResolved, resolveRating, resolveFeedbackText, conversationId,
|
|
100022
|
+
}, [isCsatEnabled, isSubmittingResolve, isConversationResolved, resolveRating, resolveFeedbackText, conversationId, organizationId, conciergeId, apiBaseUrl, csatFormat, onResetConversation, onRefreshChat, onWidgetFilterChange]);
|
|
100029
100023
|
|
|
100030
100024
|
// Handle X button: first click shows form, second click closes
|
|
100031
100025
|
const handleCloseClick = reactExports.useCallback(() => {
|
|
@@ -100363,7 +100357,7 @@
|
|
|
100363
100357
|
conciergeName: conciergeName,
|
|
100364
100358
|
companyName: companyName,
|
|
100365
100359
|
apiBaseUrl: apiBaseUrl,
|
|
100366
|
-
|
|
100360
|
+
organizationId: organizationId,
|
|
100367
100361
|
conversationResetKey: conversationId,
|
|
100368
100362
|
allowFeedback: allowFeedback,
|
|
100369
100363
|
provideCitations: provideCitations,
|
|
@@ -100448,7 +100442,8 @@
|
|
|
100448
100442
|
|
|
100449
100443
|
/**
|
|
100450
100444
|
* @param {string|undefined|null} apiBaseUrl
|
|
100451
|
-
* @param {
|
|
100445
|
+
* @param {string|undefined|null} orgId
|
|
100446
|
+
* @param {string|undefined|null} secretKey — Mode A/B: orgId resolved server-side
|
|
100452
100447
|
* @returns {{
|
|
100453
100448
|
* categories: Array<{id:string,label:string,count:number,tags:string[]}>,
|
|
100454
100449
|
* loading: boolean,
|
|
@@ -100456,15 +100451,17 @@
|
|
|
100456
100451
|
* hasFilters: boolean,
|
|
100457
100452
|
* }}
|
|
100458
100453
|
*/
|
|
100459
|
-
function useFilterCatalog(apiBaseUrl,
|
|
100460
|
-
|
|
100454
|
+
function useFilterCatalog(apiBaseUrl, orgId, secretKey) {
|
|
100455
|
+
// Mode A: secretKey present, orgId null → key-based endpoint
|
|
100456
|
+
// Mode C: orgId present (legacy) → orgId-in-path endpoint
|
|
100457
|
+
const hasAuth = !!(apiBaseUrl && (orgId || secretKey));
|
|
100461
100458
|
const [state, setState] = reactExports.useState({
|
|
100462
100459
|
categories: [],
|
|
100463
100460
|
loading: hasAuth,
|
|
100464
100461
|
error: null
|
|
100465
100462
|
});
|
|
100466
100463
|
reactExports.useEffect(() => {
|
|
100467
|
-
if (!apiBaseUrl) {
|
|
100464
|
+
if (!apiBaseUrl || !orgId && !secretKey) {
|
|
100468
100465
|
setState({
|
|
100469
100466
|
categories: [],
|
|
100470
100467
|
loading: false,
|
|
@@ -100472,7 +100469,7 @@
|
|
|
100472
100469
|
});
|
|
100473
100470
|
return;
|
|
100474
100471
|
}
|
|
100475
|
-
const cacheKey =
|
|
100472
|
+
const cacheKey = secretKey ? "".concat(apiBaseUrl, "|__key__") : "".concat(apiBaseUrl, "|").concat(orgId);
|
|
100476
100473
|
const cached = _PROCESS_CACHE.get(cacheKey);
|
|
100477
100474
|
if (cached) {
|
|
100478
100475
|
setState({
|
|
@@ -100488,54 +100485,45 @@
|
|
|
100488
100485
|
error: null
|
|
100489
100486
|
}));
|
|
100490
100487
|
const base = apiBaseUrl.replace(/\/$/, "");
|
|
100491
|
-
const url = "".concat(base, "/api/v1/widget/filters");
|
|
100492
|
-
|
|
100493
|
-
|
|
100494
|
-
|
|
100495
|
-
|
|
100496
|
-
|
|
100497
|
-
|
|
100498
|
-
|
|
100499
|
-
|
|
100500
|
-
|
|
100501
|
-
|
|
100502
|
-
headers['Authorization'] = "Bearer ".concat(token);
|
|
100503
|
-
}
|
|
100504
|
-
}
|
|
100505
|
-
const res = await fetch(url, {
|
|
100506
|
-
method: "GET",
|
|
100507
|
-
headers
|
|
100508
|
-
});
|
|
100509
|
-
if (!res.ok) {
|
|
100510
|
-
throw new Error("filter catalog HTTP ".concat(res.status));
|
|
100511
|
-
}
|
|
100512
|
-
const body = await res.json();
|
|
100513
|
-
const categories = Array.isArray(body === null || body === void 0 ? void 0 : body.categories) ? body.categories : [];
|
|
100514
|
-
if (cancelled) return;
|
|
100515
|
-
_PROCESS_CACHE.set(cacheKey, categories);
|
|
100516
|
-
setState({
|
|
100517
|
-
categories,
|
|
100518
|
-
loading: false,
|
|
100519
|
-
error: null
|
|
100520
|
-
});
|
|
100521
|
-
} catch (err) {
|
|
100522
|
-
if (cancelled) return;
|
|
100523
|
-
// Fail-soft: log and present empty so the UI hides itself.
|
|
100524
|
-
// We do NOT bubble the error to the caller because chat
|
|
100525
|
-
// should keep working even if the catalog is unreachable.
|
|
100526
|
-
// eslint-disable-next-line no-console
|
|
100527
|
-
console.warn("[useFilterCatalog] catalog fetch failed:", err);
|
|
100528
|
-
setState({
|
|
100529
|
-
categories: [],
|
|
100530
|
-
loading: false,
|
|
100531
|
-
error: err
|
|
100532
|
-
});
|
|
100488
|
+
const url = secretKey ? "".concat(base, "/api/v1/widget/filters") : "".concat(base, "/api/v1/widget/filters/").concat(encodeURIComponent(orgId));
|
|
100489
|
+
const headers = {
|
|
100490
|
+
Accept: "application/json"
|
|
100491
|
+
};
|
|
100492
|
+
if (secretKey) headers["x-eshal-key"] = secretKey;
|
|
100493
|
+
fetch(url, {
|
|
100494
|
+
method: "GET",
|
|
100495
|
+
headers
|
|
100496
|
+
}).then(async res => {
|
|
100497
|
+
if (!res.ok) {
|
|
100498
|
+
throw new Error("filter catalog HTTP ".concat(res.status));
|
|
100533
100499
|
}
|
|
100534
|
-
|
|
100500
|
+
const body = await res.json();
|
|
100501
|
+
return Array.isArray(body === null || body === void 0 ? void 0 : body.categories) ? body.categories : [];
|
|
100502
|
+
}).then(categories => {
|
|
100503
|
+
if (cancelled) return;
|
|
100504
|
+
_PROCESS_CACHE.set(cacheKey, categories);
|
|
100505
|
+
setState({
|
|
100506
|
+
categories,
|
|
100507
|
+
loading: false,
|
|
100508
|
+
error: null
|
|
100509
|
+
});
|
|
100510
|
+
}).catch(err => {
|
|
100511
|
+
if (cancelled) return;
|
|
100512
|
+
// Fail-soft: log and present empty so the UI hides itself.
|
|
100513
|
+
// We do NOT bubble the error to the caller because chat
|
|
100514
|
+
// should keep working even if the catalog is unreachable.
|
|
100515
|
+
// eslint-disable-next-line no-console
|
|
100516
|
+
console.warn("[useFilterCatalog] catalog fetch failed:", err);
|
|
100517
|
+
setState({
|
|
100518
|
+
categories: [],
|
|
100519
|
+
loading: false,
|
|
100520
|
+
error: err
|
|
100521
|
+
});
|
|
100522
|
+
});
|
|
100535
100523
|
return () => {
|
|
100536
100524
|
cancelled = true;
|
|
100537
100525
|
};
|
|
100538
|
-
}, [apiBaseUrl,
|
|
100526
|
+
}, [apiBaseUrl, orgId, secretKey]);
|
|
100539
100527
|
const hasFilters = reactExports.useMemo(() => Array.isArray(state.categories) && state.categories.length > 0, [state.categories]);
|
|
100540
100528
|
return _objectSpread2(_objectSpread2({}, state), {}, {
|
|
100541
100529
|
hasFilters
|
|
@@ -100614,28 +100602,24 @@
|
|
|
100614
100602
|
/**
|
|
100615
100603
|
* Fetches agent configuration from the deploy-agent endpoint
|
|
100616
100604
|
* @param {string} apiBaseUrl - Base URL for the API
|
|
100617
|
-
* @param {
|
|
100605
|
+
* @param {string} orgId - Organization ID
|
|
100618
100606
|
* @returns {Promise<object>} Agent configuration object
|
|
100619
100607
|
*/
|
|
100620
|
-
const fetchAgentConfig = async (apiBaseUrl,
|
|
100608
|
+
const fetchAgentConfig = async (apiBaseUrl, orgId, secretKey) => {
|
|
100621
100609
|
if (!apiBaseUrl) {
|
|
100622
100610
|
throw new Error("apiBaseUrl is required");
|
|
100623
100611
|
}
|
|
100612
|
+
// Mode A: secretKey in header, no orgId in URL
|
|
100613
|
+
// Mode B (proxy): no secretKey, no orgId — proxy intercepts and signs the request
|
|
100614
|
+
// Mode C legacy: orgId in URL path
|
|
100615
|
+
|
|
100624
100616
|
try {
|
|
100625
100617
|
const base = apiBaseUrl.replace(/\/$/, '');
|
|
100626
|
-
const url = "".concat(base, "/api/v1/deploy-agent");
|
|
100618
|
+
const url = orgId ? "".concat(base, "/api/v1/deploy-agent/").concat(orgId) : "".concat(base, "/api/v1/deploy-agent");
|
|
100627
100619
|
const headers = {
|
|
100628
100620
|
"Content-Type": "application/json"
|
|
100629
100621
|
};
|
|
100630
|
-
|
|
100631
|
-
// In-app JWT path: set Authorization header
|
|
100632
|
-
// Mode B proxy: no auth header; proxy handles org resolution
|
|
100633
|
-
if (typeof getAuthToken === 'function') {
|
|
100634
|
-
const token = await getAuthToken();
|
|
100635
|
-
if (token) {
|
|
100636
|
-
headers['Authorization'] = "Bearer ".concat(token);
|
|
100637
|
-
}
|
|
100638
|
-
}
|
|
100622
|
+
if (secretKey) headers['x-eshal-key'] = secretKey;
|
|
100639
100623
|
const response = await fetch(url, {
|
|
100640
100624
|
method: "GET",
|
|
100641
100625
|
headers,
|
|
@@ -100655,10 +100639,11 @@
|
|
|
100655
100639
|
const ChatWidget = _ref => {
|
|
100656
100640
|
var _agentConfig$concierg;
|
|
100657
100641
|
let {
|
|
100658
|
-
|
|
100659
|
-
|
|
100660
|
-
|
|
100661
|
-
|
|
100642
|
+
// Auth — at least one of secretKey (Mode A/B) or orgId (Mode C legacy) is needed.
|
|
100643
|
+
secretKey,
|
|
100644
|
+
// sk_live_... from ChatWidget.init({ secretKey, apiBaseUrl })
|
|
100645
|
+
orgId,
|
|
100646
|
+
// legacy — kept for backward compatibility
|
|
100662
100647
|
apiBaseUrl,
|
|
100663
100648
|
// Optional override props (will override fetched config if provided)
|
|
100664
100649
|
darkMode,
|
|
@@ -100714,9 +100699,13 @@
|
|
|
100714
100699
|
setIsLoadingConfig(false);
|
|
100715
100700
|
return;
|
|
100716
100701
|
}
|
|
100702
|
+
// Mode B proxy: neither secretKey nor orgId in browser — proxy handles auth
|
|
100703
|
+
|
|
100717
100704
|
try {
|
|
100718
100705
|
setIsLoadingConfig(true);
|
|
100719
|
-
|
|
100706
|
+
// Pass secretKey for Mode A/B — fetchAgentConfig will send it as a
|
|
100707
|
+
// header and omit the orgId path segment. Pass orgId for Mode C legacy.
|
|
100708
|
+
const config = await fetchAgentConfig(apiBaseUrl, orgId, secretKey);
|
|
100720
100709
|
setAgentConfig(config);
|
|
100721
100710
|
setConfigError(null);
|
|
100722
100711
|
} catch (error) {
|
|
@@ -100727,11 +100716,11 @@
|
|
|
100727
100716
|
}
|
|
100728
100717
|
};
|
|
100729
100718
|
loadAgentConfig();
|
|
100730
|
-
}, [
|
|
100719
|
+
}, [orgId, secretKey, apiBaseUrl]);
|
|
100731
100720
|
|
|
100732
100721
|
// Map API response to widget props (use props as overrides if provided)
|
|
100733
100722
|
const widgetConfig = reactExports.useMemo(() => {
|
|
100734
|
-
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, _ref5, _ref6, _branding$chatbotAvat, _branding$chatbotAvat2, _ref7, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _typography$headerTex, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18, _inactivity$timeoutVa, _inactivity$timeoutUn, _ref19, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _ref26, _csat$enabled, _csat$format, _csat$prompt, _csat$triggerType, _csat$idleTimeoutMins, _csat$followUpEnabled, _csat$followUpPrompt, _behavior$autoPromptE, _behavior$allowFeedba, _behavior$provideCita
|
|
100723
|
+
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, _ref5, _ref6, _branding$chatbotAvat, _branding$chatbotAvat2, _ref7, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _typography$headerTex, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18, _inactivity$timeoutVa, _inactivity$timeoutUn, _ref19, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _ref26, _csat$enabled, _csat$format, _csat$prompt, _csat$triggerType, _csat$idleTimeoutMins, _csat$followUpEnabled, _csat$followUpPrompt, _behavior$autoPromptE, _behavior$allowFeedba, _behavior$provideCita;
|
|
100735
100724
|
if (!agentConfig) {
|
|
100736
100725
|
return null;
|
|
100737
100726
|
}
|
|
@@ -100790,6 +100779,7 @@
|
|
|
100790
100779
|
fontFamily: (_ref1 = fontFamily !== null && fontFamily !== void 0 ? fontFamily : typography.agentMessageBubbleFontFamily) !== null && _ref1 !== void 0 ? _ref1 : "Inter",
|
|
100791
100780
|
fontSize: (_ref10 = fontSize !== null && fontSize !== void 0 ? fontSize : typography.agentMessageBubbleFontSize) !== null && _ref10 !== void 0 ? _ref10 : "14px",
|
|
100792
100781
|
defaultLanguage: locale,
|
|
100782
|
+
organizationId: orgId,
|
|
100793
100783
|
headerTextBold: (_ref11 = headerTextBold !== null && headerTextBold !== void 0 ? headerTextBold : typography.headerTextBold) !== null && _ref11 !== void 0 ? _ref11 : false,
|
|
100794
100784
|
headerTextItalic: (_ref12 = headerTextItalic !== null && headerTextItalic !== void 0 ? headerTextItalic : typography.headerTextItalic) !== null && _ref12 !== void 0 ? _ref12 : false,
|
|
100795
100785
|
headerTextColor: (_typography$headerTex = typography.headerTextColor) !== null && _typography$headerTex !== void 0 ? _typography$headerTex : "#FFFFFF",
|
|
@@ -100826,12 +100816,9 @@
|
|
|
100826
100816
|
// every message and tell the backend to skip citation generation.
|
|
100827
100817
|
// Defaults to true so agents that haven't set the field keep showing
|
|
100828
100818
|
// citations (matches the testing-lab / chatbot-preview default).
|
|
100829
|
-
provideCitations: (_behavior$provideCita = behavior.provideCitations) !== null && _behavior$provideCita !== void 0 ? _behavior$provideCita : true
|
|
100830
|
-
// organizationId from the backend response — used internally for
|
|
100831
|
-
// session isolation (localStorage keys) and WS paths. Not a user prop.
|
|
100832
|
-
organizationId: (_agentConfig$organiza = agentConfig.organizationId) !== null && _agentConfig$organiza !== void 0 ? _agentConfig$organiza : null
|
|
100819
|
+
provideCitations: (_behavior$provideCita = behavior.provideCitations) !== null && _behavior$provideCita !== void 0 ? _behavior$provideCita : true
|
|
100833
100820
|
};
|
|
100834
|
-
}, [agentConfig, darkMode, primaryColor, position, companyName, conciergeName, companyLogo, welcomeMessage, quickQuestions, quickQuestionsEnabled, textColor, agentMessageBubbleColor, userMessageBoxColor, assistantTextColor, userTextColor, fontFamily, fontSize, defaultLanguage, headerTextBold, headerTextItalic, enableVoiceInteraction, disclaimerEnabled, disclaimerText, disclaimerPosition, disclaimerLinkLabel, disclaimerLinkUrl, showPoweredBy, onboardingQuestions, onboardingEnabled, collectionPrompt, allowedDomains, agentMessageBubbleFontFamily, agentMessageBubbleFontSize, userMessageBubbleFontFamily, userMessageBubbleFontSize
|
|
100821
|
+
}, [agentConfig, darkMode, primaryColor, position, companyName, conciergeName, companyLogo, welcomeMessage, quickQuestions, quickQuestionsEnabled, textColor, agentMessageBubbleColor, userMessageBoxColor, assistantTextColor, userTextColor, fontFamily, fontSize, defaultLanguage, orgId, headerTextBold, headerTextItalic, enableVoiceInteraction, disclaimerEnabled, disclaimerText, disclaimerPosition, disclaimerLinkLabel, disclaimerLinkUrl, showPoweredBy, onboardingQuestions, onboardingEnabled, collectionPrompt, allowedDomains, agentMessageBubbleFontFamily, agentMessageBubbleFontSize, userMessageBubbleFontFamily, userMessageBubbleFontSize
|
|
100835
100822
|
// CSAT dependencies
|
|
100836
100823
|
// (kept minimal because these come from agentConfig)
|
|
100837
100824
|
]);
|
|
@@ -100850,7 +100837,7 @@
|
|
|
100850
100837
|
quickQuestions: [],
|
|
100851
100838
|
apiBaseUrl: apiBaseUrl || "",
|
|
100852
100839
|
apiKey: apiKey || "",
|
|
100853
|
-
|
|
100840
|
+
organizationId: orgId || "",
|
|
100854
100841
|
autoOpen: false,
|
|
100855
100842
|
openDelay: 0,
|
|
100856
100843
|
darkMode: false,
|
|
@@ -100858,7 +100845,7 @@
|
|
|
100858
100845
|
onboardingQuestions: [],
|
|
100859
100846
|
onboardingEnabled: false,
|
|
100860
100847
|
collectionPrompt: undefined
|
|
100861
|
-
}), [apiBaseUrl, apiKey,
|
|
100848
|
+
}), [apiBaseUrl, apiKey, orgId]);
|
|
100862
100849
|
|
|
100863
100850
|
// ALWAYS call hooks before any early returns (Rules of Hooks)
|
|
100864
100851
|
const {
|
|
@@ -100907,7 +100894,7 @@
|
|
|
100907
100894
|
// knowledge-api LoadBalancer.
|
|
100908
100895
|
apiKey,
|
|
100909
100896
|
organizationId: widgetConfig.organizationId,
|
|
100910
|
-
|
|
100897
|
+
secretKey,
|
|
100911
100898
|
autoOpen,
|
|
100912
100899
|
openDelay,
|
|
100913
100900
|
darkMode: widgetConfig.darkMode,
|
|
@@ -100934,33 +100921,25 @@
|
|
|
100934
100921
|
// navigation (but not a page refresh — feedback is not written to
|
|
100935
100922
|
// localStorage so it resets on reload as intended).
|
|
100936
100923
|
updateMessageFeedback(messageContent, feedback);
|
|
100937
|
-
if (!conversationId || !apiBaseUrl) return;
|
|
100924
|
+
if (!orgId && !secretKey || !conversationId || !apiBaseUrl) return;
|
|
100938
100925
|
const base = apiBaseUrl.replace(/\/$/, "");
|
|
100939
|
-
|
|
100940
|
-
|
|
100941
|
-
|
|
100942
|
-
|
|
100943
|
-
|
|
100944
|
-
|
|
100945
|
-
|
|
100946
|
-
|
|
100947
|
-
|
|
100948
|
-
|
|
100949
|
-
|
|
100950
|
-
|
|
100951
|
-
|
|
100952
|
-
|
|
100953
|
-
|
|
100954
|
-
|
|
100955
|
-
|
|
100956
|
-
feedbackText
|
|
100957
|
-
})
|
|
100958
|
-
});
|
|
100959
|
-
} catch (err) {
|
|
100960
|
-
console.error("Feedback submission error:", err);
|
|
100961
|
-
}
|
|
100962
|
-
})();
|
|
100963
|
-
}, [conversationId, apiBaseUrl, getAuthToken, updateMessageFeedback]);
|
|
100926
|
+
const feedbackHeaders = {
|
|
100927
|
+
"Content-Type": "application/json"
|
|
100928
|
+
};
|
|
100929
|
+
if (secretKey) feedbackHeaders['x-eshal-key'] = secretKey;else if (orgId) feedbackHeaders['x-eshal-org'] = orgId;
|
|
100930
|
+
fetch("".concat(base, "/api/v1/support/feedback"), {
|
|
100931
|
+
method: "POST",
|
|
100932
|
+
headers: feedbackHeaders,
|
|
100933
|
+
credentials: "include",
|
|
100934
|
+
body: JSON.stringify({
|
|
100935
|
+
messageContent,
|
|
100936
|
+
conversationId,
|
|
100937
|
+
organizationId: orgId,
|
|
100938
|
+
feedback,
|
|
100939
|
+
feedbackText
|
|
100940
|
+
})
|
|
100941
|
+
}).catch(err => console.error("Feedback submission error:", err));
|
|
100942
|
+
}, [orgId, conversationId, apiBaseUrl, updateMessageFeedback]);
|
|
100964
100943
|
|
|
100965
100944
|
// Refresh chat handler — reset conversation
|
|
100966
100945
|
const handleRefreshChat = reactExports.useCallback(() => {
|
|
@@ -100976,7 +100955,7 @@
|
|
|
100976
100955
|
const {
|
|
100977
100956
|
categories: filterCategories,
|
|
100978
100957
|
hasFilters: showFilterStep
|
|
100979
|
-
} = useFilterCatalog(apiBaseUrl,
|
|
100958
|
+
} = useFilterCatalog(apiBaseUrl, orgId, secretKey);
|
|
100980
100959
|
|
|
100981
100960
|
// Copy chat handler — copy all messages to clipboard
|
|
100982
100961
|
const handleCopyChat = reactExports.useCallback(() => {
|
|
@@ -101081,7 +101060,8 @@
|
|
|
101081
101060
|
showPoweredBy: widgetConfig.showPoweredBy,
|
|
101082
101061
|
apiBaseUrl: apiBaseUrl,
|
|
101083
101062
|
apiKey: apiKey,
|
|
101084
|
-
|
|
101063
|
+
organizationId: widgetConfig.organizationId,
|
|
101064
|
+
secretKey: secretKey,
|
|
101085
101065
|
conversationId: conversationId,
|
|
101086
101066
|
conciergeId: (_agentConfig$concierg = agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.conciergeId) !== null && _agentConfig$concierg !== void 0 ? _agentConfig$concierg : agentConfig === null || agentConfig === void 0 ? void 0 : agentConfig.id,
|
|
101087
101067
|
onboardingQuestions: widgetConfig.onboardingQuestions,
|
|
@@ -101229,10 +101209,15 @@
|
|
|
101229
101209
|
}
|
|
101230
101210
|
|
|
101231
101211
|
// Render component
|
|
101232
|
-
// Mode B
|
|
101233
|
-
//
|
|
101212
|
+
// Mode A/B: secretKey present — orgId derived server-side from the key
|
|
101213
|
+
// Mode C legacy: orgId in config — backward compatible
|
|
101214
|
+
// Both: apiBaseUrl required
|
|
101215
|
+
// Mode B proxy: apiBaseUrl alone is enough — no secretKey or orgId in browser
|
|
101234
101216
|
const hasNewAuth = config.apiBaseUrl;
|
|
101235
101217
|
const widgetProps = hasNewAuth ? _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({
|
|
101218
|
+
// Auth props — secretKey replaces orgId in Mode A/B
|
|
101219
|
+
secretKey: config.secretKey || null,
|
|
101220
|
+
orgId: config.orgId || null,
|
|
101236
101221
|
apiBaseUrl: config.apiBaseUrl
|
|
101237
101222
|
}, options.wsBaseUrl !== undefined && {
|
|
101238
101223
|
wsBaseUrl: config.wsBaseUrl
|