@eshal-bot/chat-widget 0.1.64 → 0.1.65
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 +73 -39
- 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
|
@@ -8011,14 +8011,18 @@
|
|
|
8011
8011
|
* @param {object} request - Chat request object
|
|
8012
8012
|
* @param {string} apiBaseUrl - Base URL for the API
|
|
8013
8013
|
*/
|
|
8014
|
-
const sendStreamingRequest = async (request, apiBaseUrl, organizationId) => {
|
|
8014
|
+
const sendStreamingRequest = async (request, apiBaseUrl, organizationId, secretKey) => {
|
|
8015
8015
|
const headers = {
|
|
8016
8016
|
'Content-Type': 'application/json',
|
|
8017
8017
|
Accept: 'text/event-stream'
|
|
8018
8018
|
};
|
|
8019
8019
|
|
|
8020
|
-
//
|
|
8021
|
-
|
|
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) {
|
|
8022
8026
|
headers['x-eshal-org'] = organizationId;
|
|
8023
8027
|
}
|
|
8024
8028
|
const response = await fetch("".concat(apiBaseUrl.replace(/\/$/, ''), "/api/v1/support"), {
|
|
@@ -9129,6 +9133,7 @@
|
|
|
9129
9133
|
apiBaseUrl,
|
|
9130
9134
|
apiKey,
|
|
9131
9135
|
organizationId,
|
|
9136
|
+
secretKey,
|
|
9132
9137
|
autoOpen,
|
|
9133
9138
|
openDelay,
|
|
9134
9139
|
darkMode,
|
|
@@ -9765,7 +9770,7 @@
|
|
|
9765
9770
|
if (apiType === 'userName' || apiType === 'email' || apiType === 'phone') {
|
|
9766
9771
|
// For onboarding fields, just consume the stream without processing.
|
|
9767
9772
|
// Single attempt — no retry, no user-visible partial state to clean up.
|
|
9768
|
-
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, organizationId);
|
|
9773
|
+
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, organizationId, secretKey);
|
|
9769
9774
|
const reader = stream.getReader();
|
|
9770
9775
|
const decoder = new TextDecoder();
|
|
9771
9776
|
while (true) {
|
|
@@ -9784,7 +9789,7 @@
|
|
|
9784
9789
|
let lastErr;
|
|
9785
9790
|
for (let attempt = 0; attempt <= STREAM_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
9786
9791
|
try {
|
|
9787
|
-
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, organizationId);
|
|
9792
|
+
const stream = await sendStreamingRequest(chatRequest, apiBaseUrl, organizationId, secretKey);
|
|
9788
9793
|
await processStream(stream, setMessages);
|
|
9789
9794
|
updateActivity(organizationId);
|
|
9790
9795
|
return {
|
|
@@ -99628,6 +99633,7 @@
|
|
|
99628
99633
|
apiBaseUrl,
|
|
99629
99634
|
apiKey,
|
|
99630
99635
|
organizationId,
|
|
99636
|
+
secretKey,
|
|
99631
99637
|
conversationId,
|
|
99632
99638
|
conciergeId,
|
|
99633
99639
|
onboardingQuestions = [],
|
|
@@ -100424,6 +100430,7 @@
|
|
|
100424
100430
|
/**
|
|
100425
100431
|
* @param {string|undefined|null} apiBaseUrl
|
|
100426
100432
|
* @param {string|undefined|null} orgId
|
|
100433
|
+
* @param {string|undefined|null} secretKey — Mode A/B: orgId resolved server-side
|
|
100427
100434
|
* @returns {{
|
|
100428
100435
|
* categories: Array<{id:string,label:string,count:number,tags:string[]}>,
|
|
100429
100436
|
* loading: boolean,
|
|
@@ -100431,14 +100438,17 @@
|
|
|
100431
100438
|
* hasFilters: boolean,
|
|
100432
100439
|
* }}
|
|
100433
100440
|
*/
|
|
100434
|
-
function useFilterCatalog(apiBaseUrl, orgId) {
|
|
100441
|
+
function useFilterCatalog(apiBaseUrl, orgId, secretKey) {
|
|
100442
|
+
// Mode A: secretKey present, orgId null → key-based endpoint
|
|
100443
|
+
// Mode C: orgId present (legacy) → orgId-in-path endpoint
|
|
100444
|
+
const hasAuth = !!(apiBaseUrl && (orgId || secretKey));
|
|
100435
100445
|
const [state, setState] = reactExports.useState({
|
|
100436
100446
|
categories: [],
|
|
100437
|
-
loading:
|
|
100447
|
+
loading: hasAuth,
|
|
100438
100448
|
error: null
|
|
100439
100449
|
});
|
|
100440
100450
|
reactExports.useEffect(() => {
|
|
100441
|
-
if (!apiBaseUrl || !orgId) {
|
|
100451
|
+
if (!apiBaseUrl || !orgId && !secretKey) {
|
|
100442
100452
|
setState({
|
|
100443
100453
|
categories: [],
|
|
100444
100454
|
loading: false,
|
|
@@ -100446,8 +100456,8 @@
|
|
|
100446
100456
|
});
|
|
100447
100457
|
return;
|
|
100448
100458
|
}
|
|
100449
|
-
const
|
|
100450
|
-
const cached = _PROCESS_CACHE.get(
|
|
100459
|
+
const cacheKey = secretKey ? "".concat(apiBaseUrl, "|__key__") : "".concat(apiBaseUrl, "|").concat(orgId);
|
|
100460
|
+
const cached = _PROCESS_CACHE.get(cacheKey);
|
|
100451
100461
|
if (cached) {
|
|
100452
100462
|
setState({
|
|
100453
100463
|
categories: cached,
|
|
@@ -100461,12 +100471,15 @@
|
|
|
100461
100471
|
loading: true,
|
|
100462
100472
|
error: null
|
|
100463
100473
|
}));
|
|
100464
|
-
const
|
|
100474
|
+
const base = apiBaseUrl.replace(/\/$/, "");
|
|
100475
|
+
const url = secretKey ? "".concat(base, "/api/v1/widget/filters") : "".concat(base, "/api/v1/widget/filters/").concat(encodeURIComponent(orgId));
|
|
100476
|
+
const headers = {
|
|
100477
|
+
Accept: "application/json"
|
|
100478
|
+
};
|
|
100479
|
+
if (secretKey) headers["x-eshal-key"] = secretKey;
|
|
100465
100480
|
fetch(url, {
|
|
100466
100481
|
method: "GET",
|
|
100467
|
-
headers
|
|
100468
|
-
Accept: "application/json"
|
|
100469
|
-
}
|
|
100482
|
+
headers
|
|
100470
100483
|
}).then(async res => {
|
|
100471
100484
|
if (!res.ok) {
|
|
100472
100485
|
throw new Error("filter catalog HTTP ".concat(res.status));
|
|
@@ -100475,7 +100488,7 @@
|
|
|
100475
100488
|
return Array.isArray(body === null || body === void 0 ? void 0 : body.categories) ? body.categories : [];
|
|
100476
100489
|
}).then(categories => {
|
|
100477
100490
|
if (cancelled) return;
|
|
100478
|
-
_PROCESS_CACHE.set(
|
|
100491
|
+
_PROCESS_CACHE.set(cacheKey, categories);
|
|
100479
100492
|
setState({
|
|
100480
100493
|
categories,
|
|
100481
100494
|
loading: false,
|
|
@@ -100497,7 +100510,7 @@
|
|
|
100497
100510
|
return () => {
|
|
100498
100511
|
cancelled = true;
|
|
100499
100512
|
};
|
|
100500
|
-
}, [apiBaseUrl, orgId]);
|
|
100513
|
+
}, [apiBaseUrl, orgId, secretKey]);
|
|
100501
100514
|
const hasFilters = reactExports.useMemo(() => Array.isArray(state.categories) && state.categories.length > 0, [state.categories]);
|
|
100502
100515
|
return _objectSpread2(_objectSpread2({}, state), {}, {
|
|
100503
100516
|
hasFilters
|
|
@@ -100579,17 +100592,24 @@
|
|
|
100579
100592
|
* @param {string} orgId - Organization ID
|
|
100580
100593
|
* @returns {Promise<object>} Agent configuration object
|
|
100581
100594
|
*/
|
|
100582
|
-
const fetchAgentConfig = async (apiBaseUrl, orgId) => {
|
|
100583
|
-
if (!apiBaseUrl
|
|
100584
|
-
throw new Error("apiBaseUrl
|
|
100595
|
+
const fetchAgentConfig = async (apiBaseUrl, orgId, secretKey) => {
|
|
100596
|
+
if (!apiBaseUrl) {
|
|
100597
|
+
throw new Error("apiBaseUrl is required");
|
|
100585
100598
|
}
|
|
100599
|
+
// Mode A: secretKey in header, no orgId in URL
|
|
100600
|
+
// Mode B (proxy): no secretKey, no orgId — proxy intercepts and signs the request
|
|
100601
|
+
// Mode C legacy: orgId in URL path
|
|
100602
|
+
|
|
100586
100603
|
try {
|
|
100587
|
-
const
|
|
100604
|
+
const base = apiBaseUrl.replace(/\/$/, '');
|
|
100605
|
+
const url = orgId ? "".concat(base, "/api/v1/deploy-agent/").concat(orgId) : "".concat(base, "/api/v1/deploy-agent");
|
|
100606
|
+
const headers = {
|
|
100607
|
+
"Content-Type": "application/json"
|
|
100608
|
+
};
|
|
100609
|
+
if (secretKey) headers['x-eshal-key'] = secretKey;
|
|
100588
100610
|
const response = await fetch(url, {
|
|
100589
100611
|
method: "GET",
|
|
100590
|
-
headers
|
|
100591
|
-
"Content-Type": "application/json"
|
|
100592
|
-
},
|
|
100612
|
+
headers,
|
|
100593
100613
|
credentials: "include"
|
|
100594
100614
|
});
|
|
100595
100615
|
if (!response.ok) {
|
|
@@ -100606,8 +100626,11 @@
|
|
|
100606
100626
|
const ChatWidget = _ref => {
|
|
100607
100627
|
var _agentConfig$concierg;
|
|
100608
100628
|
let {
|
|
100609
|
-
//
|
|
100629
|
+
// Auth — at least one of secretKey (Mode A/B) or orgId (Mode C legacy) is needed.
|
|
100630
|
+
secretKey,
|
|
100631
|
+
// sk_live_... from ChatWidget.init({ secretKey, apiBaseUrl })
|
|
100610
100632
|
orgId,
|
|
100633
|
+
// legacy — kept for backward compatibility
|
|
100611
100634
|
apiBaseUrl,
|
|
100612
100635
|
// Optional override props (will override fetched config if provided)
|
|
100613
100636
|
darkMode,
|
|
@@ -100658,14 +100681,18 @@
|
|
|
100658
100681
|
// Fetch agent configuration on mount
|
|
100659
100682
|
reactExports.useEffect(() => {
|
|
100660
100683
|
const loadAgentConfig = async () => {
|
|
100661
|
-
if (!
|
|
100662
|
-
setConfigError("
|
|
100684
|
+
if (!apiBaseUrl) {
|
|
100685
|
+
setConfigError("apiBaseUrl is required");
|
|
100663
100686
|
setIsLoadingConfig(false);
|
|
100664
100687
|
return;
|
|
100665
100688
|
}
|
|
100689
|
+
// Mode B proxy: neither secretKey nor orgId in browser — proxy handles auth
|
|
100690
|
+
|
|
100666
100691
|
try {
|
|
100667
100692
|
setIsLoadingConfig(true);
|
|
100668
|
-
|
|
100693
|
+
// Pass secretKey for Mode A/B — fetchAgentConfig will send it as a
|
|
100694
|
+
// header and omit the orgId path segment. Pass orgId for Mode C legacy.
|
|
100695
|
+
const config = await fetchAgentConfig(apiBaseUrl, orgId, secretKey);
|
|
100669
100696
|
setAgentConfig(config);
|
|
100670
100697
|
setConfigError(null);
|
|
100671
100698
|
} catch (error) {
|
|
@@ -100676,7 +100703,7 @@
|
|
|
100676
100703
|
}
|
|
100677
100704
|
};
|
|
100678
100705
|
loadAgentConfig();
|
|
100679
|
-
}, [orgId, apiBaseUrl]);
|
|
100706
|
+
}, [orgId, secretKey, apiBaseUrl]);
|
|
100680
100707
|
|
|
100681
100708
|
// Map API response to widget props (use props as overrides if provided)
|
|
100682
100709
|
const widgetConfig = reactExports.useMemo(() => {
|
|
@@ -100854,6 +100881,7 @@
|
|
|
100854
100881
|
// knowledge-api LoadBalancer.
|
|
100855
100882
|
apiKey,
|
|
100856
100883
|
organizationId: widgetConfig.organizationId,
|
|
100884
|
+
secretKey,
|
|
100857
100885
|
autoOpen,
|
|
100858
100886
|
openDelay,
|
|
100859
100887
|
darkMode: widgetConfig.darkMode,
|
|
@@ -100880,14 +100908,15 @@
|
|
|
100880
100908
|
// navigation (but not a page refresh — feedback is not written to
|
|
100881
100909
|
// localStorage so it resets on reload as intended).
|
|
100882
100910
|
updateMessageFeedback(messageContent, feedback);
|
|
100883
|
-
if (!orgId || !conversationId || !apiBaseUrl) return;
|
|
100911
|
+
if (!orgId && !secretKey || !conversationId || !apiBaseUrl) return;
|
|
100884
100912
|
const base = apiBaseUrl.replace(/\/$/, "");
|
|
100913
|
+
const feedbackHeaders = {
|
|
100914
|
+
"Content-Type": "application/json"
|
|
100915
|
+
};
|
|
100916
|
+
if (secretKey) feedbackHeaders['x-eshal-key'] = secretKey;else if (orgId) feedbackHeaders['x-eshal-org'] = orgId;
|
|
100885
100917
|
fetch("".concat(base, "/api/v1/support/feedback"), {
|
|
100886
100918
|
method: "POST",
|
|
100887
|
-
headers:
|
|
100888
|
-
"Content-Type": "application/json",
|
|
100889
|
-
"x-eshal-org": orgId
|
|
100890
|
-
},
|
|
100919
|
+
headers: feedbackHeaders,
|
|
100891
100920
|
credentials: "include",
|
|
100892
100921
|
body: JSON.stringify({
|
|
100893
100922
|
messageContent,
|
|
@@ -100913,7 +100942,7 @@
|
|
|
100913
100942
|
const {
|
|
100914
100943
|
categories: filterCategories,
|
|
100915
100944
|
hasFilters: showFilterStep
|
|
100916
|
-
} = useFilterCatalog(apiBaseUrl, orgId);
|
|
100945
|
+
} = useFilterCatalog(apiBaseUrl, orgId, secretKey);
|
|
100917
100946
|
|
|
100918
100947
|
// Copy chat handler — copy all messages to clipboard
|
|
100919
100948
|
const handleCopyChat = reactExports.useCallback(() => {
|
|
@@ -101019,6 +101048,7 @@
|
|
|
101019
101048
|
apiBaseUrl: apiBaseUrl,
|
|
101020
101049
|
apiKey: apiKey,
|
|
101021
101050
|
organizationId: widgetConfig.organizationId,
|
|
101051
|
+
secretKey: secretKey,
|
|
101022
101052
|
conversationId: conversationId,
|
|
101023
101053
|
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,
|
|
101024
101054
|
onboardingQuestions: widgetConfig.onboardingQuestions,
|
|
@@ -101166,11 +101196,15 @@
|
|
|
101166
101196
|
}
|
|
101167
101197
|
|
|
101168
101198
|
// Render component
|
|
101169
|
-
//
|
|
101170
|
-
//
|
|
101171
|
-
|
|
101172
|
-
|
|
101173
|
-
|
|
101199
|
+
// Mode A/B: secretKey present — orgId derived server-side from the key
|
|
101200
|
+
// Mode C legacy: orgId in config — backward compatible
|
|
101201
|
+
// Both: apiBaseUrl required
|
|
101202
|
+
// Mode B proxy: apiBaseUrl alone is enough — no secretKey or orgId in browser
|
|
101203
|
+
const hasNewAuth = config.apiBaseUrl;
|
|
101204
|
+
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({
|
|
101205
|
+
// Auth props — secretKey replaces orgId in Mode A/B
|
|
101206
|
+
secretKey: config.secretKey || null,
|
|
101207
|
+
orgId: config.orgId || null,
|
|
101174
101208
|
apiBaseUrl: config.apiBaseUrl
|
|
101175
101209
|
}, options.wsBaseUrl !== undefined && {
|
|
101176
101210
|
wsBaseUrl: config.wsBaseUrl
|