@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.
@@ -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, getAuthToken) => {
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
- // In-app JWT path: call getAuthToken() and set Authorization header
8022
- // Mode B proxy: no auth header from widget; proxy injects x-eshal-sig + x-eshal-org server-side
8023
- if (typeof getAuthToken === 'function') {
8024
- const token = await getAuthToken();
8025
- if (token) {
8026
- headers['Authorization'] = "Bearer ".concat(token);
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
- getAuthToken,
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, getAuthToken);
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, getAuthToken);
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, getAuthToken);
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, getAuthToken, messages, bidiSessionId, routingChoice, widgetFilter, provideCitations]);
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
- getAuthToken,
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: spHeaders,
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: dlHeaders,
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
- getAuthToken,
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
- getAuthToken: getAuthToken,
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
- getAuthToken: getAuthToken,
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
- getAuthToken,
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
- getAuthToken: getAuthToken,
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
- getAuthToken,
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
- getAuthToken: getAuthToken,
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
- getAuthToken: getAuthToken,
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
- getAuthToken,
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(undefined); // persist so page refresh doesn't re-show CSAT
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 (typeof getAuthToken === 'function') {
99948
- const token = await getAuthToken();
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 (typeof getAuthToken === 'function') {
99983
- const token = await getAuthToken();
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, getAuthToken, conciergeId, apiBaseUrl, csatFormat, onResetConversation, onRefreshChat, onWidgetFilterChange]);
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
- getAuthToken: getAuthToken,
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 {Function|undefined|null} getAuthToken - async fn returning a Bearer token (in-app JWT path), or undefined/null (Mode B proxy)
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, getAuthToken) {
100460
- const hasAuth = !!apiBaseUrl;
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 = getAuthToken ? "".concat(apiBaseUrl, "|__session__") : "".concat(apiBaseUrl, "|__proxy__");
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
- (async () => {
100493
- try {
100494
- const headers = {
100495
- Accept: "application/json"
100496
- };
100497
- // In-app JWT path: set Authorization header
100498
- // Mode B proxy: no auth header; proxy handles org resolution
100499
- if (typeof getAuthToken === 'function') {
100500
- const token = await getAuthToken();
100501
- if (token) {
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, getAuthToken]);
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 {Function|undefined} getAuthToken - async fn returning a Bearer token (in-app JWT path), or undefined (Mode B proxy)
100605
+ * @param {string} orgId - Organization ID
100618
100606
  * @returns {Promise<object>} Agent configuration object
100619
100607
  */
100620
- const fetchAgentConfig = async (apiBaseUrl, getAuthToken) => {
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
- * @param {Function|undefined} getAuthToken - async fn returning a Keycloak Bearer token (in-app JWT path)
100660
- */
100661
- getAuthToken,
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
- const config = await fetchAgentConfig(apiBaseUrl, getAuthToken);
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
- }, [apiBaseUrl, getAuthToken]);
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, _agentConfig$organiza;
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
- getAuthToken,
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, getAuthToken]);
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
- getAuthToken,
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
- (async () => {
100940
- try {
100941
- const feedbackHeaders = {
100942
- "Content-Type": "application/json"
100943
- };
100944
- if (typeof getAuthToken === 'function') {
100945
- const token = await getAuthToken();
100946
- if (token) feedbackHeaders['Authorization'] = "Bearer ".concat(token);
100947
- }
100948
- await fetch("".concat(base, "/api/v1/support/feedback"), {
100949
- method: "POST",
100950
- headers: feedbackHeaders,
100951
- credentials: "include",
100952
- body: JSON.stringify({
100953
- messageContent,
100954
- conversationId,
100955
- feedback,
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, getAuthToken);
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
- getAuthToken: getAuthToken,
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 proxy: apiBaseUrl alone is enough — no key or orgId in browser
101233
- // In-app JWT: getAuthToken fn passed via config
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